mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 12:45:28 -05:00
Compare commits
424 Commits
1.29.3
...
1.36.1-tes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2ad1ced77 | ||
|
|
e76df589e2 | ||
|
|
1390565fc6 | ||
|
|
d76a37c785 | ||
|
|
ce8a35adea | ||
|
|
9030ba1adf | ||
|
|
5b8d829bba | ||
|
|
ad03b92d2d | ||
|
|
88fc412900 | ||
|
|
c2ec6848aa | ||
|
|
01da2877b0 | ||
|
|
107d77f1b8 | ||
|
|
1030868a75 | ||
|
|
797dc2ceb1 | ||
|
|
b971bfe800 | ||
|
|
f88407b731 | ||
|
|
725e3cacb8 | ||
|
|
c9eed5d997 | ||
|
|
bf682136c3 | ||
|
|
7be2a4f544 | ||
|
|
616664e6f3 | ||
|
|
0caf8628b7 | ||
|
|
463e7caa2c | ||
|
|
0e2315807f | ||
|
|
46bf6c666f | ||
|
|
902be7759d | ||
|
|
b4a1593dc9 | ||
|
|
577cfc6ba9 | ||
|
|
f7a29dfa69 | ||
|
|
e3475cf8ee | ||
|
|
b344f75a30 | ||
|
|
338a478ead | ||
|
|
2658ced18e | ||
|
|
cd6ff4d52b | ||
|
|
5438a6a364 | ||
|
|
ea1dea8621 | ||
|
|
3a556113aa | ||
|
|
eded0367db | ||
|
|
6c90f517e4 | ||
|
|
c07c00325f | ||
|
|
0a2e2cd771 | ||
|
|
8f3b5f9dfc | ||
|
|
78499bcf5f | ||
|
|
78fa776ce5 | ||
|
|
93c6415547 | ||
|
|
12f26c29e6 | ||
|
|
e4f6d94247 | ||
|
|
a04c51397d | ||
|
|
2073ef6ce9 | ||
|
|
7dfd9ddcb5 | ||
|
|
6215c39024 | ||
|
|
1c856911e8 | ||
|
|
ed17c2ac6d | ||
|
|
1ce332a91d | ||
|
|
2aa27fc051 | ||
|
|
31b239d5dc | ||
|
|
7c3779e287 | ||
|
|
3f13c33b10 | ||
|
|
8727a65513 | ||
|
|
baf3d0e63c | ||
|
|
ea2d1e7e9d | ||
|
|
f9f26ad50b | ||
|
|
9911c41a35 | ||
|
|
d590bc11f8 | ||
|
|
31c4c1f5d7 | ||
|
|
42ff48d637 | ||
|
|
d44376e869 | ||
|
|
4b1fd9e700 | ||
|
|
d61099f9c0 | ||
|
|
c2b73a02ca | ||
|
|
49a681bcfe | ||
|
|
4cedb29123 | ||
|
|
d80b3aaf69 | ||
|
|
b1cc15386f | ||
|
|
748744d1b7 | ||
|
|
912ff98e27 | ||
|
|
a9614c5306 | ||
|
|
cb2f97f11d | ||
|
|
017ea233ec | ||
|
|
e8206173ff | ||
|
|
680f72e4f9 | ||
|
|
930e8b38d4 | ||
|
|
ee1d0136d9 | ||
|
|
20c276f4ea | ||
|
|
bea4f66eb1 | ||
|
|
c5185765ee | ||
|
|
90130c119e | ||
|
|
a7ca06d25c | ||
|
|
5a5d590c51 | ||
|
|
336b398bc3 | ||
|
|
56c8f335db | ||
|
|
b6a4d48948 | ||
|
|
774ccb7fbd | ||
|
|
eda9dde23d | ||
|
|
bbf91efd0d | ||
|
|
b022d59391 | ||
|
|
cf46a010a7 | ||
|
|
595bab0d83 | ||
|
|
6fc819d72b | ||
|
|
0553a9b2ee | ||
|
|
3caa3a4735 | ||
|
|
2469057ad6 | ||
|
|
b230ec5bc5 | ||
|
|
1669b4cb72 | ||
|
|
2841fcaadb | ||
|
|
91810d9c40 | ||
|
|
ccb5c8ba2c | ||
|
|
265daebdf3 | ||
|
|
a149a11c57 | ||
|
|
d7cc7a4c7b | ||
|
|
41866bcb24 | ||
|
|
c73a5866d7 | ||
|
|
18aaf1dd31 | ||
|
|
d523a2e674 | ||
|
|
0f7eed6257 | ||
|
|
1f5a346190 | ||
|
|
7fd2979e86 | ||
|
|
2077e1971d | ||
|
|
873e073eb6 | ||
|
|
4f3d9e3a00 | ||
|
|
c02896ea17 | ||
|
|
4bfd40219b | ||
|
|
6a3de18069 | ||
|
|
8c51b44fbb | ||
|
|
10daa38921 | ||
|
|
6e0f7ab38f | ||
|
|
86061b3cf1 | ||
|
|
c3669cae3e | ||
|
|
a116360f87 | ||
|
|
713f695aa4 | ||
|
|
dec5c2d763 | ||
|
|
f090dea136 | ||
|
|
d00986df03 | ||
|
|
03e5397b7e | ||
|
|
94d49db196 | ||
|
|
1483f9d9dc | ||
|
|
99629e8c66 | ||
|
|
ba38b8bf27 | ||
|
|
38513735dd | ||
|
|
acfc7d605b | ||
|
|
df42538319 | ||
|
|
b02259e926 | ||
|
|
2b6bd9fb51 | ||
|
|
aadedbb610 | ||
|
|
d15a324137 | ||
|
|
119fac17bf | ||
|
|
088881b674 | ||
|
|
f008d5367b | ||
|
|
1ace185a57 | ||
|
|
a01d26e25d | ||
|
|
7e2ef9aacc | ||
|
|
4a98d064f7 | ||
|
|
b0d6cea52a | ||
|
|
d6bf9ed101 | ||
|
|
7e940e515b | ||
|
|
29e1ff0754 | ||
|
|
6309100cc4 | ||
|
|
ec3052c823 | ||
|
|
a28b800228 | ||
|
|
713a64ab45 | ||
|
|
4d5ffe38fc | ||
|
|
85460157b1 | ||
|
|
35e5b7620e | ||
|
|
e4c06b14a7 | ||
|
|
7fe3258269 | ||
|
|
ec19b4d4fb | ||
|
|
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 |
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
|
||||
|
||||
@@ -19,14 +19,9 @@ inputs:
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: Setup cmake
|
||||
uses: jwlawson/actions-setup-cmake@v1.13
|
||||
with:
|
||||
cmake-version: '3.24.x'
|
||||
|
||||
- name: Restore cached dependencies
|
||||
id: restore-cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ env.DEP_DIR }}
|
||||
key: ${{ env.DEP_DIR }}-${{ runner.os }}-${{ inputs.target }}
|
||||
|
||||
2
.github/actions/run-clang-format/action.yaml
vendored
2
.github/actions/run-clang-format/action.yaml
vendored
@@ -29,6 +29,7 @@ runs:
|
||||
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
|
||||
echo "/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin" >> $GITHUB_PATH
|
||||
echo "/home/linuxbrew/.linuxbrew/opt/clang-format@16/bin" >> $GITHUB_PATH
|
||||
brew update
|
||||
brew install --quiet zsh
|
||||
echo ::endgroup::
|
||||
|
||||
@@ -52,6 +53,7 @@ runs:
|
||||
|
||||
if (( ${changes[(I)(*.c|*.h|*.cpp|*.hpp|*.m|*.mm)]} )) {
|
||||
echo ::group::Install clang-format-16
|
||||
brew update
|
||||
brew install --quiet obsproject/tools/clang-format@16
|
||||
echo ::endgroup::
|
||||
|
||||
|
||||
8
.github/scripts/.Aptfile
vendored
8
.github/scripts/.Aptfile
vendored
@@ -8,6 +8,12 @@ package 'libcurl4-openssl-dev'
|
||||
package 'libxtst-dev'
|
||||
package 'libxss-dev'
|
||||
package 'libopencv-dev'
|
||||
package 'libopencv-contrib-dev'
|
||||
package 'libtesseract-dev'
|
||||
package 'libproc2-dev'
|
||||
package 'libusb-1.0-0-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'
|
||||
|
||||
2
.github/scripts/.Wingetfile
vendored
2
.github/scripts/.Wingetfile
vendored
@@ -1,4 +1,4 @@
|
||||
package 'cmake', path: 'Cmake\bin', bin: 'cmake'
|
||||
package 'innosetup', path: 'Inno Setup 6', bin: 'iscc'
|
||||
package 'OpenSSL', path: 'OpenSSL', bin: 'openssl'
|
||||
package 'OpenSSL', path: 'OpenSSL', bin: 'openssl', version: '3.6.2'
|
||||
package 'Microsoft.VisualStudio.Locator', path: 'vswhere', bin: 'vswhere'
|
||||
125
.github/scripts/.build-deps.zsh
vendored
125
.github/scripts/.build-deps.zsh
vendored
@@ -284,30 +284,56 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
case ${host_os} {
|
||||
macos)
|
||||
local opencv_dir="${project_root}/deps/opencv"
|
||||
local opencv_build_dir="${opencv_dir}/build_${target##*-}"
|
||||
local opencv_contrib_dir="${project_root}/deps/opencv_contrib"
|
||||
local opencv_install_x86="${opencv_dir}/install_x86_64"
|
||||
local opencv_install_arm="${opencv_dir}/install_arm64"
|
||||
|
||||
local -a opencv_cmake_args=(
|
||||
local -a opencv_cmake_args_common=(
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DBUILD_LIST=core,imgproc,objdetect
|
||||
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||
-DBUILD_LIST=core,imgproc,objdetect,xobjdetect,dnn
|
||||
-DOPENCV_EXTRA_MODULES_PATH="${opencv_contrib_dir}/modules"
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||
-DCMAKE_PREFIX_PATH="${advss_dep_path};${_plugin_deps}"
|
||||
-DCMAKE_INSTALL_PREFIX="${advss_dep_path}"
|
||||
-DWITH_KLEIDICV=OFF
|
||||
)
|
||||
|
||||
if [ "${target}" != "macos-x86_64" ]; then
|
||||
opencv_cmake_args+=(-DWITH_IPP=OFF)
|
||||
fi
|
||||
|
||||
pushd ${opencv_dir}
|
||||
log_info "Configure OpenCV ..."
|
||||
cmake -S . -B ${opencv_build_dir} ${opencv_cmake_args}
|
||||
|
||||
log_info "Building OpenCV ..."
|
||||
cmake --build ${opencv_build_dir} --config Release
|
||||
log_info "Configure OpenCV (x86_64) ..."
|
||||
cmake -S . -B build_x86_64 ${opencv_cmake_args_common} \
|
||||
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
|
||||
-DCMAKE_PROJECT_INCLUDE="${SCRIPT_HOME}/opencv-force-processor-x86_64.cmake" \
|
||||
-DCMAKE_INSTALL_PREFIX="${opencv_install_x86}" \
|
||||
-DWITH_IPP=OFF
|
||||
|
||||
log_info "Installing OpenCV ..."
|
||||
cmake --install ${opencv_build_dir} --prefix "${advss_dep_path}" --config Release || true
|
||||
log_info "Building OpenCV (x86_64) ..."
|
||||
cmake --build build_x86_64 --config Release
|
||||
|
||||
log_info "Installing OpenCV (x86_64) ..."
|
||||
cmake --install build_x86_64 --prefix "${opencv_install_x86}" --config Release || true
|
||||
|
||||
log_info "Configure OpenCV (arm64) ..."
|
||||
cmake -S . -B build_arm64 ${opencv_cmake_args_common} \
|
||||
-DCMAKE_OSX_ARCHITECTURES=arm64 \
|
||||
-DCMAKE_INSTALL_PREFIX="${opencv_install_arm}"
|
||||
|
||||
log_info "Building OpenCV (arm64) ..."
|
||||
cmake --build build_arm64 --config Release
|
||||
|
||||
log_info "Installing OpenCV (arm64) ..."
|
||||
cmake --install build_arm64 --prefix "${opencv_install_arm}" --config Release || true
|
||||
|
||||
log_info "Merging OpenCV into universal binaries ..."
|
||||
cp -R "${opencv_install_arm}/." "${advss_dep_path}"
|
||||
for arm_lib in ${opencv_install_arm}/lib/**/*.(dylib|a)(.); do
|
||||
local rel="${arm_lib#${opencv_install_arm}/}"
|
||||
local x86_lib="${opencv_install_x86}/${rel}"
|
||||
if [[ -f "${x86_lib}" ]]; then
|
||||
lipo -create "${x86_lib}" "${arm_lib}" -output "${advss_dep_path}/${rel}"
|
||||
fi
|
||||
done
|
||||
|
||||
rm -rf "${opencv_install_x86}" "${opencv_install_arm}"
|
||||
popd
|
||||
|
||||
local leptonica_dir="${project_root}/deps/leptonica"
|
||||
@@ -319,7 +345,7 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||
-DSW_BUILD=OFF
|
||||
-DOPENJPEG_SUPPORT=OFF
|
||||
-DLIBWEBP_SUPPORT=OFF
|
||||
-DENABLE_WEBP=OFF
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_GIF=TRUE
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_JPEG=TRUE
|
||||
-DCMAKE_DISABLE_FIND_PACKAGE_TIFF=TRUE
|
||||
@@ -394,8 +420,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 +432,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 +470,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 +492,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,6 +512,33 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
unset MACOSX_DEPLOYMENT_TARGET
|
||||
|
||||
popd
|
||||
|
||||
local mqtt_dir="${project_root}/deps/paho.mqtt.cpp"
|
||||
local mqtt_build_dir="${mqtt_dir}/build_${target##*-}"
|
||||
|
||||
local -a mqtt_cmake_args=(
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||
-DCMAKE_PREFIX_PATH="${advss_dep_path};${_plugin_deps}"
|
||||
-DCMAKE_INSTALL_PREFIX="${advss_dep_path}"
|
||||
-DPAHO_BUILD_SHARED=OFF
|
||||
-DPAHO_BUILD_STATIC=ON
|
||||
-DPAHO_WITH_MQTT_C=ON
|
||||
-DPAHO_WITH_SSL=ON
|
||||
-DOPENSSL_USE_STATIC_LIBS=ON
|
||||
)
|
||||
|
||||
pushd ${mqtt_dir}
|
||||
log_info "Configure paho.mqtt.cpp ..."
|
||||
cmake -S . -B ${mqtt_build_dir} ${mqtt_cmake_args}
|
||||
|
||||
log_info "Building paho.mqtt.cpp ..."
|
||||
cmake --build ${mqtt_build_dir} --config Release
|
||||
|
||||
log_info "Installing paho.mqtt.cpp ..."
|
||||
cmake --install ${mqtt_build_dir} --prefix "${advss_dep_path}" --config Release
|
||||
popd
|
||||
;;
|
||||
linux)
|
||||
# Nothing to do for now
|
||||
|
||||
10
.github/scripts/.build.zsh
vendored
10
.github/scripts/.build.zsh
vendored
@@ -253,12 +253,12 @@ ${_usage_host:-}"
|
||||
macos-*)
|
||||
if (( ${+CI} )) typeset -gx NSUnbufferedIO=YES
|
||||
|
||||
local openssl_lib_dir="${advss_deps_path}/openssl-combined/"
|
||||
local openssl_include_dir="${advss_deps_path}/openssl/include"
|
||||
|
||||
cmake_args+=(
|
||||
-DOPENSSL_INCLUDE_DIR="${openssl_include_dir}"
|
||||
-DOPENSSL_LIBRARIES="${openssl_lib_dir}/libcrypto.a;${openssl_lib_dir}/libssl.a"
|
||||
-DCMAKE_PREFIX_PATH="${advss_deps_path}"
|
||||
-DOPENSSL_ROOT_DIR="${advss_deps_path}"
|
||||
-DOPENSSL_INCLUDE_DIR="${advss_deps_path}/include"
|
||||
-DOPENSSL_CRYPTO_LIBRARY="${advss_deps_path}/lib/libcrypto.a"
|
||||
-DOPENSSL_SSL_LIBRARY="${advss_deps_path}/lib/libssl.a"
|
||||
--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)|(libobs)'
|
||||
|
||||
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
|
||||
|
||||
53
.github/scripts/Build-Deps-Windows.ps1
vendored
53
.github/scripts/Build-Deps-Windows.ps1
vendored
@@ -106,6 +106,7 @@ function Build {
|
||||
$ADVSSDepPath = "$(Resolve-Path -Path ${ProjectRoot}/${OutDirName})"
|
||||
|
||||
$OpenCVPath = "${ProjectRoot}/deps/opencv"
|
||||
$OpenCVContribPath = "${ProjectRoot}/deps/opencv_contrib"
|
||||
$OpenCVBuildPath = "${OpenCVPath}/build"
|
||||
|
||||
Push-Location -Stack BuildOpenCVTemp
|
||||
@@ -115,7 +116,8 @@ function Build {
|
||||
"-DCMAKE_BUILD_TYPE=Release"
|
||||
"-DCMAKE_PREFIX_PATH:PATH=${OBSDepPath}"
|
||||
"-DCMAKE_INSTALL_PREFIX:PATH=${ADVSSDepPath}"
|
||||
"-DBUILD_LIST=core,imgproc,objdetect"
|
||||
"-DBUILD_LIST=core,imgproc,objdetect,xobjdetect"
|
||||
"-DOPENCV_EXTRA_MODULES_PATH:PATH=${OpenCVContribPath}/modules"
|
||||
)
|
||||
|
||||
Log-Information "Configuring OpenCV..."
|
||||
@@ -209,7 +211,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 +223,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
|
||||
|
||||
73
.github/scripts/Package-Windows.ps1
vendored
73
.github/scripts/Package-Windows.ps1
vendored
@@ -68,14 +68,53 @@ function Package {
|
||||
|
||||
Remove-Item @RemoveArgs
|
||||
|
||||
Log-Group "Archiving ${ProductName}..."
|
||||
$CompressArgs = @{
|
||||
Path = (Get-ChildItem -Path "${ProjectRoot}/release/${Configuration}" -Exclude "${OutputName}*.*")
|
||||
CompressionLevel = 'Optimal'
|
||||
DestinationPath = "${ProjectRoot}/release/${OutputName}.zip"
|
||||
Verbose = ($Env:CI -ne $null)
|
||||
$ReleasePath = "${ProjectRoot}/release/${Configuration}"
|
||||
$NewBinPath = "${ReleasePath}/${ProductName}/bin/64bit"
|
||||
$NewDataPath = "${ReleasePath}/${ProductName}/data"
|
||||
$CIWindowsDir = "${ProjectRoot}/build-aux/CI/windows"
|
||||
|
||||
# --- Recommended zip (new layout, extract to %ProgramData%\obs-studio\) ---
|
||||
Log-Group "Archiving ${ProductName} (recommended)..."
|
||||
$RecStaging = "${ProjectRoot}/release/zip-staging-rec"
|
||||
Remove-Item -Path $RecStaging -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path $RecStaging | Out-Null
|
||||
Copy-Item -Path "${CIWindowsDir}/README.txt" -Destination "${RecStaging}/README.txt"
|
||||
if ( Test-Path -Path $NewBinPath ) {
|
||||
$RecBinPath = "${RecStaging}/${ProductName}/bin/64bit"
|
||||
New-Item -ItemType Directory -Force -Path $RecBinPath | Out-Null
|
||||
Copy-Item -Path "${NewBinPath}/*" -Destination $RecBinPath -Recurse -Force
|
||||
}
|
||||
Compress-Archive -Force @CompressArgs
|
||||
if ( Test-Path -Path $NewDataPath ) {
|
||||
$RecDataPath = "${RecStaging}/${ProductName}/data"
|
||||
New-Item -ItemType Directory -Force -Path $RecDataPath | Out-Null
|
||||
Copy-Item -Path "${NewDataPath}/*" -Destination $RecDataPath -Recurse -Force
|
||||
}
|
||||
Compress-Archive -Force -Path (Get-ChildItem -Path $RecStaging) `
|
||||
-CompressionLevel Optimal `
|
||||
-DestinationPath "${ProjectRoot}/release/${OutputName}.zip"
|
||||
Remove-Item -Path $RecStaging -Recurse -Force
|
||||
Log-Group
|
||||
|
||||
# --- Legacy zip (old layout, extract to OBS install directory) ---
|
||||
Log-Group "Archiving ${ProductName} (portable)..."
|
||||
$PortableStaging = "${ProjectRoot}/release/zip-staging-portable"
|
||||
Remove-Item -Path $PortableStaging -Recurse -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path $PortableStaging | Out-Null
|
||||
Copy-Item -Path "${CIWindowsDir}/README-portable.txt" -Destination "${PortableStaging}/README.txt"
|
||||
if ( Test-Path -Path $NewBinPath ) {
|
||||
$PortableBinPath = "${PortableStaging}/obs-plugins/64bit"
|
||||
New-Item -ItemType Directory -Force -Path $PortableBinPath | Out-Null
|
||||
Copy-Item -Path "${NewBinPath}/*" -Destination $PortableBinPath -Recurse -Force
|
||||
}
|
||||
if ( Test-Path -Path $NewDataPath ) {
|
||||
$PortableDataPath = "${PortableStaging}/data/obs-plugins/${ProductName}"
|
||||
New-Item -ItemType Directory -Force -Path $PortableDataPath | Out-Null
|
||||
Copy-Item -Path "${NewDataPath}/*" -Destination $PortableDataPath -Recurse -Force
|
||||
}
|
||||
Compress-Archive -Force -Path (Get-ChildItem -Path $PortableStaging) `
|
||||
-CompressionLevel Optimal `
|
||||
-DestinationPath "${ProjectRoot}/release/${OutputName}-portable.zip"
|
||||
Remove-Item -Path $PortableStaging -Recurse -Force
|
||||
Log-Group
|
||||
|
||||
if ( ( $BuildInstaller ) ) {
|
||||
@@ -89,7 +128,25 @@ function Package {
|
||||
Log-Information 'Creating InnoSetup installer...'
|
||||
Push-Location -Stack BuildTemp
|
||||
Ensure-Location -Path "${ProjectRoot}/release"
|
||||
Copy-Item -Path ${Configuration} -Destination Package -Recurse
|
||||
Remove-Item -Path Package -Recurse -Force -ErrorAction SilentlyContinue
|
||||
|
||||
# Recommended layout (for %ProgramData%\obs-studio\plugins\)
|
||||
$PkgRec = "Package/recommended"
|
||||
New-Item -ItemType Directory -Force -Path $PkgRec | Out-Null
|
||||
Copy-Item -Path "${Configuration}/*" -Destination $PkgRec -Recurse -Force
|
||||
|
||||
# Legacy layout (for OBS installation directory)
|
||||
if ( Test-Path "${Configuration}/${ProductName}/bin/64bit" ) {
|
||||
$PkgLegBin = "Package/portable/obs-plugins/64bit"
|
||||
New-Item -ItemType Directory -Force -Path $PkgLegBin | Out-Null
|
||||
Copy-Item -Path "${Configuration}/${ProductName}/bin/64bit/*" -Destination $PkgLegBin -Recurse -Force
|
||||
}
|
||||
if ( Test-Path "${Configuration}/${ProductName}/data" ) {
|
||||
$PkgLegData = "Package/portable/data/obs-plugins/${ProductName}"
|
||||
New-Item -ItemType Directory -Force -Path $PkgLegData | Out-Null
|
||||
Copy-Item -Path "${Configuration}/${ProductName}/data/*" -Destination $PkgLegData -Recurse -Force
|
||||
}
|
||||
|
||||
Invoke-External iscc ${IsccFile} /O"${ProjectRoot}/release" /F"${OutputName}-Installer"
|
||||
Remove-Item -Path Package -Recurse
|
||||
Pop-Location -Stack BuildTemp
|
||||
|
||||
7
.github/scripts/opencv-force-processor-x86_64.cmake
vendored
Normal file
7
.github/scripts/opencv-force-processor-x86_64.cmake
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# Injected via CMAKE_PROJECT_INCLUDE after opencv's project() call. Forces
|
||||
# CMAKE_SYSTEM_PROCESSOR into the cache so that third-party subdirectories
|
||||
# (mlas) that read the cache directly see x86_64 instead of the arm64 host
|
||||
# processor on Apple Silicon CI runners.
|
||||
set(CMAKE_SYSTEM_PROCESSOR
|
||||
x86_64
|
||||
CACHE INTERNAL "" FORCE)
|
||||
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
|
||||
|
||||
20
.github/scripts/utils.zsh/setup_linux
vendored
20
.github/scripts/utils.zsh/setup_linux
vendored
@@ -35,13 +35,21 @@ if (( ! (${skips[(Ie)all]} + ${skips[(Ie)deps]}) )) {
|
||||
sudo apt-get install ${apt_args} gcc-${${target##*-}//_/-}-linux-gnu g++-${${target##*-}//_/-}-linux-gnu
|
||||
}
|
||||
|
||||
sudo add-apt-repository --yes ppa:obsproject/obs-studio
|
||||
sudo apt update
|
||||
local dist_version
|
||||
read -r dist_version <<< "$(source /etc/os-release; print "${VERSION_ID}")"
|
||||
|
||||
sudo apt-get install ${apt_args} \
|
||||
build-essential \
|
||||
libgles2-mesa-dev \
|
||||
obs-studio
|
||||
# The OBS PPA may not yet support newer Ubuntu versions.
|
||||
# On those, use the native obs-studio packages and install libobs-dev separately,
|
||||
# as it is not bundled in obs-studio itself on newer Ubuntu releases.
|
||||
local -a obs_packages=(build-essential libgles2-mesa-dev libsimde-dev obs-studio)
|
||||
if is-at-least 26.04 ${dist_version}; then
|
||||
obs_packages+=(libobs-dev)
|
||||
else
|
||||
sudo add-apt-repository --yes ppa:obsproject/obs-studio
|
||||
sudo apt update
|
||||
fi
|
||||
|
||||
sudo apt-get install ${apt_args} ${obs_packages}
|
||||
|
||||
local -a _qt_packages=()
|
||||
|
||||
|
||||
4
.github/workflows/build-debian.yml
vendored
4
.github/workflows/build-debian.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: "recursive"
|
||||
- name: check_libobs_revision
|
||||
@@ -50,7 +50,7 @@ jobs:
|
||||
mv ../*.deb .
|
||||
- name: Publish
|
||||
if: success()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: "obs-scene-switcher.deb"
|
||||
path: ${{ github.workspace }}/*.deb
|
||||
|
||||
144
.github/workflows/build-project.yaml
vendored
144
.github/workflows/build-project.yaml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
description: "Project name detected by parsing build spec file"
|
||||
value: ${{ jobs.check-event.outputs.pluginName }}
|
||||
env:
|
||||
DEP_DIR: .deps/advss-build-dependencies
|
||||
DEP_DIR: .deps/advss-build-dependencies-6
|
||||
jobs:
|
||||
check-event:
|
||||
name: Check GitHub Event Data 🔎
|
||||
@@ -22,7 +22,7 @@ jobs:
|
||||
commitHash: ${{ steps.setup.outputs.commitHash }}
|
||||
pluginName: ${{ steps.setup.outputs.pluginName }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Check Event Data ☑️
|
||||
@@ -75,13 +75,13 @@ jobs:
|
||||
|
||||
macos-build:
|
||||
name: Build for macOS 🍏
|
||||
runs-on: macos-14
|
||||
runs-on: macos-15
|
||||
needs: check-event
|
||||
defaults:
|
||||
run:
|
||||
shell: zsh --no-rcs --errexit --pipefail {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
@@ -107,11 +107,11 @@ 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
|
||||
- uses: actions/cache@v5
|
||||
id: ccache-cache
|
||||
with:
|
||||
path: ${{ github.workspace }}/.ccache
|
||||
@@ -163,13 +163,13 @@ jobs:
|
||||
codesignPass: ${{ secrets.MACOS_NOTARIZATION_PASSWORD }}
|
||||
|
||||
- name: Upload Artifacts 📡
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-macos-universal-${{ needs.check-event.outputs.commitHash }}
|
||||
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-macos-universal.*
|
||||
|
||||
- name: Upload Debug Symbol Artifacts 🪲
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
if: ${{ needs.check-event.outputs.config == 'Release' }}
|
||||
with:
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-macos-universal-${{ needs.check-event.outputs.commitHash }}-dSYMs
|
||||
@@ -183,7 +183,7 @@ jobs:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
@@ -202,7 +202,7 @@ jobs:
|
||||
echo "pluginName=${product_name}" >> $GITHUB_OUTPUT
|
||||
echo "pluginVersion=${git_tag}" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v4
|
||||
- uses: actions/cache@v5
|
||||
id: ccache-cache
|
||||
with:
|
||||
path: ${{ github.workspace }}/.ccache
|
||||
@@ -210,13 +210,19 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-ccache-x86_64-
|
||||
|
||||
- name: Set up CMake 🏗️
|
||||
uses: jwlawson/actions-setup-cmake@v1.13
|
||||
with:
|
||||
cmake-version: '3.24.x'
|
||||
|
||||
- name: Set up Homebrew 🍺
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
uses: Homebrew/actions/setup-homebrew@main
|
||||
|
||||
- name: Install Vulkan SDK 🌋
|
||||
shell: bash
|
||||
run: |
|
||||
wget -qO- https://packages.lunarg.com/lunarg-signing-key-pub.asc \
|
||||
| sudo tee /etc/apt/trusted.gpg.d/lunarg.asc
|
||||
sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-noble.list \
|
||||
https://packages.lunarg.com/vulkan/lunarg-vulkan-noble.list
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y vulkan-sdk
|
||||
echo "VULKAN_SDK=/usr" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build Plugin 🧱
|
||||
uses: ./.github/actions/build-plugin
|
||||
@@ -238,23 +244,111 @@ jobs:
|
||||
config: ${{ needs.check-event.outputs.config }}
|
||||
|
||||
- name: Upload Source Tarball 🗜️
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-sources-${{ needs.check-event.outputs.commitHash }}
|
||||
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-source.*
|
||||
|
||||
- name: Rename artifacts for Ubuntu 24 🏷️
|
||||
run: |
|
||||
: Rename artifacts for Ubuntu 24 🏷️
|
||||
for f in ${{ github.workspace }}/release/*-x86_64-linux-gnu.*; do
|
||||
[ -e "${f}" ] || continue
|
||||
mv "${f}" "${f/x86_64-linux-gnu/x86_64-ubuntu24.04-linux-gnu}"
|
||||
done
|
||||
|
||||
- name: Upload Artifacts 📡
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
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
|
||||
uses: actions/upload-artifact@v7
|
||||
if: ${{ fromJSON(needs.check-event.outputs.package) }}
|
||||
with:
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-24.04-x86_64-${{ needs.check-event.outputs.commitHash }}-dbgsym
|
||||
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*-dbgsym.ddeb
|
||||
if-no-files-found: ignore
|
||||
|
||||
ubuntu-26-build:
|
||||
name: Build for Ubuntu 26 🐧
|
||||
runs-on: ubuntu-26.04
|
||||
needs: check-event
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set Up Environment 🔧
|
||||
id: setup
|
||||
run: |
|
||||
: Set Up Environment 🔧
|
||||
if [[ "${RUNNER_DEBUG}" ]]; then set -x; fi
|
||||
|
||||
git_tag="$(git describe --tags)"
|
||||
|
||||
read -r product_name product_version <<< \
|
||||
"$(jq -r '. | {name, version} | join(" ")' buildspec.json)"
|
||||
|
||||
echo "pluginName=${product_name}" >> $GITHUB_OUTPUT
|
||||
echo "pluginVersion=${git_tag}" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v5
|
||||
id: ccache-cache
|
||||
with:
|
||||
path: ${{ github.workspace }}/.ccache
|
||||
key: ${{ runner.os }}-ccache-x86_64-${{ needs.check-event.outputs.config }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-ccache-x86_64-
|
||||
|
||||
- name: Set up Homebrew 🍺
|
||||
uses: Homebrew/actions/setup-homebrew@main
|
||||
|
||||
- name: Build Plugin 🧱
|
||||
uses: ./.github/actions/build-plugin
|
||||
with:
|
||||
target: x86_64
|
||||
config: ${{ needs.check-event.outputs.config }}
|
||||
|
||||
- name: Run tests
|
||||
uses: ./.github/actions/run-tests
|
||||
with:
|
||||
target: x86_64
|
||||
config: ${{ needs.check-event.outputs.config }}
|
||||
|
||||
- name: Package Plugin 📀
|
||||
uses: ./.github/actions/package-plugin
|
||||
with:
|
||||
package: ${{ fromJSON(needs.check-event.outputs.package) }}
|
||||
target: x86_64
|
||||
config: ${{ needs.check-event.outputs.config }}
|
||||
|
||||
- name: Rename artifacts for Ubuntu 26 🏷️
|
||||
run: |
|
||||
: Rename artifacts for Ubuntu 26 🏷️
|
||||
for f in ${{ github.workspace }}/release/*-x86_64-linux-gnu.*; do
|
||||
[ -e "${f}" ] || continue
|
||||
mv "${f}" "${f/x86_64-linux-gnu/x86_64-ubuntu26.04-linux-gnu}"
|
||||
done
|
||||
|
||||
- name: Upload Artifacts 📡
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-26.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@v7
|
||||
if: ${{ fromJSON(needs.check-event.outputs.package) }}
|
||||
with:
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-26.04-x86_64-${{ needs.check-event.outputs.commitHash }}-dbgsym
|
||||
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*-dbgsym.ddeb
|
||||
if-no-files-found: ignore
|
||||
|
||||
windows-build:
|
||||
name: Build for Windows 🪟
|
||||
@@ -264,7 +358,7 @@ jobs:
|
||||
run:
|
||||
shell: pwsh
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
@@ -291,6 +385,12 @@ jobs:
|
||||
target: x64
|
||||
config: ${{ needs.check-event.outputs.config }}
|
||||
|
||||
- name: Install Vulkan SDK 🌋
|
||||
uses: jakoch/install-vulkan-sdk-action@v1
|
||||
with:
|
||||
install_runtime: false
|
||||
cache: true
|
||||
|
||||
- name: Build Plugin 🧱
|
||||
uses: ./.github/actions/build-plugin
|
||||
with:
|
||||
@@ -311,7 +411,7 @@ jobs:
|
||||
package: ${{ fromJSON(needs.check-event.outputs.package) }}
|
||||
|
||||
- name: Upload Artifacts 📡
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-windows-x64-${{ needs.check-event.outputs.commitHash }}
|
||||
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-windows-x64*.*
|
||||
|
||||
4
.github/workflows/check-format.yaml
vendored
4
.github/workflows/check-format.yaml
vendored
@@ -5,7 +5,7 @@ jobs:
|
||||
clang-format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: clang-format check 🐉
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
cmake-format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: cmake-format check 🎛️
|
||||
|
||||
2
.github/workflows/locale-check.yml
vendored
2
.github/workflows/locale-check.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Check locale files
|
||||
run: |
|
||||
|
||||
5
.github/workflows/push.yaml
vendored
5
.github/workflows/push.yaml
vendored
@@ -59,7 +59,7 @@ jobs:
|
||||
esac
|
||||
|
||||
- name: Download Build Artifacts 📥
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
if: fromJSON(steps.check.outputs.validTag)
|
||||
id: download
|
||||
|
||||
@@ -78,6 +78,7 @@ jobs:
|
||||
'windows-x64;zip|exe'
|
||||
'macos-universal;tar.xz|pkg'
|
||||
'ubuntu-24.04-x86_64;tar.xz|deb|ddeb'
|
||||
'ubuntu-26.04-x86_64;tar.xz|deb|ddeb'
|
||||
'sources;tar.xz'
|
||||
)
|
||||
|
||||
@@ -106,7 +107,7 @@ jobs:
|
||||
- name: Create Release 🛫
|
||||
if: fromJSON(steps.check.outputs.validTag)
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@d4e8205d7e959a9107da6396278b2f1f07af0f9b
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda
|
||||
with:
|
||||
draft: true
|
||||
prerelease: ${{ fromJSON(steps.check.outputs.prerelease) }}
|
||||
|
||||
15
.gitmodules
vendored
15
.gitmodules
vendored
@@ -28,6 +28,15 @@
|
||||
[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
|
||||
[submodule "deps/opencv_contrib"]
|
||||
path = deps/opencv_contrib
|
||||
url = https://github.com/opencv/opencv_contrib.git
|
||||
[submodule "deps/whisper.cpp"]
|
||||
path = deps/whisper.cpp
|
||||
url = https://github.com/ggml-org/whisper.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)
|
||||
```
|
||||
|
||||
168
CMakeLists.txt
168
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)
|
||||
|
||||
@@ -16,6 +16,14 @@ if(BUILD_OUT_OF_TREE)
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake"
|
||||
NO_POLICY_SCOPE)
|
||||
include(compilerconfig)
|
||||
# OPENSSL_USE_STATIC_LIBS here ensures FindOpenSSL picks up the static libs
|
||||
# preventing DLL name collisions with other plugins (e.g.NVIDIA AR SDK).
|
||||
if(OS_WINDOWS)
|
||||
set(OPENSSL_USE_STATIC_LIBS
|
||||
ON
|
||||
CACHE BOOL "Use static OpenSSL" FORCE)
|
||||
include(cmake/windows/wingetssl.cmake)
|
||||
endif()
|
||||
include(defaults)
|
||||
include(helpers)
|
||||
endif()
|
||||
@@ -99,12 +107,12 @@ target_sources(
|
||||
lib/macro/macro-action-edit.hpp
|
||||
lib/macro/macro-action-factory.cpp
|
||||
lib/macro/macro-action-factory.hpp
|
||||
lib/macro/macro-action-loop.cpp
|
||||
lib/macro/macro-action-loop.hpp
|
||||
lib/macro/macro-action-macro.cpp
|
||||
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
|
||||
@@ -117,8 +125,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
|
||||
@@ -127,6 +133,15 @@ 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-builtin-extensions.cpp
|
||||
lib/macro/macro-export-extensions.cpp
|
||||
lib/macro/macro-export-extensions.hpp
|
||||
lib/macro/macro-export-import-dialog.cpp
|
||||
lib/macro/macro-export-import-dialog.hpp
|
||||
lib/macro/macro-helpers.cpp
|
||||
@@ -139,25 +154,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)
|
||||
|
||||
@@ -172,8 +189,12 @@ target_sources(
|
||||
lib/utils/auto-update-tooltip-label.hpp
|
||||
lib/utils/backup.cpp
|
||||
lib/utils/backup.hpp
|
||||
lib/utils/canvas-helpers.cpp
|
||||
lib/utils/canvas-helpers.hpp
|
||||
lib/utils/condition-logic.cpp
|
||||
lib/utils/condition-logic.hpp
|
||||
lib/utils/crash-handler.cpp
|
||||
lib/utils/crash-handler.hpp
|
||||
lib/utils/curl-helper.cpp
|
||||
lib/utils/curl-helper.hpp
|
||||
lib/utils/cursor-shape-changer.cpp
|
||||
@@ -191,10 +212,21 @@ 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/first-run-wizard-audio.cpp
|
||||
lib/utils/first-run-wizard-audio.hpp
|
||||
lib/utils/first-run-wizard-helpers.hpp
|
||||
lib/utils/first-run-wizard-sequence.cpp
|
||||
lib/utils/first-run-wizard-sequence.hpp
|
||||
lib/utils/first-run-wizard-window.cpp
|
||||
lib/utils/first-run-wizard-window.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
|
||||
@@ -221,17 +253,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
|
||||
@@ -274,6 +303,10 @@ target_sources(
|
||||
lib/utils/volume-control.hpp
|
||||
lib/utils/websocket-api.cpp
|
||||
lib/utils/websocket-api.hpp
|
||||
lib/variables/variable-color-button.cpp
|
||||
lib/variables/variable-color-button.hpp
|
||||
lib/variables/variable-color.cpp
|
||||
lib/variables/variable-color.hpp
|
||||
lib/variables/variable-line-edit.cpp
|
||||
lib/variables/variable-line-edit.hpp
|
||||
lib/variables/variable-number.hpp
|
||||
@@ -346,6 +379,9 @@ set_target_properties(${LIB_NAME} PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)
|
||||
target_compile_features(${LIB_NAME} PUBLIC cxx_std_17)
|
||||
|
||||
target_precompile_headers(${LIB_NAME} PRIVATE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/lib/pch.hpp")
|
||||
|
||||
target_include_directories(
|
||||
${LIB_NAME} PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/deps/obs-websocket/lib"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/deps/exprtk")
|
||||
@@ -358,6 +394,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)
|
||||
@@ -411,6 +462,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}")
|
||||
@@ -426,14 +478,29 @@ else()
|
||||
endif()
|
||||
if(PROCPS2_INCLUDE_DIR)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(libproc2 IMPORTED_TARGET libproc2<4.0.5 QUIET)
|
||||
if(libproc2_FOUND)
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_USE_INFO)
|
||||
endif()
|
||||
pkg_check_modules(libproc2 REQUIRED IMPORTED_TARGET libproc2)
|
||||
set(PROC_INCLUDE_DIR "${PROCPS2_INCLUDE_DIR}")
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_AVAILABLE)
|
||||
set(PROCESS_CONDITION_SUPPORTED 1)
|
||||
|
||||
# Check if PIDS_VAL takes 4 arguments (old API, pre-4.0.5) or 3 (new API)
|
||||
include(CheckCSourceCompiles)
|
||||
set(CMAKE_REQUIRED_INCLUDES "${PROCPS2_INCLUDE_DIR}")
|
||||
set(CMAKE_REQUIRED_LIBRARIES proc2)
|
||||
check_c_source_compiles(
|
||||
"
|
||||
#include <libproc2/pids.h>
|
||||
int main(void) {
|
||||
struct pids_stack *s = 0;
|
||||
struct pids_info *i = 0;
|
||||
(void)PIDS_VAL(0, str, s, i);
|
||||
return 0;
|
||||
}
|
||||
"
|
||||
PROCPS2_PIDS_VAL_TAKES_INFO)
|
||||
if(PROCPS2_PIDS_VAL_TAKES_INFO)
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_USE_INFO)
|
||||
endif()
|
||||
endif()
|
||||
if(NOT DEFINED PROCESS_CONDITION_SUPPORTED)
|
||||
message(
|
||||
@@ -442,7 +509,8 @@ 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/.*")
|
||||
@@ -458,7 +526,11 @@ endif()
|
||||
# --- End of section ---
|
||||
|
||||
add_subdirectory(plugins)
|
||||
add_subdirectory(tests)
|
||||
|
||||
option(ADVSS_ENABLE_TESTS "Build advanced-scene-switcher unit tests" OFF)
|
||||
if(ADVSS_ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
# --- Install ---
|
||||
|
||||
@@ -487,3 +559,59 @@ else()
|
||||
set_target_properties_obs(${PROJECT_NAME} PROPERTIES PREFIX "")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# --- Install third-party dependency licenses ---
|
||||
#
|
||||
# Each entry is "display-name:path/to/license/file" relative to deps/. Files are
|
||||
# silently skipped when a submodule is not checked out.
|
||||
set(_dep_license_files
|
||||
"asio:asio/asio/LICENSE_1_0.txt"
|
||||
"cpp-httplib:cpp-httplib/LICENSE"
|
||||
"json:json/LICENSE.MIT"
|
||||
"jsoncons:jsoncons/LICENSE"
|
||||
"leptonica:leptonica/leptonica-license.txt"
|
||||
"libremidi:libremidi/LICENSE.md"
|
||||
"libusb:libusb/COPYING"
|
||||
"opencv:opencv/LICENSE"
|
||||
"openvr:openvr/LICENSE"
|
||||
"paho-mqtt:paho.mqtt.cpp/LICENSE"
|
||||
"tesseract:tesseract/LICENSE"
|
||||
"websocketpp:websocketpp/COPYING"
|
||||
"whisper:whisper.cpp/LICENSE")
|
||||
|
||||
if(DEB_INSTALL)
|
||||
if(NOT DATA_OUT_DIR)
|
||||
set(DATA_OUT_DIR "/share/obs/obs-plugins/${PROJECT_NAME}")
|
||||
endif()
|
||||
set(_license_dest "${CMAKE_INSTALL_PREFIX}/${DATA_OUT_DIR}/licenses")
|
||||
elseif(OS_MACOS)
|
||||
# macOS: license files become bundle Resources/licenses/* entries
|
||||
set(_license_dest "")
|
||||
else()
|
||||
# Windows and non-DEB Linux: alongside the plugin's data directory
|
||||
set(_license_dest "${CMAKE_PROJECT_NAME}/data/licenses")
|
||||
endif()
|
||||
|
||||
foreach(_entry IN LISTS _dep_license_files)
|
||||
string(REGEX MATCH "^([^:]+):(.+)$" _m "${_entry}")
|
||||
set(_dep_name "${CMAKE_MATCH_1}")
|
||||
set(_dep_file "${CMAKE_CURRENT_SOURCE_DIR}/deps/${CMAKE_MATCH_2}")
|
||||
|
||||
if(NOT EXISTS "${_dep_file}")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
if(OS_MACOS)
|
||||
# Copy to binary dir so we can give the file a clean name
|
||||
set(_staged "${CMAKE_CURRENT_BINARY_DIR}/licenses/LICENSE-${_dep_name}")
|
||||
configure_file("${_dep_file}" "${_staged}" COPYONLY)
|
||||
target_sources(${PROJECT_NAME} PRIVATE "${_staged}")
|
||||
set_source_files_properties("${_staged}" PROPERTIES MACOSX_PACKAGE_LOCATION
|
||||
"Resources/licenses")
|
||||
else()
|
||||
install(
|
||||
FILES "${_dep_file}"
|
||||
DESTINATION "${_license_dest}"
|
||||
RENAME "LICENSE-${_dep_name}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
"description": "Build for macOS 11.0+ (Universal binary) for CI",
|
||||
"generator": "Xcode",
|
||||
"cacheVariables": {
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||
"ADVSS_ENABLE_TESTS": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -69,7 +70,8 @@
|
||||
"displayName": "Windows x64 CI build",
|
||||
"description": "Build for Windows x64 on CI",
|
||||
"cacheVariables": {
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||
"ADVSS_ENABLE_TESTS": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -97,7 +99,8 @@
|
||||
"description": "Build for Linux x86_64 on CI",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||
"ADVSS_ENABLE_TESTS": true
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -125,7 +128,8 @@
|
||||
"description": "Build for Linux aarch64 on CI",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true
|
||||
"CMAKE_COMPILE_WARNING_AS_ERROR": true,
|
||||
"ADVSS_ENABLE_TESTS": true
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
@@ -14,10 +14,7 @@ On Linux the plugin is available via the **Flatpak** package manager for users w
|
||||
flatpak install com.obsproject.Studio.Plugin.SceneSwitcher
|
||||
```
|
||||
|
||||
The **Snap** package manager offers an OBS Studio installation which is bundled with the plugin:
|
||||
```
|
||||
sudo snap install obs-studio
|
||||
```
|
||||
More information can be found [here](https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation).
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
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"
|
||||
23
build-aux/CI/windows/README-portable.txt
Normal file
23
build-aux/CI/windows/README-portable.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
Advanced Scene Switcher - Windows Installation (Portable)
|
||||
==========================================================
|
||||
|
||||
For full installation instructions visit:
|
||||
https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation
|
||||
|
||||
|
||||
This archive uses the portable plugin layout for older OBS versions,
|
||||
portable OBS installs, and Steam.
|
||||
|
||||
Extract the CONTENTS of this archive into your OBS installation directory,
|
||||
typically:
|
||||
|
||||
C:\Program Files\obs-studio\
|
||||
|
||||
Merge the data\ and obs-plugins\ folders with the existing ones when prompted.
|
||||
|
||||
Steam users: right-click OBS in your library -> Manage -> Browse local files,
|
||||
then extract the contents of this archive into that directory.
|
||||
|
||||
|
||||
For OBS 28 and newer the recommended archive is preferred:
|
||||
advanced-scene-switcher-<version>-windows-x64.zip
|
||||
21
build-aux/CI/windows/README.txt
Normal file
21
build-aux/CI/windows/README.txt
Normal file
@@ -0,0 +1,21 @@
|
||||
Advanced Scene Switcher - Windows Installation
|
||||
===============================================
|
||||
|
||||
For full installation instructions visit:
|
||||
https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation
|
||||
|
||||
|
||||
This archive uses the recommended plugin layout for OBS 28 and newer.
|
||||
|
||||
Extract the CONTENTS of this archive into:
|
||||
|
||||
C:\ProgramData\obs-studio\plugins\
|
||||
|
||||
Tip: press Win+R and type %ProgramData%\obs-studio\plugins to open that folder.
|
||||
|
||||
After extracting, the path should look like:
|
||||
C:\ProgramData\obs-studio\plugins\advanced-scene-switcher\bin\64bit\advanced-scene-switcher.dll
|
||||
|
||||
|
||||
If the plugin does not appear in OBS, try the portable archive instead:
|
||||
advanced-scene-switcher-<version>-windows-x64-portable.zip
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
if(BUILD_OUT_OF_TREE)
|
||||
if(OS_WINDOWS)
|
||||
set(OBS_PLUGIN_DESTINATION "obs-plugins/64bit")
|
||||
set(OBS_PLUGIN_DESTINATION "${CMAKE_PROJECT_NAME}/bin/64bit")
|
||||
else()
|
||||
set(OBS_PLUGIN_DESTINATION "${CMAKE_INSTALL_LIBDIR}/obs-plugins")
|
||||
endif()
|
||||
@@ -157,7 +157,9 @@ else()
|
||||
set_target_properties(${target} PROPERTIES INSTALL_RPATH
|
||||
"$ORIGIN:$ORIGIN/..")
|
||||
endif()
|
||||
message(STATUS "ADVSS: ENABLED PLUGIN ${target}")
|
||||
get_filename_component(_plugin_dir_name "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
|
||||
set_property(GLOBAL APPEND PROPERTY ADVSS_PLUGINS_ENABLED
|
||||
${_plugin_dir_name})
|
||||
endfunction()
|
||||
|
||||
function(install_advss_plugin_dependency_target target dep)
|
||||
@@ -331,6 +333,8 @@ function(setup_advss_plugin target)
|
||||
PRIVATE "${ADVSS_SOURCE_DIR}/lib" "${ADVSS_SOURCE_DIR}/lib/legacy"
|
||||
"${ADVSS_SOURCE_DIR}/lib/macro" "${ADVSS_SOURCE_DIR}/lib/utils"
|
||||
"${ADVSS_SOURCE_DIR}/lib/variables" "${ADVSS_SOURCE_DIR}/forms")
|
||||
|
||||
target_precompile_headers(${target} PRIVATE "${ADVSS_SOURCE_DIR}/lib/pch.hpp")
|
||||
endfunction()
|
||||
|
||||
function(install_advss_plugin_dependency)
|
||||
|
||||
@@ -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,53 @@ 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)
|
||||
|
||||
list(GET download_status 0 error_code)
|
||||
list(GET download_status 1 error_message)
|
||||
|
||||
if(error_code EQUAL 0)
|
||||
file(SHA256 "${dependencies_dir}/${file}" actual_hash)
|
||||
if(NOT actual_hash STREQUAL hash)
|
||||
set(error_code 1)
|
||||
set(error_message
|
||||
"hash mismatch (expected ${hash}, got ${actual_hash})")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
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}
|
||||
|
||||
@@ -18,8 +18,11 @@ set(CPACK_PACKAGE_FILE_NAME
|
||||
"${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CMAKE_C_LIBRARY_ARCHITECTURE}"
|
||||
)
|
||||
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
set(CPACK_GENERATOR
|
||||
"DEB"
|
||||
CACHE STRING "CPack generator to use")
|
||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS "obs-studio")
|
||||
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${PLUGIN_EMAIL}")
|
||||
set(CPACK_SET_DESTDIR ON)
|
||||
|
||||
@@ -46,6 +49,19 @@ set(CPACK_SOURCE_PACKAGE_FILE_NAME
|
||||
set(CPACK_ARCHIVE_THREADS 0)
|
||||
|
||||
include(CPack)
|
||||
# CPack.cmake has a side effect that leaves binary packaging variables in the
|
||||
# state intended for source packaging when it finishes. Specifically it sets
|
||||
# CPACK_GENERATOR to CPACK_SOURCE_GENERATOR ("TXZ"), sets
|
||||
# CPACK_INSTALLED_DIRECTORIES to the source root (which would cause CPackDeb to
|
||||
# scan the entire source tree, including ccache object files that lack a Build
|
||||
# ID), and clears CPACK_INSTALL_CMAKE_PROJECTS (preventing the cmake install
|
||||
# mechanism from being used). In some cmake versions these overrides happen
|
||||
# before CPackConfig.cmake is written. Reset all three so that binary DEB
|
||||
# packaging works correctly regardless of cmake version.
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
set(CPACK_INSTALLED_DIRECTORIES "")
|
||||
set(CPACK_INSTALL_CMAKE_PROJECTS
|
||||
"${CMAKE_BINARY_DIR};${CMAKE_PROJECT_NAME};ALL;/")
|
||||
|
||||
find_package(libobs QUIET)
|
||||
|
||||
|
||||
@@ -6,7 +6,11 @@ include(buildspec_common)
|
||||
|
||||
# _check_dependencies_windows: Set up Windows slice for _check_dependencies
|
||||
function(_check_dependencies_windows)
|
||||
set(arch ${CMAKE_GENERATOR_PLATFORM})
|
||||
if(CMAKE_GENERATOR_PLATFORM)
|
||||
set(arch ${CMAKE_GENERATOR_PLATFORM})
|
||||
else()
|
||||
set(arch x64)
|
||||
endif()
|
||||
set(platform windows-${arch})
|
||||
|
||||
set(dependencies_dir "${CMAKE_CURRENT_SOURCE_DIR}/.deps")
|
||||
|
||||
@@ -6,3 +6,9 @@ include_guard(GLOBAL)
|
||||
set(CMAKE_FIND_PACKAGE_TARGETS_GLOBAL TRUE)
|
||||
|
||||
include(buildspec)
|
||||
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||
set(CMAKE_INSTALL_PREFIX
|
||||
"$ENV{ALLUSERSPROFILE}/obs-studio/plugins"
|
||||
CACHE STRING "Default plugin installation directory" FORCE)
|
||||
endif()
|
||||
|
||||
@@ -30,13 +30,13 @@ function(set_target_properties_plugin target)
|
||||
|
||||
install(
|
||||
TARGETS ${target}
|
||||
RUNTIME DESTINATION bin/64bit
|
||||
LIBRARY DESTINATION obs-plugins/64bit)
|
||||
RUNTIME DESTINATION "${target}/bin/64bit"
|
||||
LIBRARY DESTINATION "${target}/bin/64bit")
|
||||
|
||||
install(
|
||||
FILES "$<TARGET_PDB_FILE:${target}>"
|
||||
CONFIGURATIONS RelWithDebInfo Debug Release
|
||||
DESTINATION obs-plugins/64bit
|
||||
DESTINATION "${target}/bin/64bit"
|
||||
OPTIONAL)
|
||||
|
||||
if(OBS_BUILD_DIR)
|
||||
@@ -44,11 +44,11 @@ function(set_target_properties_plugin target)
|
||||
TARGET ${target}
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory
|
||||
"${OBS_BUILD_DIR}/obs-plugins/64bit"
|
||||
"${OBS_BUILD_DIR}/plugins/${target}/bin/64bit"
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -E copy_if_different "$<TARGET_FILE:${target}>"
|
||||
"$<$<CONFIG:Debug,RelWithDebInfo,Release>:$<TARGET_PDB_FILE:${target}>>"
|
||||
"${OBS_BUILD_DIR}/obs-plugins/64bit"
|
||||
"${OBS_BUILD_DIR}/plugins/${target}/bin/64bit"
|
||||
COMMENT "Copy ${target} to obs-studio directory ${OBS_BUILD_DIR}"
|
||||
VERBATIM)
|
||||
endif()
|
||||
@@ -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")
|
||||
@@ -103,7 +105,7 @@ function(target_install_resources target)
|
||||
|
||||
install(
|
||||
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/data/"
|
||||
DESTINATION data/obs-plugins/${target}
|
||||
DESTINATION "${target}/data"
|
||||
USE_SOURCE_PERMISSIONS)
|
||||
|
||||
if(OBS_BUILD_DIR)
|
||||
@@ -111,11 +113,11 @@ function(target_install_resources target)
|
||||
TARGET ${target}
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory
|
||||
"${OBS_BUILD_DIR}/data/obs-plugins/${target}"
|
||||
"${OBS_BUILD_DIR}/plugins/${target}/data"
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -E copy_directory
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/data"
|
||||
"${OBS_BUILD_DIR}/data/obs-plugins/${target}"
|
||||
"${OBS_BUILD_DIR}/plugins/${target}/data"
|
||||
COMMENT "Copy ${target} resources to data directory"
|
||||
VERBATIM)
|
||||
endif()
|
||||
@@ -131,7 +133,7 @@ function(target_add_resource target resource)
|
||||
|
||||
install(
|
||||
FILES "${resource}"
|
||||
DESTINATION data/obs-plugins/${target}
|
||||
DESTINATION "${target}/data"
|
||||
COMPONENT Runtime)
|
||||
|
||||
if(OBS_BUILD_DIR)
|
||||
@@ -139,9 +141,9 @@ function(target_add_resource target resource)
|
||||
TARGET ${target}
|
||||
POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory
|
||||
"${OBS_BUILD_DIR}/data/obs-plugins/${target}"
|
||||
"${OBS_BUILD_DIR}/plugins/${target}/data"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy "${resource}"
|
||||
"${OBS_BUILD_DIR}/data/obs-plugins/${target}"
|
||||
"${OBS_BUILD_DIR}/plugins/${target}/data"
|
||||
COMMENT "Copy ${target} resource ${resource} to library directory"
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
#define MyAppVersion "@CMAKE_PROJECT_VERSION@"
|
||||
#define MyAppPublisher "@PLUGIN_AUTHOR@"
|
||||
#define MyAppURL "@PLUGIN_WEBSITE@"
|
||||
#define MyAppId "@UUID_APP@"
|
||||
|
||||
[Setup]
|
||||
; NOTE: The value of AppId uniquely identifies this application.
|
||||
; Do not use the same AppId value in installers for other applications.
|
||||
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
||||
AppId={{@UUID_APP@}
|
||||
AppId={{{#MyAppId}}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppPublisher={#MyAppPublisher}
|
||||
@@ -20,12 +21,19 @@ OutputBaseFilename={#MyAppName}-{#MyAppVersion}-Windows-Installer
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
DirExistsWarning=no
|
||||
UsePreviousAppDir=no
|
||||
SetupIconFile=installer.ico
|
||||
UninstallDisplayIcon={code:GetUninstallIconPath}
|
||||
DisableDirPage=no
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Files]
|
||||
Source: "..\release\Package\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
; Recommended layout - used when installing to %ProgramData%\obs-studio\plugins\
|
||||
Source: "..\release\Package\recommended\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Check: IsRecommendedLayout
|
||||
; Legacy layout - used when installing to the OBS installation directory
|
||||
Source: "..\release\Package\portable\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Check: IsLegacyLayout
|
||||
Source: "..\LICENSE"; Flags: dontcopy
|
||||
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
||||
|
||||
@@ -48,17 +56,64 @@ begin
|
||||
);
|
||||
end;
|
||||
|
||||
// credit where it's due :
|
||||
// following function come from https://github.com/Xaymar/obs-studio_amf-encoder-plugin/blob/master/%23Resources/Installer.in.iss#L45
|
||||
function GetDirName(Value: string): string;
|
||||
var
|
||||
InstallPath: string;
|
||||
// Returns true when the selected install directory is under %ProgramData%,
|
||||
// meaning the recommended plugin layout should be used.
|
||||
function IsRecommendedLayout(): Boolean;
|
||||
begin
|
||||
// initialize default path, which will be returned when the following registry
|
||||
// key queries fail due to missing keys or for some different reason
|
||||
Result := '{autopf}\obs-studio';
|
||||
// query the first registry value; if this succeeds, return the obtained value
|
||||
if RegQueryStringValue(HKLM32, 'SOFTWARE\OBS Studio', '', InstallPath) then
|
||||
Result := InstallPath
|
||||
Result := Pos(LowerCase(ExpandConstant('{commonappdata}')),
|
||||
LowerCase(WizardDirValue())) = 1;
|
||||
end;
|
||||
|
||||
function IsLegacyLayout(): Boolean;
|
||||
begin
|
||||
Result := not IsRecommendedLayout();
|
||||
end;
|
||||
|
||||
function GetUninstallIconPath(Param: string): string;
|
||||
begin
|
||||
if IsRecommendedLayout() then
|
||||
Result := ExpandConstant('{app}\advanced-scene-switcher\data\res\images\logo.ico')
|
||||
else
|
||||
Result := ExpandConstant('{app}\data\obs-plugins\advanced-scene-switcher\res\images\logo.ico');
|
||||
end;
|
||||
|
||||
function GetDirName(Value: string): string;
|
||||
var
|
||||
PrevPath: string;
|
||||
UninstallKey: string;
|
||||
begin
|
||||
Result := ExpandConstant('{commonappdata}\obs-studio\plugins');
|
||||
UninstallKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + '{' + '{#MyAppId}' + '}_is1';
|
||||
if RegQueryStringValue(HKLM, UninstallKey, 'InstallLocation', PrevPath) and (PrevPath <> '') then
|
||||
Result := PrevPath;
|
||||
end;
|
||||
|
||||
// Remove files placed by the portable installer (obs-plugins/64bit and
|
||||
// data/obs-plugins layout) so the plugin is not loaded twice by OBS.
|
||||
// Only runs when upgrading from a portable location to the recommended one.
|
||||
procedure RemoveLegacyFiles();
|
||||
var
|
||||
OldInstallPath: string;
|
||||
UninstallKey: string;
|
||||
begin
|
||||
if not IsRecommendedLayout() then
|
||||
Exit;
|
||||
UninstallKey := 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\' + '{' + '{#MyAppId}' + '}_is1';
|
||||
if not RegQueryStringValue(HKLM, UninstallKey, 'InstallLocation', OldInstallPath) then
|
||||
Exit;
|
||||
// Skip if the previous install was already in the recommended location
|
||||
if Pos(LowerCase(ExpandConstant('{commonappdata}')), LowerCase(OldInstallPath)) = 1 then
|
||||
Exit;
|
||||
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher.dll');
|
||||
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher.pdb');
|
||||
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher-lib.dll');
|
||||
DeleteFile(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher-lib.pdb');
|
||||
DelTree(OldInstallPath + '\obs-plugins\64bit\advanced-scene-switcher-plugins', True, True, True);
|
||||
DelTree(OldInstallPath + '\data\obs-plugins\advanced-scene-switcher', True, True, True);
|
||||
end;
|
||||
|
||||
procedure CurStepChanged(CurStep: TSetupStep);
|
||||
begin
|
||||
if CurStep = ssInstall then
|
||||
RemoveLegacyFiles();
|
||||
end;
|
||||
|
||||
86
cmake/windows/wingetssl.cmake
Normal file
86
cmake/windows/wingetssl.cmake
Normal file
@@ -0,0 +1,86 @@
|
||||
# ---------------------------------------------------------------------------
|
||||
# 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
|
||||
if(OPENSSL_USE_STATIC_LIBS)
|
||||
set(_crypto_lib_name "libcrypto_static.lib")
|
||||
set(_ssl_lib_name "libssl_static.lib")
|
||||
else()
|
||||
set(_crypto_lib_name "libcrypto.lib")
|
||||
set(_ssl_lib_name "libssl.lib")
|
||||
endif()
|
||||
|
||||
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}/${_crypto_lib_name}")
|
||||
set(OPENSSL_ROOT_DIR
|
||||
"${_root}"
|
||||
CACHE PATH "Path to OpenSSL root")
|
||||
set(OPENSSL_CRYPTO_LIBRARY
|
||||
"${_root}/${_suffix}/${_crypto_lib_name}"
|
||||
CACHE FILEPATH "OpenSSL crypto lib")
|
||||
set(OPENSSL_SSL_LIBRARY
|
||||
"${_root}/${_suffix}/${_ssl_lib_name}"
|
||||
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?"
|
||||
@@ -101,7 +99,6 @@ AdvSceneSwitcher.macroList.deleted="gelöscht"
|
||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" ist bereits ausgewählt!"
|
||||
|
||||
; Macro Logic
|
||||
AdvSceneSwitcher.logic.none="Eintrag ignorieren"
|
||||
AdvSceneSwitcher.logic.and="Und"
|
||||
AdvSceneSwitcher.logic.or="Oder"
|
||||
AdvSceneSwitcher.logic.andNot="Und nicht"
|
||||
@@ -147,11 +144,7 @@ AdvSceneSwitcher.condition.file="Datei"
|
||||
AdvSceneSwitcher.condition.file.type.match="entspricht"
|
||||
AdvSceneSwitcher.condition.file.type.contentChange="Inhalt geändert"
|
||||
AdvSceneSwitcher.condition.file.type.dateChange="Änderungsdatum geändert"
|
||||
AdvSceneSwitcher.condition.file.remote="Entfernte Datei"
|
||||
AdvSceneSwitcher.condition.file.local="Lokale Datei"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.file.layout="{{filePath}}{{conditions}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.media="Medien"
|
||||
AdvSceneSwitcher.condition.media.source="Quelle"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Beliebige Medienquelle in"
|
||||
@@ -195,12 +188,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"
|
||||
@@ -217,8 +210,8 @@ AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Aufnahme gestoppt"
|
||||
AdvSceneSwitcher.condition.process="Prozess"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}läuft{{focused}}und ist fokusiert"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="Aktueller Vordergrundprozess: {{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}läuft{{focused}}und ist fokusiert"
|
||||
AdvSceneSwitcher.condition.process.layout.focus="Aktueller Vordergrundprozess: {{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="Leerlauf"
|
||||
AdvSceneSwitcher.condition.idle.entry="Keine Tastatur- oder Mauseingaben für {{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Plugin-Status"
|
||||
@@ -292,14 +285,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"
|
||||
@@ -310,12 +303,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"
|
||||
@@ -384,14 +378,12 @@ 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"
|
||||
AdvSceneSwitcher.action.wait.type.random="zufällig"
|
||||
AdvSceneSwitcher.action.wait.entry.fixed="Warte für {{waitType}} Dauer von {{duration}}"
|
||||
AdvSceneSwitcher.action.wait.entry.random="Warte für {{waitType}} Dauer von {{duration}} bis {{duration2}}"
|
||||
AdvSceneSwitcher.action.wait.layout.fixed="Warte für {{waitType}} Dauer von {{duration}}"
|
||||
AdvSceneSwitcher.action.wait.layout.random="Warte für {{waitType}} Dauer von {{duration}} bis {{duration2}}"
|
||||
AdvSceneSwitcher.action.audio="Audio"
|
||||
AdvSceneSwitcher.action.audio.type.mute="Stummgeschaltet"
|
||||
AdvSceneSwitcher.action.audio.type.unmute="Nicht stummgeschaltet"
|
||||
@@ -415,7 +407,6 @@ AdvSceneSwitcher.action.recording.type.unpause="Aufnahme nicht mehr pausieren"
|
||||
AdvSceneSwitcher.action.recording.type.split="Aufnahme-Datei teilen"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Bitte beachten, dass je nach Aufnahmeeinstellung die Aufnahme möglicherweise nicht unterbrochen werden kann"
|
||||
AdvSceneSwitcher.action.recording.split.hint="Vergewissern, dass die automatische Dateiaufteilung in den OBS-Einstellungen aktiviert ist!"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Replay Buffer"
|
||||
AdvSceneSwitcher.action.replay.saveWarn="Warnung: Ein zu häufiges Speichern kann dazu führen, dass der Replay Buffer nicht gespeichert wird!"
|
||||
AdvSceneSwitcher.action.replay.type.stop="Replay Buffer stoppen"
|
||||
@@ -424,7 +415,6 @@ AdvSceneSwitcher.action.replay.type.save="Replay Buffer speichern"
|
||||
AdvSceneSwitcher.action.streaming="Stream"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="Stream stoppen"
|
||||
AdvSceneSwitcher.action.streaming.type.start="Stream starten"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Ausführen"
|
||||
AdvSceneSwitcher.action.sceneVisibility="Sichtbarkeit von Szenenelementen"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Anzeigen"
|
||||
@@ -432,7 +422,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"
|
||||
@@ -460,14 +450,14 @@ AdvSceneSwitcher.action.macro="Makro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pausieren"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Nicht mehr pausieren"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Zähler zurücksetzen"
|
||||
AdvSceneSwitcher.action.macro.type.run="Aktionen ausführen"
|
||||
AdvSceneSwitcher.action.macro.type.runActions="Aktionen ausführen"
|
||||
AdvSceneSwitcher.action.macro.type.stop="Aktionen stoppen"
|
||||
AdvSceneSwitcher.action.pluginState="Plugin-Status"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenwechsler stoppen"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="Einstellungen importieren aus"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Hinweis: Die Aktion wird ignoriert, solange das Einstellungsfenster geöffnet ist."
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{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"
|
||||
@@ -508,9 +498,9 @@ AdvSceneSwitcher.action.transition.type.scene="Szenenübergang"
|
||||
AdvSceneSwitcher.action.transition.type.sceneOverride="Szenenübergang überschreiben"
|
||||
AdvSceneSwitcher.action.transition.type.sourceShow="Übergang der Quelle anzeigen"
|
||||
AdvSceneSwitcher.action.transition.type.sourceHide="Übergang der Quelle verstecken"
|
||||
AdvSceneSwitcher.action.transition.entry.line1="Anpassen {{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Übergangstyp festlegen auf {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Übergangsdauer festlegen auf {{duration}}Sekunden"
|
||||
AdvSceneSwitcher.action.transition.layout.type="Anpassen {{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Übergangstyp festlegen auf {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Übergangsdauer festlegen auf {{duration}}Sekunden"
|
||||
AdvSceneSwitcher.action.timer="Timer"
|
||||
AdvSceneSwitcher.action.timer.type.pause="Pausieren"
|
||||
AdvSceneSwitcher.action.timer.type.continue="Fortsetzen"
|
||||
@@ -753,9 +743,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}}"
|
||||
@@ -837,8 +827,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"
|
||||
@@ -85,7 +83,6 @@ AdvSceneSwitcher.macroTab.highlightTrueConditions="Resaltar condiciones de la ma
|
||||
AdvSceneSwitcher.macroTab.highlightPerformedActions="Resaltar acciones realizadas recientemente de la macro seleccionada actualmente"
|
||||
|
||||
; Lógica de macros
|
||||
AdvSceneSwitcher.logic.none="Omitir entrada"
|
||||
AdvSceneSwitcher.logic.and="Y"
|
||||
AdvSceneSwitcher.logic.or="O"
|
||||
AdvSceneSwitcher.logic.andNot="Y no"
|
||||
@@ -119,9 +116,7 @@ AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="Durante la tra
|
||||
AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="Durante la transición, verifique la escena de origen de la transición"
|
||||
AdvSceneSwitcher.condition.window="Ventana"
|
||||
AdvSceneSwitcher.condition.file="Archivo"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="Contenido de{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.file.layout="Contenido de{{filePath}}{{conditions}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.media="Medios"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Cualquier fuente multimedia activada"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="Todas las fuentes de medios activadas"
|
||||
@@ -155,12 +150,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"
|
||||
@@ -177,7 +172,7 @@ AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Grabación detenida"
|
||||
AdvSceneSwitcher.condition.process="Proceso"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}se está ejecutando{{focused}}y está enfocado"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}se está ejecutando{{focused}}y está enfocado"
|
||||
AdvSceneSwitcher.condition.idle="Inactivo"
|
||||
AdvSceneSwitcher.condition.idle.entry="No hay entradas de teclado o ratón durante {{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Estado del complemento"
|
||||
@@ -242,14 +237,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"
|
||||
@@ -259,11 +254,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"
|
||||
@@ -312,13 +308,12 @@ 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"
|
||||
AdvSceneSwitcher.action.wait.type.random="aleatorio"
|
||||
AdvSceneSwitcher.action.wait.entry.fixed="Espere {{waitType}} de {{duration}}"
|
||||
AdvSceneSwitcher.action.wait.entry.random="Espere {{waitType}} de {{duration}} a {{duration2}}"
|
||||
AdvSceneSwitcher.action.wait.layout.fixed="Espere {{waitType}} de {{duration}}"
|
||||
AdvSceneSwitcher.action.wait.layout.random="Espere {{waitType}} de {{duration}} a {{duration2}}"
|
||||
AdvSceneSwitcher.action.audio="Audio"
|
||||
AdvSceneSwitcher.action.audio.type.mute="Silencio"
|
||||
AdvSceneSwitcher.action.audio.type.unmute="Activar silencio"
|
||||
@@ -336,7 +331,6 @@ AdvSceneSwitcher.action.recording.type.start="Iniciar grabación"
|
||||
AdvSceneSwitcher.action.recording.type.pause="Pausar grabación"
|
||||
AdvSceneSwitcher.action.recording.type.unpause="Reanudar grabación"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Tenga en cuenta que, dependiendo de la configuración de grabación, es posible que no pueda pausar la grabación"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Búfer de reproducción"
|
||||
AdvSceneSwitcher.action.replay.saveWarn="Advertencia: ¡Guardar con demasiada frecuencia puede hacer que el búfer de reproducción no se guarde realmente!"
|
||||
AdvSceneSwitcher.action.replay.type.stop="Detener el búfer de reproducción"
|
||||
@@ -345,14 +339,13 @@ AdvSceneSwitcher.action.replay.type.save="Guardar búfer de reproducción"
|
||||
AdvSceneSwitcher.action.streaming="Transmisión"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="Detener transmisión"
|
||||
AdvSceneSwitcher.action.streaming.type.start="Iniciar transmisión"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Ejecutar"
|
||||
AdvSceneSwitcher.action.sceneVisibility="Visibilidad del elemento de escena"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Mostrar"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Fuente"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Cualquiera"
|
||||
AdvSceneSwitcher.action.sceneVisibility.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"
|
||||
@@ -377,14 +370,14 @@ AdvSceneSwitcher.action.macro="Macro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pausa"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Reanudar"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
|
||||
AdvSceneSwitcher.action.macro.type.run="Ejecutar"
|
||||
AdvSceneSwitcher.action.macro.type.runActions="Ejecutar"
|
||||
AdvSceneSwitcher.action.macro.type.stop="Detener"
|
||||
AdvSceneSwitcher.action.pluginState="Estado del complemento"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced Scene Switcher"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="Importar configuración desde"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Nota: la acción se ignorará mientras se abra la ventana de configuración."
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{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"
|
||||
@@ -425,9 +418,9 @@ AdvSceneSwitcher.action.transition.type.scene="transición de escena"
|
||||
AdvSceneSwitcher.action.transition.type.sceneOverride="anulación de transición de escena"
|
||||
AdvSceneSwitcher.action.transition.type.sourceShow="transición del programa de origen"
|
||||
AdvSceneSwitcher.action.transition.type.sourceHide="fuente ocultar transición"
|
||||
AdvSceneSwitcher.action.transition.entry.line1="Modificar {{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Establecer el tipo de transición en {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Establecer la duración de la transición en {{duration}}segundos"
|
||||
AdvSceneSwitcher.action.transition.layout.type="Modificar {{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Establecer el tipo de transición en {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Establecer la duración de la transición en {{duration}}segundos"
|
||||
AdvSceneSwitcher.action.timer="Temporizador"
|
||||
AdvSceneSwitcher.action.timer.type.pause="Pausa"
|
||||
AdvSceneSwitcher.action.timer.type.continue="Continuar"
|
||||
@@ -641,9 +634,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}}"
|
||||
@@ -682,8 +675,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\" ?"
|
||||
@@ -133,7 +131,6 @@ AdvSceneSwitcher.macroList.deleted="supprimé"
|
||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" est déjà sélectionné !"
|
||||
|
||||
; Macro Logic
|
||||
AdvSceneSwitcher.logic.none="Ignorer l'entrée"
|
||||
AdvSceneSwitcher.logic.and="Et"
|
||||
AdvSceneSwitcher.logic.or="Ou"
|
||||
AdvSceneSwitcher.logic.andNot="Et pas"
|
||||
@@ -189,8 +186,6 @@ AdvSceneSwitcher.condition.file="Fichier"
|
||||
AdvSceneSwitcher.condition.file.type.match="correspond à"
|
||||
AdvSceneSwitcher.condition.file.type.contentChange="a changé de contenu"
|
||||
AdvSceneSwitcher.condition.file.type.dateChange="a changé de date de modification"
|
||||
AdvSceneSwitcher.condition.file.remote="Fichier distant"
|
||||
AdvSceneSwitcher.condition.file.local="Fichier local"
|
||||
AdvSceneSwitcher.condition.media="Média"
|
||||
AdvSceneSwitcher.condition.media.source="Source"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Toute source média sur la scène"
|
||||
@@ -258,14 +253,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 :{{color}}"
|
||||
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}}"
|
||||
AdvSceneSwitcher.condition.video.minSize="Taille minimale :"
|
||||
AdvSceneSwitcher.condition.video.maxSize="Taille maximale :"
|
||||
AdvSceneSwitcher.condition.video.selectArea="Sélectionner la zone"
|
||||
@@ -283,8 +278,8 @@ AdvSceneSwitcher.condition.record.state.start="Enregistrement en cours"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Enregistrement en pause"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Arrêt de l'enregistrement"
|
||||
AdvSceneSwitcher.condition.process="Processus"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}en cours d'exécution{{focused}}et est au premier plan"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="Processus au premier plan actuel :{{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}en cours d'exécution{{focused}}et est au premier plan"
|
||||
AdvSceneSwitcher.condition.process.layout.focus="Processus au premier plan actuel :{{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="Inactif"
|
||||
AdvSceneSwitcher.condition.idle.entry="Aucune entrée de clavier ou de souris pendant{{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="État du plugin"
|
||||
@@ -357,14 +352,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 +370,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,14 +456,12 @@ 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"
|
||||
AdvSceneSwitcher.action.wait.type.random="aléatoire"
|
||||
AdvSceneSwitcher.action.wait.entry.fixed="Attendre pour{{waitType}}une durée de{{duration}}"
|
||||
AdvSceneSwitcher.action.wait.entry.random="Attendre pour{{waitType}}une durée de{{duration}}à{{duration2}}"
|
||||
AdvSceneSwitcher.action.wait.layout.fixed="Attendre pour{{waitType}}une durée de{{duration}}"
|
||||
AdvSceneSwitcher.action.wait.layout.random="Attendre pour{{waitType}}une durée de{{duration}}à{{duration2}}"
|
||||
AdvSceneSwitcher.action.audio="Audio"
|
||||
AdvSceneSwitcher.action.audio.type.mute="Muet"
|
||||
AdvSceneSwitcher.action.audio.type.unmute="Activer le son"
|
||||
@@ -513,7 +507,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"
|
||||
@@ -556,7 +550,7 @@ AdvSceneSwitcher.action.macro="Macro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pause"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Reprendre"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Réinitialiser le compteur"
|
||||
AdvSceneSwitcher.action.macro.type.run="Exécuter les actions"
|
||||
AdvSceneSwitcher.action.macro.type.runActions="Exécuter les actions"
|
||||
AdvSceneSwitcher.action.macro.type.stop="Arrêter les actions"
|
||||
AdvSceneSwitcher.action.macro.type.disableAction="Désactiver l'action"
|
||||
AdvSceneSwitcher.action.macro.type.enableAction="Activer l'action"
|
||||
@@ -625,9 +619,9 @@ AdvSceneSwitcher.action.transition.type.scene="Transition de scène"
|
||||
AdvSceneSwitcher.action.transition.type.sceneOverride="Remplacement de la transition de scène"
|
||||
AdvSceneSwitcher.action.transition.type.sourceShow="Transition d'affichage de la source"
|
||||
AdvSceneSwitcher.action.transition.type.sourceHide="Transition de masquage de la source"
|
||||
AdvSceneSwitcher.action.transition.entry.line1="Modifier{{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Définir le type de transition sur{{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Définir la durée de la transition à{{duration}}secondes"
|
||||
AdvSceneSwitcher.action.transition.layout.type="Modifier{{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Définir le type de transition sur{{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Définir la durée de la transition à{{duration}}secondes"
|
||||
AdvSceneSwitcher.action.timer="Minuterie"
|
||||
AdvSceneSwitcher.action.timer.type.pause="Mettre en pause"
|
||||
AdvSceneSwitcher.action.timer.type.continue="Continuer"
|
||||
@@ -704,10 +698,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"
|
||||
@@ -921,9 +915,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}}"
|
||||
@@ -1108,15 +1102,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"
|
||||
|
||||
@@ -1125,8 +1119,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."
|
||||
@@ -241,7 +239,6 @@ AdvSceneSwitcher.macroList.deleted="excluída"
|
||||
AdvSceneSwitcher.macroList.duplicate="\"%1\" já está selecionada!"
|
||||
|
||||
; Macro Logic
|
||||
AdvSceneSwitcher.logic.none="Ignorar entrada"
|
||||
AdvSceneSwitcher.logic.and="E"
|
||||
AdvSceneSwitcher.logic.or="Ou"
|
||||
AdvSceneSwitcher.logic.andNot="E não"
|
||||
@@ -297,11 +294,6 @@ AdvSceneSwitcher.condition.file="Arquivo"
|
||||
AdvSceneSwitcher.condition.file.type.match="corresponde"
|
||||
AdvSceneSwitcher.condition.file.type.contentChange="conteúdo mudou"
|
||||
AdvSceneSwitcher.condition.file.type.dateChange="data de modificação mudou"
|
||||
AdvSceneSwitcher.condition.file.remote="Arquivo remoto"
|
||||
AdvSceneSwitcher.condition.file.local="Arquivo local"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="Mídia"
|
||||
AdvSceneSwitcher.condition.media.checkType.state="Estado corresponde"
|
||||
AdvSceneSwitcher.condition.media.checkType.time="Restrição de tempo corresponde"
|
||||
@@ -373,16 +365,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:{{color}}"
|
||||
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}}"
|
||||
AdvSceneSwitcher.condition.video.minSize="Tamanho mínimo:"
|
||||
AdvSceneSwitcher.condition.video.maxSize="Tamanho máximo:"
|
||||
AdvSceneSwitcher.condition.video.selectArea="Selecionar área"
|
||||
@@ -402,8 +394,8 @@ AdvSceneSwitcher.condition.record.state.stop="Gravação parada"
|
||||
AdvSceneSwitcher.condition.record.state.duration="Duração da gravação é maior que"
|
||||
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
||||
AdvSceneSwitcher.condition.process="Processo"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}está em execução{{focused}}e está em foco"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="Processo atual em primeiro plano:{{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}está em execução{{focused}}e está em foco"
|
||||
AdvSceneSwitcher.condition.process.layout.focus="Processo atual em primeiro plano:{{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="Inativo"
|
||||
AdvSceneSwitcher.condition.idle.entry="Sem entradas de teclado ou mouse por {{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Estado do plugin"
|
||||
@@ -503,14 +495,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"
|
||||
@@ -521,12 +513,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"
|
||||
@@ -721,15 +714,12 @@ 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"
|
||||
AdvSceneSwitcher.action.wait.type.random="aleatório"
|
||||
AdvSceneSwitcher.action.wait.entry.fixed="Aguardando por{{waitType}}duração de{{duration}}"
|
||||
AdvSceneSwitcher.action.wait.entry.random="Aguardando por{{waitType}}duração de{{duration}}para{{duration2}}"
|
||||
AdvSceneSwitcher.action.wait.layout.fixed="Aguardando por{{waitType}}duração de{{duration}}"
|
||||
AdvSceneSwitcher.action.wait.layout.random="Aguardando por{{waitType}}duração de{{duration}}para{{duration2}}"
|
||||
AdvSceneSwitcher.action.audio="Áudio"
|
||||
AdvSceneSwitcher.action.audio.type.mute="Silenciar"
|
||||
AdvSceneSwitcher.action.audio.type.unmute="Ativar som"
|
||||
@@ -758,7 +748,6 @@ AdvSceneSwitcher.action.recording.type.changeOutputFolder="Alterar pasta de saí
|
||||
AdvSceneSwitcher.action.recording.type.changeOutputFileFormat="Alterar formatação do nome do arquivo"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Observe que dependendo das suas configurações de gravação, você pode não conseguir pausar a gravação"
|
||||
AdvSceneSwitcher.action.recording.split.hint="Certifique-se de habilitar a divisão automática de arquivos nas configurações do OBS primeiro!"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Buffer de replay"
|
||||
AdvSceneSwitcher.action.replay.saveWarn="Aviso: Salvar com muita frequência pode resultar em o buffer de replay não ser realmente salvo!"
|
||||
AdvSceneSwitcher.action.replay.durationWarn="Aviso: Alterar o tempo máximo de replay só se aplicará na próxima vez que o buffer de replay for iniciado!"
|
||||
@@ -775,7 +764,6 @@ AdvSceneSwitcher.action.streaming.type.server="Definir URL do servidor"
|
||||
AdvSceneSwitcher.action.streaming.type.streamKey="Definir chave de transmissão"
|
||||
AdvSceneSwitcher.action.streaming.type.username="Definir nome de usuário"
|
||||
AdvSceneSwitcher.action.streaming.type.password="Definir senha"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Executar"
|
||||
AdvSceneSwitcher.action.run.wait.entry="{{wait}}Aguardar a saída do processo ou no máximo {{timeout}}{{waitHelp}}"
|
||||
AdvSceneSwitcher.action.run.wait.help.tooltip="Observe que as propriedades da macro não funcionarão se você deixar isso desmarcado, pois o processo é iniciado de forma independente do restante da lógica e não há controle sobre ele."
|
||||
@@ -785,7 +773,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"
|
||||
@@ -850,7 +838,7 @@ AdvSceneSwitcher.action.macro="Macro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pausar"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Retomar"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
|
||||
AdvSceneSwitcher.action.macro.type.run="Executar macro"
|
||||
AdvSceneSwitcher.action.macro.type.runActions="Executar macro"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Não considerar o estado da condição"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.true="Apenas se as condições forem verdadeiras"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.false="Apenas se as condições forem falsas"
|
||||
@@ -865,9 +853,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:"
|
||||
@@ -875,7 +863,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"
|
||||
@@ -937,9 +925,9 @@ AdvSceneSwitcher.action.transition.type.scene="transição de cena"
|
||||
AdvSceneSwitcher.action.transition.type.sceneOverride="substituição de transição de cena"
|
||||
AdvSceneSwitcher.action.transition.type.sourceShow="transição de exibição de fonte"
|
||||
AdvSceneSwitcher.action.transition.type.sourceHide="transição de ocultação de fonte"
|
||||
AdvSceneSwitcher.action.transition.entry.line1="Modificar{{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Definir tipo de transição para{{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Definir duração da transição para{{duration}}segundos"
|
||||
AdvSceneSwitcher.action.transition.layout.type="Modificar{{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Definir tipo de transição para{{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Definir duração da transição para{{duration}}segundos"
|
||||
AdvSceneSwitcher.action.timer="Temporizador"
|
||||
AdvSceneSwitcher.action.timer.type.pause="Pausar"
|
||||
AdvSceneSwitcher.action.timer.type.continue="Continuar"
|
||||
@@ -1012,7 +1000,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"
|
||||
@@ -1032,13 +1020,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"
|
||||
@@ -1069,8 +1057,8 @@ AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Habilitar modo apenas
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Desabilitar modo apenas emotes no chat"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Enviar mensagem de chat"
|
||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Não é possível selecionar categoria sem selecionar uma conta Twitch primeiro!"
|
||||
AdvSceneSwitcher.action.twitch.entry.default="Em{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="Usando conta{{account}}{{actions}}em{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.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"
|
||||
@@ -1112,9 +1100,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}}"
|
||||
@@ -1852,19 +1840,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"
|
||||
|
||||
@@ -1875,8 +1863,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="Содержание файла"
|
||||
@@ -71,7 +70,6 @@ AdvSceneSwitcher.macroTab.name="Имя:"
|
||||
AdvSceneSwitcher.macroTab.defaultname="Макрос %1"
|
||||
AdvSceneSwitcher.macroTab.copy="Создать копию"
|
||||
; Macro Logic
|
||||
AdvSceneSwitcher.logic.none="Игнорировать вход"
|
||||
AdvSceneSwitcher.logic.and="И"
|
||||
AdvSceneSwitcher.logic.or="Или"
|
||||
AdvSceneSwitcher.logic.andNot="И не"
|
||||
@@ -86,8 +84,6 @@ AdvSceneSwitcher.condition.scene.type.current="Текущий"
|
||||
AdvSceneSwitcher.condition.scene.type.previous="Предыдущий"
|
||||
AdvSceneSwitcher.condition.window="Окно"
|
||||
AdvSceneSwitcher.condition.file="Файл"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.media="Медиа"
|
||||
AdvSceneSwitcher.condition.video="Видео"
|
||||
AdvSceneSwitcher.condition.video.condition.match="точно соответствует"
|
||||
@@ -106,7 +102,7 @@ AdvSceneSwitcher.condition.record.state.start="Запись запущена"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Запись приостановлена"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Запись остановлена"
|
||||
AdvSceneSwitcher.condition.process="Процесс"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}запущен{{focused}}и сфокусирован"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}запущен{{focused}}и сфокусирован"
|
||||
AdvSceneSwitcher.condition.idle="Простой"
|
||||
AdvSceneSwitcher.condition.idle.entry="Не было ни клавиатуры, ни мыши в течении{{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Состояние плагина"
|
||||
@@ -115,12 +111,11 @@ 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="случайный"
|
||||
AdvSceneSwitcher.action.wait.entry.fixed="Ожидать {{waitType}} в течении {{duration}}"
|
||||
AdvSceneSwitcher.action.wait.entry.random="Ожидание {{waitType}} длительностью от {{duration}} до {{duration2}}"
|
||||
AdvSceneSwitcher.action.wait.layout.fixed="Ожидать {{waitType}} в течении {{duration}}"
|
||||
AdvSceneSwitcher.action.wait.layout.random="Ожидание {{waitType}} длительностью от {{duration}} до {{duration2}}"
|
||||
AdvSceneSwitcher.action.audio="Аудио"
|
||||
AdvSceneSwitcher.action.audio.type.mute="Замьютить"
|
||||
AdvSceneSwitcher.action.audio.type.unmute="Размьютить"
|
||||
@@ -132,7 +127,6 @@ AdvSceneSwitcher.action.recording.type.start="Начать запись"
|
||||
AdvSceneSwitcher.action.recording.type.pause="Пауза записи"
|
||||
AdvSceneSwitcher.action.recording.type.unpause="Снять запись с паузы"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Обратите внимание, что в зависимости от настроек записи вы можете не иметь возможности приостановить запись"
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Буфер воспроизведения"
|
||||
AdvSceneSwitcher.action.replay.type.stop="Остановить буфер воспроизведения"
|
||||
AdvSceneSwitcher.action.replay.type.start="Начать воспроизведение буфера"
|
||||
@@ -140,7 +134,6 @@ AdvSceneSwitcher.action.replay.type.save="Сохранить буфер восп
|
||||
AdvSceneSwitcher.action.streaming="Потоковое вещание"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="Остановить потоковое вещание"
|
||||
AdvSceneSwitcher.action.streaming.type.start="Начать потоковое вещание"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Запустить"
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Her zaman sahne deği
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Sahne değiştiriciyi başlatma"
|
||||
AdvSceneSwitcher.generalTab.status.start="Başlat"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Durdur"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="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,14 +72,12 @@ AdvSceneSwitcher.macroTab.add="Yeni Makro ekle"
|
||||
AdvSceneSwitcher.macroTab.name="İsim:"
|
||||
AdvSceneSwitcher.macroTab.run="Makro Çalıştırma"
|
||||
AdvSceneSwitcher.macroTab.runInParallel="Makroyu diğer makrolara paralel olarak çalıştırın"
|
||||
AdvSceneSwitcher.macroTab.onChange="Eylemleri yalnızca koşul değişikliğinde gerçekleştirin"
|
||||
AdvSceneSwitcher.macroTab.defaultname="Makro %1"
|
||||
AdvSceneSwitcher.macroTab.copy="Kopya oluştur"
|
||||
AdvSceneSwitcher.macroTab.expandAll="Hepsini Genişlet"
|
||||
AdvSceneSwitcher.macroTab.collapseAll="Hepsini Küçült"
|
||||
|
||||
; Macro Logic
|
||||
AdvSceneSwitcher.logic.none="Girişi yoksay"
|
||||
AdvSceneSwitcher.logic.and="Ve"
|
||||
AdvSceneSwitcher.logic.or="Ya da"
|
||||
AdvSceneSwitcher.logic.andNot="ve değil"
|
||||
@@ -109,9 +106,7 @@ AdvSceneSwitcher.condition.scene.type.notChanged="Sahne değişmedi"
|
||||
AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="Geçiş hedefi sahnesi için geçiş kontrolü sırasında"
|
||||
AdvSceneSwitcher.condition.window="Pencere"
|
||||
AdvSceneSwitcher.condition.file="Dosya"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="İçerik{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||
AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFileContent}}"
|
||||
AdvSceneSwitcher.condition.file.layout="İçerik{{filePath}}{{conditions}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.media="Medya"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Herhangi bir medya kaynağı"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="Tüm medya kaynakları "
|
||||
@@ -140,10 +135,10 @@ 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"
|
||||
@@ -154,7 +149,7 @@ AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Kayıt durdu"
|
||||
AdvSceneSwitcher.condition.process="İşlem"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}çalışıyor{{focused}}ve odaklandı"
|
||||
AdvSceneSwitcher.condition.process.layout="{{processes}}{{regex}}çalışıyor{{focused}}ve odaklandı"
|
||||
AdvSceneSwitcher.condition.idle="Boşta"
|
||||
AdvSceneSwitcher.condition.idle.entry="...için klavye veya fare girişi yok {{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Eklenti durumu"
|
||||
@@ -250,13 +245,12 @@ 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"
|
||||
AdvSceneSwitcher.action.wait.type.random="rastgele"
|
||||
AdvSceneSwitcher.action.wait.entry.fixed="Şunu bekle {{waitType}} süre {{duration}}"
|
||||
AdvSceneSwitcher.action.wait.entry.random="Şunu bekle {{waitType}} bu aralıktan {{duration}} buna {{duration2}}"
|
||||
AdvSceneSwitcher.action.wait.layout.fixed="Şunu bekle {{waitType}} süre {{duration}}"
|
||||
AdvSceneSwitcher.action.wait.layout.random="Şunu bekle {{waitType}} bu aralıktan {{duration}} buna {{duration2}}"
|
||||
AdvSceneSwitcher.action.audio="Ses"
|
||||
AdvSceneSwitcher.action.audio.type.mute="Sessiz"
|
||||
AdvSceneSwitcher.action.audio.type.unmute="Ses açmak"
|
||||
@@ -268,7 +262,6 @@ AdvSceneSwitcher.action.recording.type.start="Kayıt Başlat"
|
||||
AdvSceneSwitcher.action.recording.type.pause="Kayıt Duraklat"
|
||||
AdvSceneSwitcher.action.recording.type.unpause="Kayıt Duraklatma"
|
||||
AdvSceneSwitcher.action.recording.pause.hint="Kayıt ayarlarınıza bağlı olarak kaydı duraklatamayabileceğinizi unutmayın."
|
||||
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
|
||||
AdvSceneSwitcher.action.replay="Tekrar arabelleği"
|
||||
AdvSceneSwitcher.action.replay.type.stop="Tekrar arabelleğini durdur"
|
||||
AdvSceneSwitcher.action.replay.type.start="Tekrar arabelleğini başlat"
|
||||
@@ -276,14 +269,13 @@ AdvSceneSwitcher.action.replay.type.save="Tekrar arabelleğini kaydet"
|
||||
AdvSceneSwitcher.action.streaming="Yayın"
|
||||
AdvSceneSwitcher.action.streaming.type.stop="Yayın durdur"
|
||||
AdvSceneSwitcher.action.streaming.type.start="Yayın başlat"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Çalıştır"
|
||||
AdvSceneSwitcher.action.sceneVisibility="Sahne öğesi görünürlüğü"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Göster"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Gizle"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Kayıt"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Herhangi"
|
||||
AdvSceneSwitcher.action.sceneVisibility.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"
|
||||
@@ -307,13 +299,13 @@ AdvSceneSwitcher.action.macro="Makro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Duraklat"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Duraklatma"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Sayacı sıfırla"
|
||||
AdvSceneSwitcher.action.macro.type.run="Çalıştır"
|
||||
AdvSceneSwitcher.action.macro.type.runActions="Çalıştır"
|
||||
AdvSceneSwitcher.action.pluginState="Eklenti durumu"
|
||||
AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisini durdurun"
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="Ayarları şuradan içe aktar:"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Not: Ayarlar penceresi açılırken eylem göz ardı edilecektir."
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{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"
|
||||
@@ -344,8 +336,8 @@ AdvSceneSwitcher.action.file.type.write="Yaz"
|
||||
AdvSceneSwitcher.action.file.type.append="Ekle"
|
||||
AdvSceneSwitcher.action.file.entry="{{actions}} {{filePath}}:"
|
||||
AdvSceneSwitcher.action.transition="Geçiş"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Geçiş türünü ayarla {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Geçiş süresini şuna ayarla: {{duration}}saniyeler"
|
||||
AdvSceneSwitcher.action.transition.layout.transition="{{setTransition}}Geçiş türünü ayarla {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.layout.duration="{{setDuration}}Geçiş süresini şuna ayarla: {{duration}}saniyeler"
|
||||
AdvSceneSwitcher.action.timer="Zamanlayıcı"
|
||||
AdvSceneSwitcher.action.timer.type.pause="Duraklat"
|
||||
AdvSceneSwitcher.action.timer.type.continue="Devam et"
|
||||
@@ -589,8 +581,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
10
data/res/images/DarkVariable.svg
Normal file
10
data/res/images/DarkVariable.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#fefefe" xmlns="http://www.w3.org/2000/svg"
|
||||
width="800px" height="800px" viewBox="0 0 52 52" enable-background="new 0 0 52 52" xml:space="preserve">
|
||||
<path d="M42.6,17.8c2.4,0,7.2-2,7.2-8.4c0-6.4-4.6-6.8-6.1-6.8c-2.8,0-5.6,2-8.1,6.3c-2.5,4.4-5.3,9.1-5.3,9.1
|
||||
l-0.1,0c-0.6-3.1-1.1-5.6-1.3-6.7c-0.5-2.7-3.6-8.4-9.9-8.4c-6.4,0-12.2,3.7-12.2,3.7l0,0C5.8,7.3,5.1,8.5,5.1,9.9
|
||||
c0,2.1,1.7,3.9,3.9,3.9c0.6,0,1.2-0.2,1.7-0.4l0,0c0,0,4.8-2.7,5.9,0c0.3,0.8,0.6,1.7,0.9,2.7c1.2,4.2,2.4,9.1,3.3,13.5l-4.2,6
|
||||
c0,0-4.7-1.7-7.1-1.7s-7.2,2-7.2,8.4s4.6,6.8,6.1,6.8c2.8,0,5.6-2,8.1-6.3c2.5-4.4,5.3-9.1,5.3-9.1c0.8,4,1.5,7.1,1.9,8.5
|
||||
c1.6,4.5,5.3,7.2,10.1,7.2c0,0,5,0,10.9-3.3c1.4-0.6,2.4-2,2.4-3.6c0-2.1-1.7-3.9-3.9-3.9c-0.6,0-1.2,0.2-1.7,0.4l0,0
|
||||
c0,0-4.2,2.4-5.6,0.5c-1-2-1.9-4.6-2.6-7.8c-0.6-2.8-1.3-6.2-2-9.5l4.3-6.2C35.5,16.1,40.2,17.8,42.6,17.8z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 973 B |
10
data/res/images/LightVariable.svg
Normal file
10
data/res/images/LightVariable.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||
<svg fill="#202020" xmlns="http://www.w3.org/2000/svg"
|
||||
width="800px" height="800px" viewBox="0 0 52 52" enable-background="new 0 0 52 52" xml:space="preserve">
|
||||
<path d="M42.6,17.8c2.4,0,7.2-2,7.2-8.4c0-6.4-4.6-6.8-6.1-6.8c-2.8,0-5.6,2-8.1,6.3c-2.5,4.4-5.3,9.1-5.3,9.1
|
||||
l-0.1,0c-0.6-3.1-1.1-5.6-1.3-6.7c-0.5-2.7-3.6-8.4-9.9-8.4c-6.4,0-12.2,3.7-12.2,3.7l0,0C5.8,7.3,5.1,8.5,5.1,9.9
|
||||
c0,2.1,1.7,3.9,3.9,3.9c0.6,0,1.2-0.2,1.7-0.4l0,0c0,0,4.8-2.7,5.9,0c0.3,0.8,0.6,1.7,0.9,2.7c1.2,4.2,2.4,9.1,3.3,13.5l-4.2,6
|
||||
c0,0-4.7-1.7-7.1-1.7s-7.2,2-7.2,8.4s4.6,6.8,6.1,6.8c2.8,0,5.6-2,8.1-6.3c2.5-4.4,5.3-9.1,5.3-9.1c0.8,4,1.5,7.1,1.9,8.5
|
||||
c1.6,4.5,5.3,7.2,10.1,7.2c0,0,5,0,10.9-3.3c1.4-0.6,2.4-2,2.4-3.6c0-2.1-1.7-3.9-3.9-3.9c-0.6,0-1.2,0.2-1.7,0.4l0,0
|
||||
c0,0-4.2,2.4-5.6,0.5c-1-2-1.9-4.6-2.6-7.8c-0.6-2.8-1.3-6.2-2-9.5l4.3-6.2C35.5,16.1,40.2,17.8,42.6,17.8z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 973 B |
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 |
BIN
data/res/speech/ggml-tiny-q8_0.bin
Normal file
BIN
data/res/speech/ggml-tiny-q8_0.bin
Normal file
Binary file not shown.
2
deps/cpp-httplib
vendored
2
deps/cpp-httplib
vendored
Submodule deps/cpp-httplib updated: c7ed1796a7...008e107d0f
1
deps/date
vendored
1
deps/date
vendored
Submodule deps/date deleted from 5bdb7e6f31
2
deps/json
vendored
2
deps/json
vendored
Submodule deps/json updated: bc889afb4c...55f93686c0
1
deps/jsoncons
vendored
Submodule
1
deps/jsoncons
vendored
Submodule
Submodule deps/jsoncons added at 64b9da1e9f
2
deps/leptonica
vendored
2
deps/leptonica
vendored
Submodule deps/leptonica updated: b667978e86...13275a278e
2
deps/libusb
vendored
2
deps/libusb
vendored
Submodule deps/libusb updated: d52e355daa...bc368fb133
2
deps/opencv
vendored
2
deps/opencv
vendored
Submodule deps/opencv updated: 71d3237a09...40738fb16c
1
deps/opencv_contrib
vendored
Submodule
1
deps/opencv_contrib
vendored
Submodule
Submodule deps/opencv_contrib added at 755e50675d
1
deps/paho.mqtt.cpp
vendored
Submodule
1
deps/paho.mqtt.cpp
vendored
Submodule
Submodule deps/paho.mqtt.cpp added at 165476b1dc
1
deps/whisper.cpp
vendored
Submodule
1
deps/whisper.cpp
vendored
Submodule
Submodule deps/whisper.cpp added at 306c88f4d1
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,5 +1,6 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "backup.hpp"
|
||||
#include "crash-handler.hpp"
|
||||
#include "log-helper.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
@@ -18,8 +19,10 @@
|
||||
#include <obs-frontend-api.h>
|
||||
#include <QAction>
|
||||
#include <QDirIterator>
|
||||
#include <QInputDialog>
|
||||
#include <QLibrary>
|
||||
#include <QMainWindow>
|
||||
#include <QMessageBox>
|
||||
#include <QTextStream>
|
||||
#include <regex>
|
||||
|
||||
@@ -40,9 +43,12 @@ AdvSceneSwitcher::AdvSceneSwitcher(QWidget *parent)
|
||||
{
|
||||
switcher->settingsWindowOpened = true;
|
||||
ui->setupUi(this);
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->Prune();
|
||||
LoadUI();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->Prune();
|
||||
LoadUI();
|
||||
}
|
||||
CheckFirstTimeSetup();
|
||||
}
|
||||
|
||||
AdvSceneSwitcher::~AdvSceneSwitcher()
|
||||
@@ -138,7 +144,6 @@ void AdvSceneSwitcher::LoadUI()
|
||||
SetTabOrder(ui->tabWidget);
|
||||
SetCurrentTab(ui->tabWidget);
|
||||
RestoreWindowGeo();
|
||||
CheckFirstTimeSetup();
|
||||
|
||||
loading = false;
|
||||
}
|
||||
@@ -146,16 +151,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();
|
||||
|
||||
@@ -200,25 +196,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,8 +326,7 @@ void SwitcherData::SetPreconditions()
|
||||
{
|
||||
// Window title
|
||||
lastTitle = currentTitle;
|
||||
std::string title;
|
||||
GetCurrentWindowTitle(title);
|
||||
auto title = GetCurrentWindowTitle();
|
||||
for (auto &window : ignoreWindowsSwitches) {
|
||||
bool equals = (title == window);
|
||||
bool matches = false;
|
||||
@@ -355,7 +346,7 @@ void SwitcherData::SetPreconditions()
|
||||
currentTitle = title;
|
||||
|
||||
// Process name
|
||||
GetForegroundProcessName(currentForegroundProcess);
|
||||
currentForegroundProcess = GetForegroundProcessName();
|
||||
|
||||
// Macro
|
||||
InvalidateMacroTempVarValues();
|
||||
@@ -430,7 +421,7 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
|
||||
|
||||
static void ResetMacros()
|
||||
{
|
||||
for (auto &m : GetMacros()) {
|
||||
for (auto &m : GetTopLevelMacros()) {
|
||||
ResetMacroRunCount(m.get());
|
||||
ResetMacroConditionTimers(m.get());
|
||||
}
|
||||
@@ -470,12 +461,13 @@ void SwitcherData::Stop()
|
||||
SetMacroAbortWait(true);
|
||||
GetMacroWaitCV().notify_all();
|
||||
GetMacroTransitionCV().notify_all();
|
||||
StopAllMacros();
|
||||
SignalStopAllMacros();
|
||||
StopAndClearAllActionQueues();
|
||||
CloseAllInputDialogs();
|
||||
th->wait();
|
||||
delete th;
|
||||
th = nullptr;
|
||||
WaitForAllMacros();
|
||||
RunStopSteps();
|
||||
}
|
||||
|
||||
@@ -519,6 +511,8 @@ bool SwitcherData::AnySceneTransitionStarted()
|
||||
******************************************************************************/
|
||||
extern "C" EXPORT void FreeSceneSwitcher()
|
||||
{
|
||||
switcher->Stop();
|
||||
|
||||
PlatformCleanup();
|
||||
RunPluginCleanupSteps();
|
||||
|
||||
@@ -547,6 +541,7 @@ static void handleSceneChange()
|
||||
}
|
||||
|
||||
switcher->checkDefaultSceneTransitions();
|
||||
switcher->CheckAutoStart();
|
||||
}
|
||||
|
||||
static void setLiveTime()
|
||||
@@ -561,18 +556,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()
|
||||
@@ -608,7 +613,7 @@ static void handleSceneCollectionChanging()
|
||||
AdvSceneSwitcher::window->close();
|
||||
}
|
||||
if (!switcher->stop) {
|
||||
switcher->sceneColletionStop = true;
|
||||
switcher->sceneCollectionStop = true;
|
||||
switcher->Stop();
|
||||
}
|
||||
}
|
||||
@@ -629,13 +634,20 @@ static void handleSceneCollectionCleanup()
|
||||
return;
|
||||
}
|
||||
|
||||
// OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP is also called on
|
||||
// shutdown.
|
||||
// Here we also don't want to clear the settings.
|
||||
if (switcher->obsIsShuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
SaveSceneSwitcher(nullptr, false, nullptr);
|
||||
}
|
||||
|
||||
// Note to future self:
|
||||
// be careful using switcher->m here as there is potential for deadlocks when using
|
||||
// frontend functions such as obs_frontend_set_current_scene()
|
||||
static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
||||
static void OBSEvent(enum obs_frontend_event event, void *)
|
||||
{
|
||||
if (!switcher) {
|
||||
return;
|
||||
@@ -709,19 +721,54 @@ static void LoadPlugins()
|
||||
}
|
||||
}
|
||||
|
||||
static bool settingsPasswordIsCorrect(QWidget *parent)
|
||||
{
|
||||
bool ok;
|
||||
QString input = QInputDialog::getText(
|
||||
parent,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.passwordLabel"),
|
||||
QLineEdit::Password, QString(), &ok);
|
||||
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input.toStdString() == switcher->settingsLockPassword) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QMessageBox::warning(
|
||||
parent,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.wrongPassword"));
|
||||
return false;
|
||||
}
|
||||
|
||||
void OpenSettingsWindow()
|
||||
{
|
||||
if (switcher->settingsWindowOpened) {
|
||||
AdvSceneSwitcher::window->show();
|
||||
AdvSceneSwitcher::window->raise();
|
||||
AdvSceneSwitcher::window->activateWindow();
|
||||
} else {
|
||||
AdvSceneSwitcher::window =
|
||||
new AdvSceneSwitcher(static_cast<QMainWindow *>(
|
||||
obs_frontend_get_main_window()));
|
||||
AdvSceneSwitcher::window->setAttribute(Qt::WA_DeleteOnClose);
|
||||
AdvSceneSwitcher::window->show();
|
||||
return;
|
||||
}
|
||||
|
||||
auto parent =
|
||||
static_cast<QMainWindow *>(obs_frontend_get_main_window());
|
||||
if (switcher->settingsLockEnabled &&
|
||||
!switcher->settingsLockPassword.empty() &&
|
||||
!settingsPasswordIsCorrect(parent)) {
|
||||
return;
|
||||
}
|
||||
|
||||
AdvSceneSwitcher::window = new AdvSceneSwitcher(parent);
|
||||
AdvSceneSwitcher::window->setAttribute(Qt::WA_DeleteOnClose);
|
||||
AdvSceneSwitcher::window->show();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightMacroSettingsButton(bool enable)
|
||||
@@ -744,6 +791,21 @@ void AdvSceneSwitcher::HighlightMacroSettingsButton(bool enable)
|
||||
highlight = HighlightWidget(ui->macroSettings, Qt::green);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightAction(int idx, QColor color) const
|
||||
{
|
||||
ui->macroEdit->HighlightAction(idx, color);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightElseAction(int idx, QColor color) const
|
||||
{
|
||||
ui->macroEdit->HighlightElseAction(idx, color);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightCondition(int idx, QColor color) const
|
||||
{
|
||||
ui->macroEdit->HighlightCondition(idx, color);
|
||||
}
|
||||
|
||||
void HighlightMacroSettingsButton(bool enable)
|
||||
{
|
||||
auto window = GetSettingsWindow();
|
||||
@@ -754,8 +816,6 @@ void HighlightMacroSettingsButton(bool enable)
|
||||
enable);
|
||||
}
|
||||
|
||||
void SetupActionQueues();
|
||||
|
||||
extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module,
|
||||
translateFunc translate)
|
||||
{
|
||||
@@ -767,12 +827,11 @@ extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module,
|
||||
PlatformInit();
|
||||
LoadPlugins();
|
||||
SetupDock();
|
||||
SetupActionQueues();
|
||||
|
||||
RunPluginInitSteps();
|
||||
|
||||
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
|
||||
obs_frontend_add_event_callback(OBSEvent, switcher);
|
||||
obs_frontend_add_event_callback(OBSEvent, nullptr);
|
||||
|
||||
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
|
||||
obs_module_text("AdvSceneSwitcher.pluginName"));
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
#pragma once
|
||||
#include "macro-segment-list.hpp"
|
||||
#include "condition-logic.hpp"
|
||||
#include "log-helper.hpp"
|
||||
|
||||
#include <ui_advanced-scene-switcher.h>
|
||||
|
||||
@@ -11,6 +8,7 @@ namespace advss {
|
||||
|
||||
class MacroActionEdit;
|
||||
class MacroConditionEdit;
|
||||
class MacroSegment;
|
||||
class Duration;
|
||||
class SequenceWidget;
|
||||
struct SceneGroup;
|
||||
@@ -44,7 +42,6 @@ protected:
|
||||
/* --- Begin of general tab section --- */
|
||||
public:
|
||||
void SetupGeneralTab();
|
||||
void UpdateNonMatchingScene(const QString &name);
|
||||
void SetDeprecationWarnings();
|
||||
|
||||
public slots:
|
||||
@@ -57,7 +54,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();
|
||||
@@ -67,34 +63,39 @@ public slots:
|
||||
void on_uiHintsDisable_stateChanged(int state);
|
||||
void on_disableComboBoxFilter_stateChanged(int state);
|
||||
void on_warnPluginLoadFailure_stateChanged(int state);
|
||||
void on_suppressCrashRecoveryDialog_stateChanged(int state);
|
||||
void on_hideLegacyTabs_stateChanged(int state);
|
||||
void on_settingsLock_stateChanged(int state);
|
||||
void on_priorityUp_clicked();
|
||||
void on_priorityDown_clicked();
|
||||
void on_threadPriority_currentTextChanged(const QString &text);
|
||||
void on_openSetupWizard_clicked();
|
||||
|
||||
/* --- End of legacy tab section --- */
|
||||
|
||||
/* --- Begin of macro tab section --- */
|
||||
public:
|
||||
void SetupMacroTab();
|
||||
bool MacroTabIsInFocus();
|
||||
bool AddNewMacro(std::shared_ptr<Macro> &res, std::string &name,
|
||||
std::string format = "");
|
||||
void RemoveMacro(std::shared_ptr<Macro> &);
|
||||
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 HighlightMacroSettingsButton(bool enable = true);
|
||||
@@ -102,111 +103,24 @@ public:
|
||||
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 PauseSelectedMacros();
|
||||
void UnpauseSelectedMacros();
|
||||
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 --- */
|
||||
|
||||
|
||||
372
lib/general.cpp
372
lib/general.cpp
@@ -1,22 +1,28 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "crash-handler.hpp"
|
||||
#include "file-selection.hpp"
|
||||
#include "filter-combo-box.hpp"
|
||||
#include "first-run-wizard.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-search.hpp"
|
||||
#include "macro-settings.hpp"
|
||||
#include "macro.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"
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -25,15 +31,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 +52,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 +109,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 +127,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 +148,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();
|
||||
}
|
||||
@@ -214,6 +199,15 @@ void AdvSceneSwitcher::on_warnPluginLoadFailure_stateChanged(int state)
|
||||
switcher->warnPluginLoadFailure = state;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_suppressCrashRecoveryDialog_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetSuppressCrashDialog(state);
|
||||
}
|
||||
|
||||
static bool isLegacyTab(const QString &name)
|
||||
{
|
||||
return name == obs_module_text(
|
||||
@@ -253,6 +247,64 @@ void AdvSceneSwitcher::on_hideLegacyTabs_stateChanged(int state)
|
||||
ui->priorityBox->setVisible(!switcher->hideLegacyTabs);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_settingsLock_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state) {
|
||||
switcher->settingsLockEnabled = false;
|
||||
switcher->settingsLockPassword = "";
|
||||
return;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
QString newPassword = QInputDialog::getText(
|
||||
this,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.newPasswordLabel"),
|
||||
QLineEdit::Password, QString(), &ok);
|
||||
|
||||
const auto disablePassword = [this]() {
|
||||
QSignalBlocker blocker(ui->settingsLock);
|
||||
ui->settingsLock->setChecked(false);
|
||||
ui->settingsLock->setCheckState(Qt::Unchecked);
|
||||
switcher->settingsLockEnabled = false;
|
||||
switcher->settingsLockPassword = "";
|
||||
};
|
||||
|
||||
if (!ok || newPassword.isEmpty()) {
|
||||
disablePassword();
|
||||
return;
|
||||
}
|
||||
|
||||
QString confirm = QInputDialog::getText(
|
||||
this,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.confirmPasswordLabel"),
|
||||
QLineEdit::Password, QString(), &ok);
|
||||
if (!ok || newPassword != confirm) {
|
||||
if (ok) {
|
||||
QMessageBox::warning(
|
||||
this,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.title"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.settingsLock.passwordMismatch"));
|
||||
}
|
||||
disablePassword();
|
||||
return;
|
||||
}
|
||||
|
||||
switcher->settingsLockEnabled = true;
|
||||
switcher->settingsLockPassword = newPassword.toStdString();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetDeprecationWarnings()
|
||||
{
|
||||
QString toolTip =
|
||||
@@ -275,12 +327,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()
|
||||
@@ -377,13 +432,50 @@ 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;
|
||||
}
|
||||
|
||||
bool wasSkipped = false;
|
||||
auto macro = wiz::FirstRunWizard::ShowWizard(this, &wasSkipped);
|
||||
if (macro) {
|
||||
renameMacroIfNecessary(macro);
|
||||
QTimer::singleShot(0, this,
|
||||
[this, macro]() { ui->macros->Add(macro); });
|
||||
}
|
||||
if (wasSkipped) {
|
||||
ui->alwaysShowFeatureTabs->setChecked(true);
|
||||
}
|
||||
switcher->Start();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_openSetupWizard_clicked()
|
||||
{
|
||||
auto macro = wiz::FirstRunWizard::ShowWizard(this);
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
renameMacroIfNecessary(macro);
|
||||
ui->macros->Add(macro);
|
||||
ui->tabWidget->setCurrentWidget(ui->macroTab);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_tabWidget_currentChanged(int)
|
||||
@@ -437,16 +529,13 @@ 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);
|
||||
@@ -467,7 +556,7 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
||||
LoadHotkeys(obj);
|
||||
LoadUISettings(obj);
|
||||
|
||||
RunPostLoadSteps();
|
||||
RunAndClearPostLoadSteps();
|
||||
|
||||
// Reset on startup and scene collection change
|
||||
ResetLastOpenedTab();
|
||||
@@ -483,7 +572,6 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
|
||||
saveSceneGroups(obj);
|
||||
SaveMacros(obj);
|
||||
SaveGlobalMacroSettings(obj);
|
||||
SaveVariables(obj);
|
||||
saveWindowTitleSwitches(obj);
|
||||
saveScreenRegionSwitches(obj);
|
||||
savePauseSwitches(obj);
|
||||
@@ -502,18 +590,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");
|
||||
@@ -521,16 +607,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);
|
||||
@@ -538,6 +629,9 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
|
||||
disableFilterComboboxFilter);
|
||||
obs_data_set_bool(obj, "warnPluginLoadFailure", warnPluginLoadFailure);
|
||||
obs_data_set_bool(obj, "hideLegacyTabs", hideLegacyTabs);
|
||||
obs_data_set_bool(obj, "settingsLockEnabled", settingsLockEnabled);
|
||||
obs_data_set_string(obj, "settingsLockPassword",
|
||||
settingsLockPassword.c_str());
|
||||
|
||||
SaveFunctionPriorities(obj, functionNamesByPriority);
|
||||
|
||||
@@ -560,9 +654,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");
|
||||
@@ -583,28 +682,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");
|
||||
@@ -615,6 +703,8 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
||||
warnPluginLoadFailure = obs_data_get_bool(obj, "warnPluginLoadFailure");
|
||||
obs_data_set_default_bool(obj, "hideLegacyTabs", true);
|
||||
hideLegacyTabs = obs_data_get_bool(obj, "hideLegacyTabs");
|
||||
settingsLockEnabled = obs_data_get_bool(obj, "settingsLockEnabled");
|
||||
settingsLockPassword = obs_data_get_string(obj, "settingsLockPassword");
|
||||
|
||||
SetDefaultFunctionPriorities(obj);
|
||||
LoadFunctionPriorities(obj, functionNamesByPriority);
|
||||
@@ -680,10 +770,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) {
|
||||
@@ -691,6 +781,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) {
|
||||
@@ -833,7 +944,7 @@ static void setupGeneralTabInactiveWarning(QTabWidget *tabs)
|
||||
inactiveTimer->start();
|
||||
}
|
||||
|
||||
void advss::AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
|
||||
void AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
|
||||
{
|
||||
auto macro = GetMacroWithInvalidConditionInterval();
|
||||
if (!macro) {
|
||||
@@ -857,8 +968,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);
|
||||
@@ -870,8 +979,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);
|
||||
@@ -894,7 +1012,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(
|
||||
@@ -905,7 +1025,9 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
||||
FilterComboBox::SetFilterBehaviourEnabled(
|
||||
!switcher->disableFilterComboboxFilter);
|
||||
ui->warnPluginLoadFailure->setChecked(switcher->warnPluginLoadFailure);
|
||||
ui->suppressCrashRecoveryDialog->setChecked(GetSuppressCrashDialog());
|
||||
ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs);
|
||||
ui->settingsLock->setChecked(switcher->settingsLockEnabled);
|
||||
|
||||
populatePriorityFunctionList(ui->priorityList);
|
||||
populateThreadPriorityList(ui->threadPriority);
|
||||
@@ -917,6 +1039,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);
|
||||
@@ -937,6 +1141,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
|
||||
|
||||
@@ -92,12 +92,11 @@ bool SwitcherData::checkExeSwitch(OBSWeakSource &scene,
|
||||
}
|
||||
|
||||
std::string title = switcher->currentTitle;
|
||||
QStringList runningProcesses;
|
||||
bool ignored = false;
|
||||
bool match = false;
|
||||
|
||||
// Check for match
|
||||
GetProcessList(runningProcesses);
|
||||
const auto runningProcesses = GetProcessList();
|
||||
for (ExecutableSwitch &s : executableSwitches) {
|
||||
if (!s.initialized()) {
|
||||
continue;
|
||||
|
||||
@@ -178,47 +178,19 @@ void AdvSceneSwitcher::on_ignoreWindows_currentRowChanged(int idx)
|
||||
}
|
||||
}
|
||||
|
||||
void checkWindowTitleSwitchDirect(WindowSwitch &s,
|
||||
std::string ¤tWindowTitle, bool &match,
|
||||
OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
static bool windowInfoMatchesSwitch(const WindowInfo &info,
|
||||
const WindowSwitch &s)
|
||||
{
|
||||
bool focus = (!s.focus || s.window == currentWindowTitle);
|
||||
bool fullscreen = (!s.fullscreen || IsFullscreen(s.window));
|
||||
bool max = (!s.maximized || IsMaximized(s.window));
|
||||
|
||||
if (focus && fullscreen && max) {
|
||||
match = true;
|
||||
scene = s.getScene();
|
||||
transition = s.transition;
|
||||
if (s.focus && !info.focused) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void checkWindowTitleSwitchRegex(WindowSwitch &s,
|
||||
std::string ¤tWindowTitle,
|
||||
std::vector<std::string> windowList,
|
||||
bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
for (auto &window : windowList) {
|
||||
try {
|
||||
std::regex expr(s.window);
|
||||
if (!std::regex_match(window, expr)) {
|
||||
continue;
|
||||
}
|
||||
} catch (const std::regex_error &) {
|
||||
}
|
||||
|
||||
bool focus = (!s.focus || window == currentWindowTitle);
|
||||
bool fullscreen = (!s.fullscreen || IsFullscreen(window));
|
||||
bool max = (!s.maximized || IsMaximized(window));
|
||||
|
||||
if (focus && fullscreen && max) {
|
||||
match = true;
|
||||
scene = s.getScene();
|
||||
transition = s.transition;
|
||||
}
|
||||
if (s.fullscreen && !info.fullscreen) {
|
||||
return false;
|
||||
}
|
||||
if (s.maximized && !info.maximized) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SwitcherData::checkWindowTitleSwitch(OBSWeakSource &scene,
|
||||
@@ -228,24 +200,37 @@ bool SwitcherData::checkWindowTitleSwitch(OBSWeakSource &scene,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string currentWindowTitle = switcher->currentTitle;
|
||||
bool match = false;
|
||||
std::vector<std::string> windowList;
|
||||
GetWindowList(windowList);
|
||||
|
||||
WindowQueryOptions options;
|
||||
options.focus = true;
|
||||
options.fullscreen = true;
|
||||
options.maximized = true;
|
||||
const auto windows = GetWindows(options);
|
||||
|
||||
for (WindowSwitch &s : windowSwitches) {
|
||||
if (!s.initialized()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std::find(windowList.begin(), windowList.end(), s.window) !=
|
||||
windowList.end()) {
|
||||
checkWindowTitleSwitchDirect(s, currentWindowTitle,
|
||||
match, scene, transition);
|
||||
} else {
|
||||
checkWindowTitleSwitchRegex(s, currentWindowTitle,
|
||||
windowList, match, scene,
|
||||
transition);
|
||||
for (const auto &info : windows) {
|
||||
bool titleMatch = false;
|
||||
try {
|
||||
std::regex expr(s.window);
|
||||
titleMatch = info.title == s.window ||
|
||||
std::regex_match(info.title, expr);
|
||||
} catch (const std::regex_error &) {
|
||||
titleMatch = info.title == s.window;
|
||||
}
|
||||
|
||||
if (!titleMatch || !windowInfoMatchesSwitch(info, s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match = true;
|
||||
scene = s.getScene();
|
||||
transition = s.transition;
|
||||
break;
|
||||
}
|
||||
|
||||
if (match) {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
#include "platform-funcs.hpp"
|
||||
|
||||
#include "log-helper.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
@@ -32,6 +36,10 @@
|
||||
#endif
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <climits>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include "kwin-helpers.h"
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -44,6 +52,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);
|
||||
@@ -228,28 +240,89 @@ std::string getWindowName(Window window)
|
||||
return windowTitle;
|
||||
}
|
||||
|
||||
void GetWindowList(std::vector<std::string> &windows)
|
||||
std::vector<WindowInfo> GetWindows(const WindowQueryOptions &options)
|
||||
{
|
||||
windows.resize(0);
|
||||
for (auto window : getTopLevelWindows()) {
|
||||
auto name = getWindowName(window);
|
||||
if (name.empty()) {
|
||||
continue;
|
||||
}
|
||||
windows.emplace_back(name);
|
||||
}
|
||||
}
|
||||
const std::string foregroundTitle = GetCurrentWindowTitle();
|
||||
const auto topLevel = getTopLevelWindows();
|
||||
auto display = disp();
|
||||
|
||||
void GetWindowList(QStringList &windows)
|
||||
{
|
||||
windows.clear();
|
||||
for (auto window : getTopLevelWindows()) {
|
||||
std::vector<WindowInfo> result;
|
||||
result.reserve(topLevel.size());
|
||||
|
||||
for (auto window : topLevel) {
|
||||
auto name = getWindowName(window);
|
||||
if (name.empty()) {
|
||||
continue;
|
||||
}
|
||||
windows << QString::fromStdString(name);
|
||||
|
||||
WindowInfo info;
|
||||
info.title = name;
|
||||
|
||||
if (options.focus) {
|
||||
info.focused = (name == foregroundTitle);
|
||||
}
|
||||
|
||||
if (options.fullscreen || options.maximized) {
|
||||
QStringList states = getStates(window);
|
||||
if (options.fullscreen) {
|
||||
info.fullscreen = states.contains(
|
||||
"_NET_WM_STATE_FULLSCREEN");
|
||||
}
|
||||
if (options.maximized) {
|
||||
info.maximized =
|
||||
states.contains(
|
||||
"_NET_WM_STATE_MAXIMIZED_VERT") &&
|
||||
states.contains(
|
||||
"_NET_WM_STATE_MAXIMIZED_HORZ");
|
||||
}
|
||||
}
|
||||
|
||||
if (options.geometry && display) {
|
||||
XWindowAttributes attrs;
|
||||
if (XGetWindowAttributes(display, window, &attrs)) {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
Window child;
|
||||
XTranslateCoordinates(
|
||||
display, window,
|
||||
DefaultRootWindow(display), 0, 0, &x,
|
||||
&y, &child);
|
||||
info.x = x;
|
||||
info.y = y;
|
||||
info.width = attrs.width;
|
||||
info.height = attrs.height;
|
||||
}
|
||||
}
|
||||
|
||||
// windowClass and text not implemented on Linux
|
||||
result.emplace_back(std::move(info));
|
||||
}
|
||||
|
||||
// When KWin compat is active, native Wayland windows are not tracked by
|
||||
// X11 and therefore do not appear in the list above. Merge in any window
|
||||
// reported by KWin that is not already present (matched by title) so that
|
||||
// title and focus conditions work for native Wayland windows.
|
||||
if (KWin) {
|
||||
for (const auto &[pid, title] :
|
||||
FocusNotifier::getWindowList()) {
|
||||
bool found = false;
|
||||
for (const auto &info : result) {
|
||||
if (info.title == title) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
WindowInfo waylandWindow;
|
||||
waylandWindow.title = title;
|
||||
waylandWindow.focused =
|
||||
(title == foregroundTitle);
|
||||
result.emplace_back(std::move(waylandWindow));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int getActiveWindow(Window *&window)
|
||||
@@ -273,85 +346,24 @@ int getActiveWindow(Window *&window)
|
||||
&bytes, (uint8_t **)&window);
|
||||
}
|
||||
|
||||
void GetCurrentWindowTitle(std::string &title)
|
||||
std::string GetCurrentWindowTitle()
|
||||
{
|
||||
if (KWin) {
|
||||
return FocusNotifier::getActiveWindowTitle();
|
||||
}
|
||||
|
||||
Window *data = 0;
|
||||
if (getActiveWindow(data) != Success || !data) {
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
if (!data[0]) {
|
||||
XFree(data);
|
||||
return;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto name = getWindowName(data[0]);
|
||||
XFree(data);
|
||||
if (name.empty()) {
|
||||
return;
|
||||
}
|
||||
title = name;
|
||||
}
|
||||
|
||||
bool windowStatesAreSet(const std::string &windowTitle,
|
||||
std::vector<QString> &expectedStates)
|
||||
{
|
||||
if (!ewmhIsSupported()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<Window> windows = getTopLevelWindows();
|
||||
for (auto &window : windows) {
|
||||
auto name = getWindowName(window);
|
||||
if (name.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool equals = windowTitle == name;
|
||||
bool matches = QString::fromStdString(name).contains(
|
||||
QRegularExpression(
|
||||
QString::fromStdString(windowTitle)));
|
||||
|
||||
if (!(equals || matches)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QStringList states = getStates(window);
|
||||
if (states.isEmpty()) {
|
||||
if (expectedStates.empty()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &state : expectedStates) {
|
||||
if (!states.contains(state)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsMaximized(const std::string &title)
|
||||
{
|
||||
std::vector<QString> states;
|
||||
states.emplace_back("_NET_WM_STATE_MAXIMIZED_VERT");
|
||||
states.emplace_back("_NET_WM_STATE_MAXIMIZED_HORZ");
|
||||
return windowStatesAreSet(title, states);
|
||||
}
|
||||
|
||||
bool IsFullscreen(const std::string &title)
|
||||
{
|
||||
std::vector<QString> states;
|
||||
states.emplace_back("_NET_WM_STATE_FULLSCREEN");
|
||||
return windowStatesAreSet(title, states);
|
||||
}
|
||||
|
||||
std::optional<std::string> GetTextInWindow(const std::string &)
|
||||
{
|
||||
// Not implemented
|
||||
return {};
|
||||
return name;
|
||||
}
|
||||
|
||||
static void getProcessListProcps(QStringList &processes)
|
||||
@@ -398,20 +410,25 @@ static void getProcessListProcps2(QStringList &processes)
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetProcessList(QStringList &processes)
|
||||
QStringList GetProcessList()
|
||||
{
|
||||
processes.clear();
|
||||
QStringList processes;
|
||||
if (libprocpsSupported) {
|
||||
getProcessListProcps(processes);
|
||||
return;
|
||||
return processes;
|
||||
}
|
||||
if (libprocps2Supported) {
|
||||
getProcessListProcps2(processes);
|
||||
}
|
||||
return processes;
|
||||
}
|
||||
|
||||
long getForegroundProcessPid()
|
||||
{
|
||||
if (KWin) {
|
||||
return FocusNotifier::getActiveWindowPID();
|
||||
}
|
||||
|
||||
Window *window;
|
||||
if (getActiveWindow(window) != Success || !window || !*window) {
|
||||
return -1;
|
||||
@@ -437,6 +454,7 @@ long getForegroundProcessPid()
|
||||
|
||||
pid = *((long *)prop);
|
||||
XFree(prop);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
@@ -453,24 +471,83 @@ std::string getProcNameFromPid(long pid)
|
||||
return name;
|
||||
}
|
||||
|
||||
void GetForegroundProcessName(QString &proc)
|
||||
std::string GetForegroundProcessName()
|
||||
{
|
||||
std::string temp;
|
||||
GetForegroundProcessName(temp);
|
||||
proc = QString::fromStdString(temp);
|
||||
auto pid = getForegroundProcessPid();
|
||||
return getProcNameFromPid(pid);
|
||||
}
|
||||
|
||||
void GetForegroundProcessName(std::string &proc)
|
||||
static std::string getProcessPathFromPid(long pid)
|
||||
{
|
||||
std::string linkPath = "/proc/" + std::to_string(pid) + "/exe";
|
||||
char buf[PATH_MAX];
|
||||
ssize_t len = readlink(linkPath.c_str(), buf, sizeof(buf) - 1);
|
||||
if (len <= 0) {
|
||||
return {};
|
||||
}
|
||||
buf[len] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string GetForegroundProcessPath()
|
||||
{
|
||||
proc.resize(0);
|
||||
auto pid = getForegroundProcessPid();
|
||||
proc = getProcNameFromPid(pid);
|
||||
if (pid <= 0) {
|
||||
return {};
|
||||
}
|
||||
return getProcessPathFromPid(pid);
|
||||
}
|
||||
|
||||
QStringList GetProcessPathsFromName(const QString &name)
|
||||
{
|
||||
QStringList paths;
|
||||
const std::string nameStr = name.toStdString();
|
||||
DIR *procDir = opendir("/proc");
|
||||
if (!procDir) {
|
||||
return paths;
|
||||
}
|
||||
|
||||
struct dirent *entry;
|
||||
while ((entry = readdir(procDir)) != nullptr) {
|
||||
bool isPid = (entry->d_name[0] != '\0');
|
||||
for (const char *c = entry->d_name; *c; c++) {
|
||||
if (!isdigit(*c)) {
|
||||
isPid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isPid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string pid = entry->d_name;
|
||||
std::string commPath = "/proc/" + pid + "/comm";
|
||||
std::ifstream commFile(commPath);
|
||||
if (!commFile) {
|
||||
continue;
|
||||
}
|
||||
std::string comm;
|
||||
std::getline(commFile, comm);
|
||||
if (comm != nameStr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string path = getProcessPathFromPid(std::stol(pid));
|
||||
if (path.empty()) {
|
||||
continue;
|
||||
}
|
||||
QString qPath = QString::fromStdString(path);
|
||||
if (!paths.contains(qPath)) {
|
||||
paths.append(qPath);
|
||||
}
|
||||
}
|
||||
closedir(procDir);
|
||||
return paths;
|
||||
}
|
||||
|
||||
bool IsInFocus(const QString &executable)
|
||||
{
|
||||
std::string current;
|
||||
GetForegroundProcessName(current);
|
||||
const auto current = GetForegroundProcessName();
|
||||
|
||||
// True if executable switch equals current window
|
||||
bool equals = (executable.toStdString() == current);
|
||||
@@ -555,16 +632,39 @@ int ignoreXerror(Display *d, XErrorEvent *e)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handleKWinInitFailure(bool kwinAvailable)
|
||||
{
|
||||
blog(LOG_INFO, "not using KWin compat");
|
||||
const bool onKDE = qEnvironmentVariable("XDG_CURRENT_DESKTOP")
|
||||
.contains("KDE", Qt::CaseInsensitive);
|
||||
const bool inFlatpak = qEnvironmentVariableIsSet("FLATPAK_ID");
|
||||
if (!kwinAvailable && onKDE && inFlatpak)
|
||||
AddFinishedLoadingStep([]() {
|
||||
DisplayTrayMessage(
|
||||
obs_module_text("AdvSceneSwitcher.pluginName"),
|
||||
obs_module_text("AdvSceneSwitcher.kwin.flatpakPermissionWarning"));
|
||||
});
|
||||
}
|
||||
|
||||
void PlatformInit()
|
||||
{
|
||||
const bool kwinAvailable = isKWinAvailable();
|
||||
KWin = kwinAvailable && registerKWinDBusListener(¬ifier) &&
|
||||
startKWinScript(KWinScriptObjectPath);
|
||||
if (KWin)
|
||||
blog(LOG_INFO, "using KWin compat");
|
||||
else
|
||||
handleKWinInitFailure(kwinAvailable);
|
||||
|
||||
initProcps();
|
||||
initProc2();
|
||||
|
||||
auto display = disp();
|
||||
if (!display) {
|
||||
return;
|
||||
}
|
||||
|
||||
initXss();
|
||||
initProcps();
|
||||
initProc2();
|
||||
XSetErrorHandler(ignoreXerror);
|
||||
}
|
||||
|
||||
@@ -583,6 +683,8 @@ void PlatformCleanup()
|
||||
cleanupHelper(libproc2);
|
||||
cleanupDisplay();
|
||||
XSetErrorHandler(NULL);
|
||||
if (KWin && !KWinScriptObjectPath.isEmpty())
|
||||
stopKWinScript(KWinScriptObjectPath);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
224
lib/linux/kwin-helpers.cpp
Normal file
224
lib/linux/kwin-helpers.cpp
Normal file
@@ -0,0 +1,224 @@
|
||||
#include "kwin-helpers.h"
|
||||
|
||||
#include "log-helper.hpp"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileDevice>
|
||||
#include <QStandardPaths>
|
||||
#include <QTextStream>
|
||||
#include <QtDBus/QDBusConnectionInterface>
|
||||
#include <QtDBus/QDBusInterface>
|
||||
#include <QtDBus/QDBusReply>
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::mutex FocusNotifier::_mutex;
|
||||
int FocusNotifier::activePID = -1;
|
||||
std::string FocusNotifier::activeTitle = {};
|
||||
std::map<std::string, std::pair<int, std::string>> FocusNotifier::_windows;
|
||||
|
||||
int FocusNotifier::getActiveWindowPID()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
return activePID;
|
||||
}
|
||||
|
||||
std::string FocusNotifier::getActiveWindowTitle()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
return activeTitle;
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, std::string>> FocusNotifier::getWindowList()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
std::vector<std::pair<int, std::string>> result;
|
||||
result.reserve(_windows.size());
|
||||
for (const auto &entry : _windows) {
|
||||
result.emplace_back(entry.second);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void FocusNotifier::focusChanged(const int pid)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
activePID = pid;
|
||||
}
|
||||
|
||||
void FocusNotifier::focusTitle(const QString &title)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
activeTitle = title.toStdString();
|
||||
}
|
||||
|
||||
void FocusNotifier::focusUpdate(const int pid, const QString &title)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
activePID = pid;
|
||||
activeTitle = title.toStdString();
|
||||
}
|
||||
|
||||
void FocusNotifier::windowAdded(const QString &id, const int pid,
|
||||
const QString &title)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
_windows[id.toStdString()] = {pid, title.toStdString()};
|
||||
}
|
||||
|
||||
void FocusNotifier::windowRemoved(const QString &id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
_windows.erase(id.toStdString());
|
||||
}
|
||||
|
||||
void FocusNotifier::windowTitleChanged(const QString &id, const QString &title)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
auto it = _windows.find(id.toStdString());
|
||||
if (it != _windows.end()) {
|
||||
it->second.second = 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 =
|
||||
QStandardPaths::writableLocation(
|
||||
QStandardPaths::RuntimeLocation) +
|
||||
"/AdvancedSceneSwitcher/KWinFocusNotifier.js";
|
||||
|
||||
const QString script =
|
||||
R"(var adss = "com.obsproject.Studio.Plugin.SceneSwitcher";
|
||||
var adssPath = "/com/obsproject/Studio/Plugin/SceneSwitcher";
|
||||
|
||||
function trackWindow(window) {
|
||||
var id = window.internalId.toString();
|
||||
callDBus(adss, adssPath, adss, "windowAdded", id, window.pid, window.caption);
|
||||
window.captionChanged.connect(function() {
|
||||
callDBus(adss, adssPath, adss, "windowTitleChanged", id, window.caption);
|
||||
});
|
||||
}
|
||||
|
||||
var windows = workspace.windowList();
|
||||
for (var i = 0; i < windows.length; i++) {
|
||||
trackWindow(windows[i]);
|
||||
}
|
||||
|
||||
workspace.windowAdded.connect(trackWindow);
|
||||
|
||||
workspace.windowRemoved.connect(function(window) {
|
||||
callDBus(adss, adssPath, adss, "windowRemoved", window.internalId.toString());
|
||||
});
|
||||
|
||||
workspace.windowActivated.connect(function(client) {
|
||||
callDBus(adss, adssPath, adss, "focusUpdate",
|
||||
client ? client.pid : 0,
|
||||
client ? client.caption : "");
|
||||
}))";
|
||||
|
||||
if (const QDir dir; !dir.mkpath(QFileInfo(scriptPath).absolutePath())) {
|
||||
blog(LOG_ERROR,
|
||||
"error creating KWinFocusNotifier script directory");
|
||||
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.obsproject.Studio.Plugin.SceneSwitcher";
|
||||
static const QString objectPath = "/com/obsproject/Studio/Plugin/SceneSwitcher";
|
||||
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
|
||||
46
lib/linux/kwin-helpers.h
Normal file
46
lib/linux/kwin-helpers.h
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class FocusNotifier final : public QObject {
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "com.obsproject.Studio.Plugin.SceneSwitcher")
|
||||
|
||||
static std::mutex _mutex;
|
||||
static int activePID;
|
||||
static std::string activeTitle;
|
||||
// Maps KWin internal window ID to {pid, title}
|
||||
static std::map<std::string, std::pair<int, std::string>> _windows;
|
||||
|
||||
public:
|
||||
using QObject::QObject;
|
||||
|
||||
static int getActiveWindowPID();
|
||||
static std::string getActiveWindowTitle();
|
||||
static std::vector<std::pair<int, std::string>> getWindowList();
|
||||
|
||||
public slots:
|
||||
void focusChanged(const int pid);
|
||||
void focusTitle(const QString &title);
|
||||
void focusUpdate(const int pid, const QString &title);
|
||||
void windowAdded(const QString &id, const int pid,
|
||||
const QString &title);
|
||||
void windowRemoved(const QString &id);
|
||||
void windowTitleChanged(const QString &id, const QString &title);
|
||||
};
|
||||
|
||||
bool isKWinAvailable();
|
||||
bool startKWinScript(QString &scriptObjectPath);
|
||||
bool stopKWinScript(const QString &scriptObjectPath);
|
||||
bool registerKWinDBusListener(FocusNotifier *notifier);
|
||||
void printDBusError();
|
||||
|
||||
} // namespace advss
|
||||
@@ -28,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);
|
||||
@@ -48,10 +49,12 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
_section->AddHeaderWidget(_enable);
|
||||
_section->AddHeaderWidget(_actionSelection);
|
||||
_section->AddHeaderWidget(_headerInfo);
|
||||
_section->AddHeaderWidget(_varMappingToggle);
|
||||
|
||||
auto actionLayout = new QVBoxLayout;
|
||||
actionLayout->setContentsMargins({7, 7, 7, 7});
|
||||
actionLayout->addWidget(_section);
|
||||
actionLayout->addWidget(_outputMappings);
|
||||
_contentLayout->addLayout(actionLayout);
|
||||
|
||||
auto mainLayout = new QHBoxLayout;
|
||||
@@ -60,13 +63,43 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
mainLayout->addWidget(_frame);
|
||||
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 &)));
|
||||
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
|
||||
SLOT(ShowVariableMappings(bool)));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetupVarMappings((*_entryData).get());
|
||||
SetFocusPolicyOfWidgets();
|
||||
|
||||
_allWidgetsAreSetup = true;
|
||||
}
|
||||
|
||||
void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
@@ -87,28 +120,15 @@ 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 &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
|
||||
SLOT(ShowVariableMappings(bool)));
|
||||
_section->SetContent(widget);
|
||||
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());
|
||||
SetupVarMappings((*_entryData).get());
|
||||
SetFocusPolicyOfWidgets();
|
||||
}
|
||||
|
||||
@@ -144,473 +164,9 @@ std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
||||
return *_entryData;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroAction(Macro *macro, int idx,
|
||||
const std::string &id, obs_data_t *data)
|
||||
void MacroActionEdit::FocusTypeSelection()
|
||||
{
|
||||
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());
|
||||
_actionSelection->setFocus();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -13,12 +13,11 @@ 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> *);
|
||||
void FocusTypeSelection() override;
|
||||
|
||||
private slots:
|
||||
void ActionSelectionChanged(const QString &text);
|
||||
@@ -32,7 +31,6 @@ private:
|
||||
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)
|
||||
|
||||
@@ -20,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,
|
||||
|
||||
196
lib/macro/macro-action-loop.cpp
Normal file
196
lib/macro/macro-action-loop.cpp
Normal file
@@ -0,0 +1,196 @@
|
||||
#include "macro-action-loop.hpp"
|
||||
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro-action-factory.hpp"
|
||||
#include "macro.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
const std::string MacroActionLoop::id = "loop";
|
||||
|
||||
bool MacroActionLoop::_registered = MacroActionFactory::Register(
|
||||
MacroActionLoop::id,
|
||||
{MacroActionLoop::Create, MacroActionLoopEdit::Create,
|
||||
"AdvSceneSwitcher.action.loop"});
|
||||
|
||||
bool MacroActionLoop::PerformAction()
|
||||
{
|
||||
int iterations = 0;
|
||||
const int maxIterations = _maxIterations;
|
||||
Macro *parentMacro = GetMacro();
|
||||
|
||||
if (maxIterations <= 0) {
|
||||
blog(LOG_WARNING,
|
||||
"loop action has invalid max iterations value of %d",
|
||||
maxIterations);
|
||||
return true;
|
||||
}
|
||||
|
||||
while (_loopMacro->CheckConditions()) {
|
||||
if (iterations >= maxIterations) {
|
||||
blog(LOG_WARNING,
|
||||
"loop action reached iteration limit of %d",
|
||||
maxIterations);
|
||||
break;
|
||||
}
|
||||
ablog(LOG_INFO, "loop iteration %d", iterations);
|
||||
if (!_loopMacro->PerformActions(true, false, true)) {
|
||||
break;
|
||||
}
|
||||
++iterations;
|
||||
if (parentMacro && parentMacro->GetStop()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ablog(LOG_INFO, "loop completed after %d iteration(s)", iterations);
|
||||
SetTempVarValue("count", std::to_string(iterations));
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroActionLoop::LogAction() const
|
||||
{
|
||||
ablog(LOG_INFO, "running loop (max %d iterations)",
|
||||
_maxIterations.GetValue());
|
||||
}
|
||||
|
||||
bool MacroActionLoop::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
_maxIterations.Save(obj, "maxIterations");
|
||||
OBSDataAutoRelease loopMacroData = obs_data_create();
|
||||
_loopMacro->Save(loopMacroData);
|
||||
obs_data_set_obj(obj, "loopMacro", loopMacroData);
|
||||
obs_data_set_int(obj, "customWidgetHeight", _customWidgetHeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroActionLoop::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_maxIterations.Load(obj, "maxIterations");
|
||||
if (obs_data_has_user_value(obj, "loopMacro")) {
|
||||
OBSDataAutoRelease loopMacroData =
|
||||
obs_data_get_obj(obj, "loopMacro");
|
||||
_loopMacro = std::make_shared<Macro>();
|
||||
_loopMacro->Load(loopMacroData);
|
||||
}
|
||||
_customWidgetHeight = obs_data_get_int(obj, "customWidgetHeight");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroActionLoop::PostLoad()
|
||||
{
|
||||
MacroAction::PostLoad();
|
||||
_loopMacro->PostLoad();
|
||||
_loopMacro->SetActionTriggerMode(Macro::ActionTriggerMode::ALWAYS);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionLoop::Create(Macro *m)
|
||||
{
|
||||
return std::make_shared<MacroActionLoop>(m);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionLoop::Copy() const
|
||||
{
|
||||
auto copy = std::make_shared<MacroActionLoop>(*this);
|
||||
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
_loopMacro->Save(data);
|
||||
|
||||
copy->_loopMacro = std::make_shared<Macro>();
|
||||
copy->_loopMacro->Load(data);
|
||||
copy->_loopMacro->PostLoad();
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
void MacroActionLoop::ResolveVariablesToFixedValues()
|
||||
{
|
||||
_maxIterations.ResolveVariables();
|
||||
for (auto &action : _loopMacro->Actions()) {
|
||||
action->ResolveVariablesToFixedValues();
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionLoop::SetupTempVars()
|
||||
{
|
||||
MacroAction::SetupTempVars();
|
||||
AddTempvar("count",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.loop.count"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.loop.count.description"));
|
||||
}
|
||||
|
||||
MacroActionLoopEdit::MacroActionLoopEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionLoop> entryData)
|
||||
: ResizableWidget(parent),
|
||||
_macroEdit(new MacroEdit(
|
||||
this, QStringList()
|
||||
<< "AdvSceneSwitcher.action.loop.conditionHelp"
|
||||
<< "AdvSceneSwitcher.action.loop.actionHelp"
|
||||
<< "")),
|
||||
_maxIterations(new VariableSpinBox())
|
||||
{
|
||||
_maxIterations->setMinimum(1);
|
||||
_maxIterations->setMaximum(10000000);
|
||||
|
||||
QWidget::connect(
|
||||
_maxIterations,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(MaxIterationsChanged(const NumberVariable<int> &)));
|
||||
|
||||
auto controlsLayout = new QHBoxLayout();
|
||||
controlsLayout->addWidget(new QLabel(
|
||||
obs_module_text("AdvSceneSwitcher.action.loop.maxIterations")));
|
||||
controlsLayout->addWidget(_maxIterations);
|
||||
controlsLayout->addStretch();
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->addLayout(controlsLayout);
|
||||
layout->addWidget(_macroEdit);
|
||||
setLayout(layout);
|
||||
|
||||
_macroEdit->HideElseSection();
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
MacroActionLoopEdit::~MacroActionLoopEdit()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
_entryData->_customWidgetHeight = GetCustomHeight();
|
||||
_macroEdit->SetMacro({});
|
||||
}
|
||||
|
||||
void MacroActionLoopEdit::UpdateEntryData()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_maxIterations->SetValue(_entryData->_maxIterations);
|
||||
_macroEdit->SetMacro(_entryData->_loopMacro);
|
||||
|
||||
if (_macroEdit->IsEmpty()) {
|
||||
_macroEdit->ShowAllMacroSections();
|
||||
_entryData->_customWidgetHeight = 600;
|
||||
}
|
||||
SetResizingEnabled(true);
|
||||
SetCustomHeight(_entryData->_customWidgetHeight);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionLoopEdit::MaxIterationsChanged(const NumberVariable<int> &value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_maxIterations = value;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
64
lib/macro/macro-action-loop.hpp
Normal file
64
lib/macro/macro-action-loop.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "macro-edit.hpp"
|
||||
#include "resizable-widget.hpp"
|
||||
#include "variable-spinbox.hpp"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MacroActionLoop : public MacroAction {
|
||||
public:
|
||||
MacroActionLoop(Macro *m) : MacroAction(m) {}
|
||||
bool PerformAction();
|
||||
void LogAction() const;
|
||||
bool Save(obs_data_t *obj) const;
|
||||
bool Load(obs_data_t *obj);
|
||||
bool PostLoad();
|
||||
std::string GetId() const { return id; }
|
||||
static std::shared_ptr<MacroAction> Create(Macro *m);
|
||||
std::shared_ptr<MacroAction> Copy() const;
|
||||
void ResolveVariablesToFixedValues();
|
||||
|
||||
std::shared_ptr<Macro> _loopMacro = std::make_shared<Macro>();
|
||||
IntVariable _maxIterations = 100;
|
||||
int _customWidgetHeight = 0;
|
||||
|
||||
private:
|
||||
void SetupTempVars();
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionLoopEdit : public ResizableWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroActionLoopEdit(
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroActionLoop> entryData = nullptr);
|
||||
~MacroActionLoopEdit();
|
||||
void UpdateEntryData();
|
||||
static QWidget *Create(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
return new MacroActionLoopEdit(
|
||||
parent,
|
||||
std::dynamic_pointer_cast<MacroActionLoop>(action));
|
||||
}
|
||||
|
||||
private slots:
|
||||
void MaxIterationsChanged(const NumberVariable<int> &value);
|
||||
|
||||
private:
|
||||
MacroEdit *_macroEdit;
|
||||
VariableSpinBox *_maxIterations;
|
||||
|
||||
std::shared_ptr<MacroActionLoop> _entryData;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,8 +1,14 @@
|
||||
#include "macro-action-macro.hpp"
|
||||
|
||||
#include "condition-logic.hpp"
|
||||
#include "help-icon.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro-action-factory.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace advss {
|
||||
|
||||
const std::string MacroActionMacro::id = "macro";
|
||||
@@ -12,70 +18,165 @@ 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;
|
||||
case Action::RUN_MACRO: {
|
||||
if (_runOptions.skipWhenPaused && macro->Paused()) {
|
||||
break;
|
||||
}
|
||||
const bool conditionsMatched =
|
||||
macro->CheckConditions(true);
|
||||
macro->PerformActions(conditionsMatched, false, true);
|
||||
break;
|
||||
}
|
||||
case Action::GET_INFO: {
|
||||
SetTempVarValue(
|
||||
"conditionCount",
|
||||
std::to_string(macro->Conditions().size()));
|
||||
SetTempVarValue(
|
||||
"actionCount",
|
||||
std::to_string(macro->Actions().size()));
|
||||
SetTempVarValue(
|
||||
"elseActionCount",
|
||||
std::to_string(macro->ElseActions().size()));
|
||||
SetTempVarValue("paused",
|
||||
macro->Paused() ? "true" : "false");
|
||||
SetTempVarValue("runCount",
|
||||
std::to_string(macro->RunCount()));
|
||||
const auto lastRun = macro->GetLastExecutionTime();
|
||||
const bool hasRun =
|
||||
lastRun.time_since_epoch().count() != 0;
|
||||
const auto secondsSinceLastRun =
|
||||
hasRun ? std::chrono::duration_cast<
|
||||
std::chrono::seconds>(
|
||||
std::chrono::
|
||||
high_resolution_clock::
|
||||
now() -
|
||||
lastRun)
|
||||
.count()
|
||||
: -1;
|
||||
SetTempVarValue("secondsSinceLastRun",
|
||||
std::to_string(secondsSinceLastRun));
|
||||
break;
|
||||
}
|
||||
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 +197,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 +216,15 @@ void MacroActionMacro::LogAction() const
|
||||
ablog(LOG_INFO, "toggled action %d of macro \"%s\"",
|
||||
_actionIndex.GetValue(), macro->Name().c_str());
|
||||
break;
|
||||
case Action::NESTED_MACRO:
|
||||
ablog(LOG_INFO, "run nested macro");
|
||||
break;
|
||||
case Action::GET_INFO:
|
||||
ablog(LOG_INFO, "get info for \"%s\"", macro->Name().c_str());
|
||||
break;
|
||||
case Action::RUN_MACRO:
|
||||
ablog(LOG_INFO, "run macro \"%s\"", macro->Name().c_str());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -123,21 +233,45 @@ 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);
|
||||
SetAction(static_cast<MacroActionMacro::Action>(
|
||||
obs_data_get_int(obj, "action")));
|
||||
_macro.Load(obj);
|
||||
_actionSelectionType = static_cast<SelectionType>(
|
||||
obs_data_get_int(obj, "actionSelectionType"));
|
||||
_actionIndex.Load(obj, "actionIndex");
|
||||
_action = static_cast<MacroActionMacro::Action>(
|
||||
obs_data_get_int(obj, "action"));
|
||||
_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 = std::make_shared<Macro>();
|
||||
_nestedMacro->Load(nestedMacroData);
|
||||
}
|
||||
|
||||
_customWidgetHeight = obs_data_get_int(obj, "customWidgetHeight");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -146,6 +280,7 @@ bool MacroActionMacro::PostLoad()
|
||||
MacroRefAction::PostLoad();
|
||||
MacroAction::PostLoad();
|
||||
_runOptions.macro.PostLoad();
|
||||
_nestedMacro->PostLoad();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -161,12 +296,32 @@ 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();
|
||||
|
||||
if (_action == Action::NESTED_MACRO) {
|
||||
for (auto &action : _nestedMacro->Actions()) {
|
||||
action->ResolveVariablesToFixedValues();
|
||||
}
|
||||
for (auto &action : _nestedMacro->ElseActions()) {
|
||||
action->ResolveVariablesToFixedValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void runActionsHelper(Macro *macro, bool runElseActions, bool setInputs,
|
||||
@@ -208,10 +363,89 @@ void MacroActionMacro::RunActions(Macro *actionMacro) const
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionMacro::SetAction(Action action)
|
||||
{
|
||||
_action = action;
|
||||
SetupTempVars();
|
||||
}
|
||||
|
||||
void MacroActionMacro::SetupTempVars()
|
||||
{
|
||||
MacroAction::SetupTempVars();
|
||||
|
||||
if (_action != Action::GET_INFO) {
|
||||
return;
|
||||
}
|
||||
|
||||
AddTempvar(
|
||||
"conditionCount",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.conditionCount"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.conditionCount.description"));
|
||||
AddTempvar(
|
||||
"actionCount",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.actionCount"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.actionCount.description"));
|
||||
AddTempvar(
|
||||
"elseActionCount",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.elseActionCount"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.elseActionCount.description"));
|
||||
AddTempvar(
|
||||
"paused",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.macro.info.paused"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.paused.description"));
|
||||
AddTempvar(
|
||||
"runCount",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.macro.info.runCount"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.runCount.description"));
|
||||
AddTempvar(
|
||||
"secondsSinceLastRun",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.secondsSinceLastRun"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.info.secondsSinceLastRun.description"));
|
||||
}
|
||||
|
||||
static void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
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.runActions"},
|
||||
{MacroActionMacro::Action::RUN_MACRO,
|
||||
"AdvSceneSwitcher.action.macro.type.runMacro"},
|
||||
{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"},
|
||||
{MacroActionMacro::Action::GET_INFO,
|
||||
"AdvSceneSwitcher.action.macro.type.getInfo"},
|
||||
};
|
||||
|
||||
for (const auto &[value, name] : actions) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +459,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,49 +467,99 @@ 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"))),
|
||||
_noConditionsWarning(new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.runMacro.noConditionsWarning"))),
|
||||
_runMacroHelp(new HelpIcon(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.runMacro.help"))),
|
||||
_setInputs(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.action.macro.type.run.setInputs"))),
|
||||
_inputs(new MacroInputEdit()),
|
||||
_entryLayout(new QHBoxLayout()),
|
||||
_conditionLayout(new QHBoxLayout()),
|
||||
_reevaluateConditionStateLayout(new QHBoxLayout()),
|
||||
_setInputsLayout(new QHBoxLayout())
|
||||
_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,6 +587,8 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
||||
layout->addLayout(_setInputsLayout);
|
||||
layout->addWidget(_inputs);
|
||||
layout->addWidget(_skipWhenPaused);
|
||||
layout->addWidget(_noConditionsWarning);
|
||||
layout->addWidget(_nestedMacro);
|
||||
setLayout(layout);
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
@@ -314,6 +600,12 @@ void HighlightMacroSettingsButton(bool enable);
|
||||
MacroActionMacroEdit::~MacroActionMacroEdit()
|
||||
{
|
||||
HighlightMacroSettingsButton(false);
|
||||
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
_entryData->_customWidgetHeight = GetCustomHeight();
|
||||
_nestedMacro->SetMacro({}); // Save splitter states
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::UpdateEntryData()
|
||||
@@ -321,23 +613,42 @@ void MacroActionMacroEdit::UpdateEntryData()
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
|
||||
_actions->setCurrentIndex(
|
||||
_actions->findData(static_cast<int>(_entryData->GetAction())));
|
||||
_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 +661,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->SetAction(static_cast<MacroActionMacro::Action>(
|
||||
_actions->itemData(idx).toInt()));
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::ActionSelectionTypeChanged(int idx)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_actionSelectionType =
|
||||
static_cast<MacroActionMacro::SelectionType>(
|
||||
_actionSelectionType->itemData(idx).toInt());
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -363,6 +684,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 +724,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)
|
||||
@@ -414,9 +757,14 @@ void MacroActionMacroEdit::InputsChanged(const StringList &inputs)
|
||||
void MacroActionMacroEdit::SetWidgetVisibility()
|
||||
{
|
||||
_entryLayout->removeWidget(_actions);
|
||||
_entryLayout->removeWidget(_runMacroHelp);
|
||||
_entryLayout->removeWidget(_actionIndex);
|
||||
_entryLayout->removeWidget(_macros);
|
||||
_entryLayout->removeWidget(_actionSections);
|
||||
_entryLayout->removeWidget(_label);
|
||||
_entryLayout->removeWidget(_regex);
|
||||
_entryLayout->removeWidget(_actionTypes);
|
||||
_entryLayout->removeWidget(_actionSelectionType);
|
||||
_conditionLayout->removeWidget(_conditionBehaviors);
|
||||
_conditionLayout->removeWidget(_conditionMacros);
|
||||
|
||||
@@ -425,20 +773,47 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
||||
|
||||
const std::unordered_map<std::string, QWidget *> placeholders = {
|
||||
{"{{actions}}", _actions},
|
||||
{"{{runMacroHelp}}", _runMacroHelp},
|
||||
{"{{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->GetAction();
|
||||
const char *layoutText = "";
|
||||
switch (action) {
|
||||
case MacroActionMacro::Action::PAUSE:
|
||||
case MacroActionMacro::Action::UNPAUSE:
|
||||
case MacroActionMacro::Action::TOGGLE_PAUSE:
|
||||
case MacroActionMacro::Action::RESET_COUNTER:
|
||||
case MacroActionMacro::Action::STOP:
|
||||
case MacroActionMacro::Action::NESTED_MACRO:
|
||||
case MacroActionMacro::Action::GET_INFO:
|
||||
layoutText = "AdvSceneSwitcher.action.macro.layout.other";
|
||||
break;
|
||||
case MacroActionMacro::Action::RUN_MACRO:
|
||||
layoutText = "AdvSceneSwitcher.action.macro.layout.runMacro";
|
||||
break;
|
||||
case MacroActionMacro::Action::RUN_ACTIONS:
|
||||
layoutText = "AdvSceneSwitcher.action.macro.layout.run";
|
||||
break;
|
||||
case MacroActionMacro::Action::DISABLE_ACTION:
|
||||
case MacroActionMacro::Action::ENABLE_ACTION:
|
||||
case MacroActionMacro::Action::TOGGLE_ACTION:
|
||||
layoutText = "AdvSceneSwitcher.action.macro.layout.actionState";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
PlaceWidgets(obs_module_text(layoutText), _entryLayout, placeholders);
|
||||
|
||||
if (_entryData->_runOptions.logic ==
|
||||
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS) {
|
||||
@@ -447,47 +822,82 @@ 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 ||
|
||||
action == MacroActionMacro::Action::RUN_MACRO) {
|
||||
_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);
|
||||
HighlightMacroSettingsButton(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN &&
|
||||
_entryData->_runOptions.setInputs &&
|
||||
!_inputs->HasInputsToSet());
|
||||
_actionTypes->setVisible(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN);
|
||||
_skipWhenPaused->setVisible(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN);
|
||||
HighlightMacroSettingsButton(
|
||||
action == MacroActionMacro::Action::RUN_ACTIONS &&
|
||||
_entryData->_runOptions.setInputs &&
|
||||
!_inputs->HasInputsToSet());
|
||||
_actionSections->setVisible(
|
||||
action == MacroActionMacro::Action::RUN_ACTIONS ||
|
||||
isModifyingActionState);
|
||||
_skipWhenPaused->setVisible(
|
||||
action == MacroActionMacro::Action::RUN_ACTIONS ||
|
||||
action == MacroActionMacro::Action::RUN_MACRO);
|
||||
|
||||
if (action == MacroActionMacro::Action::RUN_MACRO) {
|
||||
auto macro = _entryData->_macro.GetMacro();
|
||||
_noConditionsWarning->setVisible(!macro ||
|
||||
macro->Conditions().empty());
|
||||
} else {
|
||||
_noConditionsWarning->setVisible(false);
|
||||
}
|
||||
_runMacroHelp->setVisible(action ==
|
||||
MacroActionMacro::Action::RUN_MACRO);
|
||||
|
||||
_nestedMacro->setVisible(action ==
|
||||
MacroActionMacro::Action::NESTED_MACRO);
|
||||
_macros->setVisible(action != MacroActionMacro::Action::NESTED_MACRO);
|
||||
SetResizingEnabled(action == MacroActionMacro::Action::NESTED_MACRO);
|
||||
|
||||
if (_nestedMacro->IsEmpty()) {
|
||||
_nestedMacro->ShowAllMacroSections();
|
||||
// TODO: find a better solution than setting a fixed height
|
||||
_entryData->_customWidgetHeight = 600;
|
||||
}
|
||||
SetCustomHeight(_entryData->_customWidgetHeight);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
#pragma once
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-edit.hpp"
|
||||
#include "macro-input.hpp"
|
||||
#include "macro-selection.hpp"
|
||||
#include "macro-segment-selection.hpp"
|
||||
#include "regex-config.hpp"
|
||||
#include "resizable-widget.hpp"
|
||||
#include "variable-line-edit.hpp"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -44,24 +50,44 @@ public:
|
||||
PAUSE,
|
||||
UNPAUSE,
|
||||
RESET_COUNTER,
|
||||
RUN,
|
||||
RUN_ACTIONS,
|
||||
STOP,
|
||||
DISABLE_ACTION,
|
||||
ENABLE_ACTION,
|
||||
TOGGLE_ACTION,
|
||||
TOGGLE_PAUSE,
|
||||
NESTED_MACRO,
|
||||
GET_INFO,
|
||||
RUN_MACRO,
|
||||
};
|
||||
Action _action = Action::RUN;
|
||||
|
||||
void SetAction(Action);
|
||||
Action GetAction() const { return _action; }
|
||||
|
||||
enum class SelectionType { INDEX, LABEL, ID };
|
||||
|
||||
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 SetupTempVars();
|
||||
void RunActions(Macro *actionMacro) const;
|
||||
void AdjustActionState(Macro *) const;
|
||||
|
||||
Action _action = Action::NESTED_MACRO;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionMacroEdit final : public QWidget {
|
||||
class MacroActionMacroEdit final : public ResizableWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@@ -70,22 +96,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,20 +121,27 @@ 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;
|
||||
QLabel *_noConditionsWarning;
|
||||
HelpIcon *_runMacroHelp;
|
||||
QCheckBox *_setInputs;
|
||||
MacroInputEdit *_inputs;
|
||||
QHBoxLayout *_entryLayout;
|
||||
QHBoxLayout *_conditionLayout;
|
||||
QHBoxLayout *_reevaluateConditionStateLayout;
|
||||
QHBoxLayout *_setInputsLayout;
|
||||
MacroEdit *_nestedMacro;
|
||||
|
||||
std::shared_ptr<MacroActionMacro> _entryData;
|
||||
bool _loading = true;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#include "macro-action-variable.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "help-icon.hpp"
|
||||
#include "json-helpers.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "non-modal-dialog.hpp"
|
||||
#include "source-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <random>
|
||||
@@ -14,6 +17,15 @@ namespace advss {
|
||||
|
||||
const std::string MacroActionVariable::id = "variable";
|
||||
|
||||
std::vector<TempVariableRef> MacroActionVariable::GetTempVarRefs() const
|
||||
{
|
||||
auto refs = MacroSegment::GetTempVarRefs();
|
||||
if (_tempVar.HasValidID()) {
|
||||
refs.push_back(_tempVar);
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
bool MacroActionVariable::_registered = MacroActionFactory::Register(
|
||||
MacroActionVariable::id,
|
||||
{MacroActionVariable::Create, MacroActionVariableEdit::Create,
|
||||
@@ -216,6 +228,43 @@ void MacroActionVariable::GenerateRandomNumber(Variable *var)
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionVariable::PickRandomValue(Variable *var)
|
||||
{
|
||||
static std::random_device rd;
|
||||
static std::mt19937 gen(rd());
|
||||
static const uint8_t maxIter = 255;
|
||||
|
||||
if (_randomValues.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_randomValues.size() == 1) {
|
||||
const auto &value = _randomValues.at(0);
|
||||
var->SetValue(value);
|
||||
_lastRandomValue = value;
|
||||
}
|
||||
|
||||
std::uniform_int_distribution<int> dis(0, _randomValues.size() - 1);
|
||||
StringVariable value = _randomValues.at(dis(gen));
|
||||
|
||||
uint8_t iter = 0;
|
||||
for (; !_allowRepeatValues && iter < maxIter &&
|
||||
_lastRandomValue.has_value() &&
|
||||
std::string(value) == _lastRandomValue.value();
|
||||
iter++) {
|
||||
value = _randomValues.at(dis(gen));
|
||||
}
|
||||
|
||||
if (iter == maxIter) {
|
||||
blog(LOG_INFO,
|
||||
"giving up picking non-repeat random value after %d tries",
|
||||
maxIter);
|
||||
}
|
||||
|
||||
var->SetValue(value);
|
||||
_lastRandomValue = value;
|
||||
}
|
||||
|
||||
struct AskForInputParams {
|
||||
AskForInputParams(const QString &prompt_, const QString &placeholder_)
|
||||
: prompt(prompt_),
|
||||
@@ -283,6 +332,14 @@ bool MacroActionVariable::PerformAction()
|
||||
case Action::APPEND:
|
||||
apppend(*var, _strValue);
|
||||
break;
|
||||
case Action::COPY_VAR: {
|
||||
auto var2 = _variable2.lock();
|
||||
if (!var2) {
|
||||
return true;
|
||||
}
|
||||
var->SetValue(var2->Value());
|
||||
break;
|
||||
}
|
||||
case Action::APPEND_VAR: {
|
||||
auto var2 = _variable2.lock();
|
||||
if (!var2) {
|
||||
@@ -385,6 +442,34 @@ bool MacroActionVariable::PerformAction()
|
||||
var->SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
case Action::QUERY_JSON: {
|
||||
auto value = QueryJson(var->Value(), _jsonQuery);
|
||||
if (!value.has_value()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!_jsonQueryExtractSingle) {
|
||||
var->SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto extracted = ExtractSingleJsonArrayElement(*value);
|
||||
if (extracted.has_value()) {
|
||||
var->SetValue(*extracted);
|
||||
} else {
|
||||
var->SetValue(*value);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
case Action::ARRAY_JSON: {
|
||||
auto value = AccessJsonArrayIndex(var->Value(), _jsonIndex);
|
||||
if (!value.has_value()) {
|
||||
return true;
|
||||
}
|
||||
var->SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
case Action::SET_TO_TEMPVAR: {
|
||||
auto tempVar = _tempVar.GetTempVariable(GetMacro());
|
||||
if (!tempVar) {
|
||||
@@ -431,6 +516,9 @@ bool MacroActionVariable::PerformAction()
|
||||
case Action::RANDOM_NUMBER:
|
||||
GenerateRandomNumber(var.get());
|
||||
return true;
|
||||
case Action::RANDOM_LIST_VALUE:
|
||||
PickRandomValue(var.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -462,7 +550,7 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
_inputPlaceholder.Save(obj, "inputPlaceholder");
|
||||
_envVariableName.Save(obj, "environmentVariableName");
|
||||
_scene.Save(obj);
|
||||
_tempVar.Save(obj);
|
||||
_tempVar.Save(obj, GetMacro());
|
||||
_sceneItemIndex.Save(obj, "sceneItemIndex");
|
||||
obs_data_set_int(obj, "direction", static_cast<int>(_direction));
|
||||
_stringLength.Save(obj, "stringLength");
|
||||
@@ -471,6 +559,12 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
_randomNumberStart.Save(obj, "randomNumberStart");
|
||||
_randomNumberEnd.Save(obj, "randomNumberEnd");
|
||||
obs_data_set_bool(obj, "generateInteger", _generateInteger);
|
||||
_randomValues.Save(obj, "randomValues", "value");
|
||||
obs_data_set_bool(obj, "allowRepeatValues", _allowRepeatValues);
|
||||
_jsonQuery.Save(obj, "jsonQuery");
|
||||
_jsonIndex.Save(obj, "jsonIndex");
|
||||
obs_data_set_bool(obj, "jsonQueryExtractSingle",
|
||||
_jsonQueryExtractSingle);
|
||||
|
||||
obs_data_set_int(obj, "version", 1);
|
||||
|
||||
@@ -527,6 +621,12 @@ bool MacroActionVariable::Load(obs_data_t *obj)
|
||||
_randomNumberStart.Load(obj, "randomNumberStart");
|
||||
_randomNumberEnd.Load(obj, "randomNumberEnd");
|
||||
_generateInteger = obs_data_get_bool(obj, "generateInteger");
|
||||
_randomValues.Load(obj, "randomValues", "value");
|
||||
_allowRepeatValues = obs_data_get_bool(obj, "allowRepeatValues");
|
||||
_jsonQuery.Load(obj, "jsonQuery");
|
||||
_jsonIndex.Load(obj, "jsonIndex");
|
||||
_jsonQueryExtractSingle =
|
||||
obs_data_get_bool(obj, "jsonQueryExtractSingle");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -626,6 +726,8 @@ void MacroActionVariable::ResolveVariablesToFixedValues()
|
||||
_envVariableName.ResolveVariables();
|
||||
_scene.ResolveVariables();
|
||||
_sceneItemIndex.ResolveVariables();
|
||||
_jsonQuery.ResolveVariables();
|
||||
_jsonIndex.ResolveVariables();
|
||||
}
|
||||
|
||||
void MacroActionVariable::DecrementCurrentSegmentVariableRef()
|
||||
@@ -645,6 +747,8 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
actions = {
|
||||
{MacroActionVariable::Action::SET_VALUE,
|
||||
"AdvSceneSwitcher.action.variable.type.set"},
|
||||
{MacroActionVariable::Action::COPY_VAR,
|
||||
"AdvSceneSwitcher.action.variable.type.copy"},
|
||||
{MacroActionVariable::Action::APPEND,
|
||||
"AdvSceneSwitcher.action.variable.type.append"},
|
||||
{MacroActionVariable::Action::PAD,
|
||||
@@ -655,8 +759,6 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
"AdvSceneSwitcher.action.variable.type.subString"},
|
||||
{MacroActionVariable::Action::FIND_AND_REPLACE,
|
||||
"AdvSceneSwitcher.action.variable.type.findAndReplace"},
|
||||
{MacroActionVariable::Action::EXTRACT_JSON,
|
||||
"AdvSceneSwitcher.action.variable.type.extractJson"},
|
||||
{MacroActionVariable::Action::STRING_LENGTH,
|
||||
"AdvSceneSwitcher.action.variable.type.stringLength"},
|
||||
{MacroActionVariable::Action::TRIM,
|
||||
@@ -665,6 +767,14 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
"AdvSceneSwitcher.action.variable.type.changeCase"},
|
||||
{true, ""}, // Separator
|
||||
|
||||
{MacroActionVariable::Action::EXTRACT_JSON,
|
||||
"AdvSceneSwitcher.action.variable.type.extractJsonField"},
|
||||
{MacroActionVariable::Action::QUERY_JSON,
|
||||
"AdvSceneSwitcher.action.variable.type.queryJson"},
|
||||
{MacroActionVariable::Action::ARRAY_JSON,
|
||||
"AdvSceneSwitcher.action.variable.type.accessJsonArray"},
|
||||
{true, ""}, // Separator
|
||||
|
||||
{MacroActionVariable::Action::SET_TO_TEMPVAR,
|
||||
"AdvSceneSwitcher.action.variable.type.setToTempvar"},
|
||||
{MacroActionVariable::Action::SET_CONDITION_VALUE,
|
||||
@@ -683,6 +793,8 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
"AdvSceneSwitcher.action.variable.type.roundToInt"},
|
||||
{MacroActionVariable::Action::RANDOM_NUMBER,
|
||||
"AdvSceneSwitcher.action.variable.type.randomNumber"},
|
||||
{MacroActionVariable::Action::RANDOM_LIST_VALUE,
|
||||
"AdvSceneSwitcher.action.variable.type.randomListValue"},
|
||||
{true, ""}, // Separator
|
||||
|
||||
{MacroActionVariable::Action::USER_INPUT,
|
||||
@@ -760,11 +872,10 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_segmentValueStatus(new QLabel()),
|
||||
_segmentValue(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
||||
_substringLayout(new QVBoxLayout()),
|
||||
_subStringIndexEntryLayout(new QHBoxLayout()),
|
||||
_subStringRegexEntryLayout(new QHBoxLayout()),
|
||||
_subStringControlsLayout(new QHBoxLayout()),
|
||||
_subStringStart(new VariableSpinBox(this)),
|
||||
_subStringSize(new VariableSpinBox(this)),
|
||||
_substringRegex(new RegexConfigWidget(parent)),
|
||||
_subStringRegex(new RegexConfigWidget(parent)),
|
||||
_regexPattern(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
||||
_regexMatchIdx(new VariableSpinBox(this)),
|
||||
_findReplaceLayout(new QHBoxLayout()),
|
||||
@@ -796,7 +907,28 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.generateInteger"),
|
||||
this)),
|
||||
_randomLayout(new QVBoxLayout()),
|
||||
_randomNumberLayout(new QVBoxLayout()),
|
||||
_randomValues(new StringListEdit(this)),
|
||||
_allowRepeatValues(new QCheckBox(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.allowRepeat"),
|
||||
this)),
|
||||
_randomValueLayout(new QVBoxLayout()),
|
||||
_jsonQuery(new VariableLineEdit(this)),
|
||||
_jsonQueryHelp(new HelpIcon(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.queryJson.info"),
|
||||
this)),
|
||||
_jsonIndex(new VariableSpinBox(this)),
|
||||
_jsonExtractSingle(new QCheckBox(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.queryJson.extractSingle"),
|
||||
this)),
|
||||
_jsonExtractSingleHelp(new HelpIcon(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.queryJson.extractSingle.info"),
|
||||
this)),
|
||||
_jsonQueryLayout(new QVBoxLayout()),
|
||||
_entryLayout(new QHBoxLayout())
|
||||
{
|
||||
_numValue->setMinimum(-9999999999);
|
||||
@@ -826,6 +958,13 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_randomNumberStart->setMaximum(9999999999);
|
||||
_randomNumberEnd->setMinimum(-9999999999);
|
||||
_randomNumberEnd->setMaximum(9999999999);
|
||||
_randomValues->SetMaxStringSize(99999999);
|
||||
_jsonIndex->setMaximum(999);
|
||||
auto jsonExtractSingleLayout = new QHBoxLayout();
|
||||
jsonExtractSingleLayout->addWidget(_jsonExtractSingle);
|
||||
jsonExtractSingleLayout->addWidget(_jsonExtractSingleHelp);
|
||||
jsonExtractSingleLayout->addStretch();
|
||||
_jsonQueryLayout->addLayout(jsonExtractSingleLayout);
|
||||
|
||||
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
||||
this, SLOT(VariableChanged(const QString &)));
|
||||
@@ -842,7 +981,8 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
QWidget::connect(_segmentIdx,
|
||||
SIGNAL(SelectionChanged(const IntVariable &)), this,
|
||||
SLOT(SegmentIndexChanged(const IntVariable &)));
|
||||
QWidget::connect(window(), SIGNAL(MacroSegmentOrderChanged()), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(SegmentOrderChanged()), this,
|
||||
SLOT(MacroSegmentOrderChanged()));
|
||||
QWidget::connect(
|
||||
_subStringStart,
|
||||
@@ -852,7 +992,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_subStringSize,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(SubStringSizeChanged(const NumberVariable<int> &)));
|
||||
QWidget::connect(_substringRegex,
|
||||
QWidget::connect(_subStringRegex,
|
||||
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
|
||||
SLOT(SubStringRegexChanged(const RegexConfig &)));
|
||||
QWidget::connect(_regexPattern, SIGNAL(textChanged()), this,
|
||||
@@ -912,6 +1052,19 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
SLOT(RandomNumberEndChanged(const NumberVariable<double> &)));
|
||||
QWidget::connect(_generateInteger, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(GenerateIntegerChanged(int)));
|
||||
QWidget::connect(_randomValues,
|
||||
SIGNAL(StringListChanged(const StringList &)), this,
|
||||
SLOT(RandomValueListChanged(const StringList &)));
|
||||
QWidget::connect(_allowRepeatValues, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(AllowRepeatValuesChanged(int)));
|
||||
QWidget::connect(_jsonQuery, SIGNAL(editingFinished()), this,
|
||||
SLOT(JsonQueryChanged()));
|
||||
QWidget::connect(
|
||||
_jsonIndex,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(JsonIndexChanged(const NumberVariable<int> &)));
|
||||
QWidget::connect(_jsonExtractSingle, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(JsonQueryExtractSingleChanged(int)));
|
||||
|
||||
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{variables}}", _variables},
|
||||
@@ -920,9 +1073,6 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
{"{{strValue}}", _strValue},
|
||||
{"{{numValue}}", _numValue},
|
||||
{"{{segmentIndex}}", _segmentIdx},
|
||||
{"{{subStringStart}}", _subStringStart},
|
||||
{"{{subStringSize}}", _subStringSize},
|
||||
{"{{regexMatchIdx}}", _regexMatchIdx},
|
||||
{"{{findRegex}}", _findRegex},
|
||||
{"{{findStr}}", _findStr},
|
||||
{"{{replaceStr}}", _replaceStr},
|
||||
@@ -943,54 +1093,55 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
{"{{randomNumberStart}}", _randomNumberStart},
|
||||
{"{{randomNumberEnd}}", _randomNumberEnd},
|
||||
{"{{generateInteger}}", _generateInteger},
|
||||
{"{{jsonQuery}}", _jsonQuery},
|
||||
{"{{jsonQueryHelp}}", _jsonQueryHelp},
|
||||
{"{{jsonIndex}}", _jsonIndex},
|
||||
};
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.action.variable.entry.other"),
|
||||
_entryLayout, widgetPlaceholders);
|
||||
PlaceWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.layout.other"),
|
||||
_entryLayout, widgetPlaceholders);
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.substringIndex"),
|
||||
_subStringIndexEntryLayout, widgetPlaceholders);
|
||||
"AdvSceneSwitcher.action.variable.layout.substringIndex"),
|
||||
_subStringControlsLayout, widgetPlaceholders);
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.substringRegex"),
|
||||
_subStringRegexEntryLayout, widgetPlaceholders);
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.findAndReplace"),
|
||||
"AdvSceneSwitcher.action.variable.layout.findAndReplace"),
|
||||
_findReplaceLayout, widgetPlaceholders, false);
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.userInput.customPrompt"),
|
||||
"AdvSceneSwitcher.action.variable.layout.userInput.customPrompt"),
|
||||
_promptLayout, widgetPlaceholders);
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.userInput.placeholder"),
|
||||
"AdvSceneSwitcher.action.variable.layout.userInput.placeholder"),
|
||||
_placeholderLayout, widgetPlaceholders);
|
||||
|
||||
auto randomLayout = new QHBoxLayout();
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.randomNumber"),
|
||||
"AdvSceneSwitcher.action.variable.layout.randomNumber"),
|
||||
randomLayout, widgetPlaceholders);
|
||||
_randomLayout->addLayout(randomLayout);
|
||||
_randomLayout->addWidget(_generateInteger);
|
||||
_randomNumberLayout->addLayout(randomLayout);
|
||||
_randomNumberLayout->addWidget(_generateInteger);
|
||||
|
||||
_randomValueLayout->addWidget(_randomValues);
|
||||
_randomValueLayout->addWidget(_allowRepeatValues);
|
||||
|
||||
auto regexConfigLayout = new QHBoxLayout;
|
||||
regexConfigLayout->addWidget(_substringRegex);
|
||||
regexConfigLayout->addWidget(_subStringRegex);
|
||||
regexConfigLayout->addStretch();
|
||||
|
||||
_substringLayout->addLayout(_subStringIndexEntryLayout);
|
||||
_substringLayout->addLayout(_subStringRegexEntryLayout);
|
||||
_substringLayout->addLayout(_subStringControlsLayout);
|
||||
_substringLayout->addWidget(_regexPattern);
|
||||
_substringLayout->addLayout(regexConfigLayout);
|
||||
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->addLayout(_entryLayout);
|
||||
layout->addLayout(_jsonQueryLayout);
|
||||
layout->addLayout(_substringLayout);
|
||||
layout->addWidget(_segmentValueStatus);
|
||||
layout->addWidget(_segmentValue);
|
||||
@@ -998,7 +1149,8 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
layout->addWidget(_mathExpressionResult);
|
||||
layout->addLayout(_promptLayout);
|
||||
layout->addLayout(_placeholderLayout);
|
||||
layout->addLayout(_randomLayout);
|
||||
layout->addLayout(_randomNumberLayout);
|
||||
layout->addLayout(_randomValueLayout);
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
@@ -1032,7 +1184,7 @@ void MacroActionVariableEdit::UpdateEntryData()
|
||||
: MacroSegmentSelection::Type::ACTION);
|
||||
_subStringStart->SetValue(_entryData->_subStringStart);
|
||||
_subStringSize->SetValue(_entryData->_subStringSize);
|
||||
_substringRegex->SetRegexConfig(_entryData->_subStringRegex);
|
||||
_subStringRegex->SetRegexConfig(_entryData->_subStringRegex);
|
||||
_findRegex->SetRegexConfig(_entryData->_findRegex);
|
||||
_regexPattern->setPlainText(
|
||||
QString::fromStdString(_entryData->_regexPattern));
|
||||
@@ -1057,17 +1209,18 @@ void MacroActionVariableEdit::UpdateEntryData()
|
||||
_randomNumberStart->SetValue(_entryData->_randomNumberStart);
|
||||
_randomNumberEnd->SetValue(_entryData->_randomNumberEnd);
|
||||
_generateInteger->setChecked(_entryData->_generateInteger);
|
||||
_allowRepeatValues->setChecked(_entryData->_allowRepeatValues);
|
||||
_randomValues->SetStringList(_entryData->_randomValues);
|
||||
_jsonQuery->setText(_entryData->_jsonQuery);
|
||||
_jsonIndex->SetValue(_entryData->_jsonIndex);
|
||||
_jsonExtractSingle->setChecked(_entryData->_jsonQueryExtractSingle);
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::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()));
|
||||
@@ -1075,11 +1228,7 @@ void MacroActionVariableEdit::VariableChanged(const QString &text)
|
||||
|
||||
void MacroActionVariableEdit::Variable2Changed(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_variable2 = GetWeakVariableByQString(text);
|
||||
}
|
||||
|
||||
@@ -1105,11 +1254,7 @@ void MacroActionVariableEdit::ActionChanged(int idx)
|
||||
|
||||
void MacroActionVariableEdit::StrValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_strValue = _strValue->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -1118,21 +1263,13 @@ void MacroActionVariableEdit::StrValueChanged()
|
||||
void MacroActionVariableEdit::NumValueChanged(
|
||||
const NumberVariable<double> &value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_numValue = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SegmentIndexChanged(const IntVariable &val)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->SetSegmentIndexValue(val - 1);
|
||||
}
|
||||
|
||||
@@ -1238,32 +1375,20 @@ void MacroActionVariableEdit::MacroSegmentOrderChanged()
|
||||
void MacroActionVariableEdit::SubStringStartChanged(
|
||||
const NumberVariable<int> &start)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_subStringStart = start;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SubStringSizeChanged(
|
||||
const NumberVariable<int> &size)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_subStringSize = size;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SubStringRegexChanged(const RegexConfig &conf)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_subStringRegex = conf;
|
||||
|
||||
SetWidgetVisibility();
|
||||
@@ -1271,11 +1396,7 @@ void MacroActionVariableEdit::SubStringRegexChanged(const RegexConfig &conf)
|
||||
|
||||
void MacroActionVariableEdit::RegexPatternChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_regexPattern = _regexPattern->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -1284,21 +1405,13 @@ void MacroActionVariableEdit::RegexPatternChanged()
|
||||
void MacroActionVariableEdit::RegexMatchIdxChanged(
|
||||
const NumberVariable<int> &index)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_regexMatchIdx = index;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::FindStrValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_findStr = _findStr->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -1306,11 +1419,7 @@ void MacroActionVariableEdit::FindStrValueChanged()
|
||||
|
||||
void MacroActionVariableEdit::FindRegexChanged(const RegexConfig &conf)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_findRegex = conf;
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -1318,11 +1427,7 @@ void MacroActionVariableEdit::FindRegexChanged(const RegexConfig &conf)
|
||||
|
||||
void MacroActionVariableEdit::ReplaceStrValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_replaceStr = _replaceStr->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -1330,11 +1435,7 @@ void MacroActionVariableEdit::ReplaceStrValueChanged()
|
||||
|
||||
void MacroActionVariableEdit::MathExpressionChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_mathExpression = _mathExpression->text().toStdString();
|
||||
|
||||
// In case of invalid expression display an error
|
||||
@@ -1352,95 +1453,60 @@ void MacroActionVariableEdit::MathExpressionChanged()
|
||||
|
||||
void MacroActionVariableEdit::UseCustomPromptChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_useCustomPrompt = value;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::InputPromptChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_inputPrompt = _inputPrompt->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::UseInputPlaceholderChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_useInputPlaceholder = value;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::InputPlaceholderChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_inputPlaceholder = _inputPlaceholder->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::EnvVariableChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_envVariableName = _envVariable->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SceneChanged(const SceneSelection &scene)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_scene = scene;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SelectionChanged(const TempVariableRef &var)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_tempVar = var;
|
||||
IncrementTempVarInUseGeneration();
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SceneItemIndexChanged(
|
||||
const NumberVariable<int> &value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_sceneItemIndex = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::DirectionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_direction =
|
||||
static_cast<MacroActionVariable::Direction>(value);
|
||||
}
|
||||
@@ -1448,21 +1514,13 @@ void MacroActionVariableEdit::DirectionChanged(int value)
|
||||
void MacroActionVariableEdit::StringLengthChanged(
|
||||
const NumberVariable<int> &value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_stringLength = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::CharSelectionChanged(const QString &character)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
if (character.isEmpty()) {
|
||||
_entryData->_paddingChar = ' ';
|
||||
} else {
|
||||
@@ -1472,11 +1530,7 @@ void MacroActionVariableEdit::CharSelectionChanged(const QString &character)
|
||||
|
||||
void MacroActionVariableEdit::CaseTypeChanged(int index)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_caseType = static_cast<MacroActionVariable::CaseType>(
|
||||
_caseType->itemData(index).toInt());
|
||||
}
|
||||
@@ -1501,6 +1555,36 @@ void MacroActionVariableEdit::GenerateIntegerChanged(int value)
|
||||
_entryData->_generateInteger = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::RandomValueListChanged(const StringList &values)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_randomValues = values;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::AllowRepeatValuesChanged(int value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_allowRepeatValues = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::JsonQueryChanged()
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_jsonQuery = _jsonQuery->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::JsonIndexChanged(const NumberVariable<int> &value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_jsonIndex = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::JsonQueryExtractSingleChanged(int value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_jsonQueryExtractSingle = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
{
|
||||
if (!_entryData) {
|
||||
@@ -1524,26 +1608,40 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
{"{{stringLength}}", _stringLength},
|
||||
{"{{paddingCharSelection}}", _paddingCharSelection},
|
||||
{"{{caseType}}", _caseType},
|
||||
{"{{jsonQuery}}", _jsonQuery},
|
||||
{"{{jsonQueryHelp}}", _jsonQueryHelp},
|
||||
{"{{jsonIndex}}", _jsonIndex},
|
||||
{"{{subStringRegex}}", _subStringRegex},
|
||||
{"{{subStringStart}}", _subStringStart},
|
||||
{"{{subStringSize}}", _subStringSize},
|
||||
{"{{regexMatchIdx}}", _regexMatchIdx},
|
||||
};
|
||||
|
||||
for (const auto &[_, widget] : widgetPlaceholders) {
|
||||
_entryLayout->removeWidget(widget);
|
||||
_subStringControlsLayout->removeWidget(widget);
|
||||
}
|
||||
|
||||
ClearLayout(_entryLayout);
|
||||
ClearLayout(_subStringControlsLayout);
|
||||
|
||||
const char *layoutString = "";
|
||||
if (_entryData->_action == MacroActionVariable::Action::PAD) {
|
||||
layoutString = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.pad");
|
||||
"AdvSceneSwitcher.action.variable.layout.pad");
|
||||
} else if (_entryData->_action ==
|
||||
MacroActionVariable::Action::TRUNCATE) {
|
||||
layoutString = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.truncate");
|
||||
"AdvSceneSwitcher.action.variable.layout.truncate");
|
||||
} else if (_entryData->_action ==
|
||||
MacroActionVariable::Action::COPY_VAR) {
|
||||
layoutString = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.layout.copy");
|
||||
} else {
|
||||
layoutString = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.other");
|
||||
"AdvSceneSwitcher.action.variable.layout.other");
|
||||
}
|
||||
|
||||
for (const auto &[_, widget] : widgetPlaceholders) {
|
||||
_entryLayout->removeWidget(widget);
|
||||
}
|
||||
|
||||
ClearLayout(_entryLayout);
|
||||
PlaceWidgets(layoutString, _entryLayout, widgetPlaceholders);
|
||||
|
||||
if (_entryData->_action == MacroActionVariable::Action::SET_VALUE ||
|
||||
@@ -1552,13 +1650,15 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
MacroActionVariable::Action::MATH_EXPRESSION ||
|
||||
_entryData->_action == MacroActionVariable::Action::ENV_VARIABLE ||
|
||||
_entryData->_action == MacroActionVariable::Action::STRING_LENGTH ||
|
||||
_entryData->_action == MacroActionVariable::Action::EXTRACT_JSON) {
|
||||
_entryData->_action == MacroActionVariable::Action::EXTRACT_JSON ||
|
||||
_entryData->_action == MacroActionVariable::Action::QUERY_JSON) {
|
||||
RemoveStretchIfPresent(_entryLayout);
|
||||
} else {
|
||||
AddStretchIfNecessary(_entryLayout);
|
||||
}
|
||||
|
||||
_variables2->setVisible(
|
||||
_entryData->_action == MacroActionVariable::Action::COPY_VAR ||
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::APPEND_VAR ||
|
||||
_entryData->_action ==
|
||||
@@ -1588,15 +1688,25 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
MacroActionVariable::Action::SET_ACTION_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::SET_CONDITION_VALUE);
|
||||
|
||||
bool showRegex = _entryData->_subStringRegex.Enabled();
|
||||
layoutString =
|
||||
showRegex
|
||||
? "AdvSceneSwitcher.action.variable.layout.substringRegex"
|
||||
: "AdvSceneSwitcher.action.variable.layout.substringIndex";
|
||||
PlaceWidgets(obs_module_text(layoutString), _subStringControlsLayout,
|
||||
widgetPlaceholders);
|
||||
_subStringStart->setVisible(!showRegex);
|
||||
_subStringSize->setVisible(!showRegex);
|
||||
_regexMatchIdx->setVisible(showRegex);
|
||||
|
||||
SetLayoutVisible(_substringLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::SUBSTRING);
|
||||
if (_entryData->_action == MacroActionVariable::Action::SUBSTRING) {
|
||||
bool showRegex = _entryData->_subStringRegex.Enabled();
|
||||
SetLayoutVisible(_subStringIndexEntryLayout, !showRegex);
|
||||
SetLayoutVisible(_subStringRegexEntryLayout, showRegex);
|
||||
_regexPattern->setVisible(showRegex);
|
||||
}
|
||||
_regexPattern->setVisible(
|
||||
showRegex &&
|
||||
_entryData->_action == MacroActionVariable::Action::SUBSTRING);
|
||||
|
||||
SetLayoutVisible(_findReplaceLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::FIND_AND_REPLACE);
|
||||
@@ -1661,9 +1771,22 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
MacroActionVariable::Action::PAD);
|
||||
_caseType->setVisible(_entryData->_action ==
|
||||
MacroActionVariable::Action::CHANGE_CASE);
|
||||
SetLayoutVisible(_randomLayout,
|
||||
SetLayoutVisible(_randomNumberLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::RANDOM_NUMBER);
|
||||
SetLayoutVisible(
|
||||
_randomValueLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::RANDOM_LIST_VALUE);
|
||||
_jsonQuery->setVisible(_entryData->_action ==
|
||||
MacroActionVariable::Action::QUERY_JSON);
|
||||
_jsonQueryHelp->setVisible(_entryData->_action ==
|
||||
MacroActionVariable::Action::QUERY_JSON);
|
||||
_jsonIndex->setVisible(_entryData->_action ==
|
||||
MacroActionVariable::Action::ARRAY_JSON);
|
||||
SetLayoutVisible(_jsonQueryLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::QUERY_JSON);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
@@ -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"
|
||||
@@ -22,6 +23,7 @@ public:
|
||||
bool PostLoad();
|
||||
std::string GetShortDesc() const;
|
||||
std::string GetId() const { return id; };
|
||||
std::vector<TempVariableRef> GetTempVarRefs() const;
|
||||
static std::shared_ptr<MacroAction> Create(Macro *m);
|
||||
std::shared_ptr<MacroAction> Copy() const;
|
||||
void SetSegmentIndexValue(int);
|
||||
@@ -53,6 +55,10 @@ public:
|
||||
TRIM,
|
||||
CHANGE_CASE,
|
||||
RANDOM_NUMBER,
|
||||
QUERY_JSON,
|
||||
ARRAY_JSON,
|
||||
COPY_VAR,
|
||||
RANDOM_LIST_VALUE,
|
||||
};
|
||||
|
||||
Action _action = Action::SET_VALUE;
|
||||
@@ -104,6 +110,14 @@ public:
|
||||
DoubleVariable _randomNumberEnd = 100;
|
||||
bool _generateInteger = true;
|
||||
|
||||
StringList _randomValues = {"value1", "value2", "value3"};
|
||||
bool _allowRepeatValues = true;
|
||||
std::optional<std::string> _lastRandomValue;
|
||||
|
||||
StringVariable _jsonQuery = "$.some.nested.value";
|
||||
IntVariable _jsonIndex = 0;
|
||||
bool _jsonQueryExtractSingle = true;
|
||||
|
||||
private:
|
||||
void DecrementCurrentSegmentVariableRef();
|
||||
void HandleIndexSubString(Variable *);
|
||||
@@ -113,6 +127,7 @@ private:
|
||||
void HandleCaseChange(Variable *);
|
||||
void SetToSceneItemName(Variable *);
|
||||
void GenerateRandomNumber(Variable *);
|
||||
void PickRandomValue(Variable *);
|
||||
|
||||
std::weak_ptr<MacroSegment> _macroSegment;
|
||||
int _segmentIdxLoadValue = -1;
|
||||
@@ -169,6 +184,11 @@ private slots:
|
||||
void RandomNumberStartChanged(const NumberVariable<double> &);
|
||||
void RandomNumberEndChanged(const NumberVariable<double> &);
|
||||
void GenerateIntegerChanged(int);
|
||||
void RandomValueListChanged(const StringList &);
|
||||
void AllowRepeatValuesChanged(int);
|
||||
void JsonQueryChanged();
|
||||
void JsonIndexChanged(const NumberVariable<int> &);
|
||||
void JsonQueryExtractSingleChanged(int);
|
||||
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
@@ -186,11 +206,10 @@ private:
|
||||
QLabel *_segmentValueStatus;
|
||||
ResizingPlainTextEdit *_segmentValue;
|
||||
QVBoxLayout *_substringLayout;
|
||||
QHBoxLayout *_subStringIndexEntryLayout;
|
||||
QHBoxLayout *_subStringRegexEntryLayout;
|
||||
QHBoxLayout *_subStringControlsLayout;
|
||||
VariableSpinBox *_subStringStart;
|
||||
VariableSpinBox *_subStringSize;
|
||||
RegexConfigWidget *_substringRegex;
|
||||
RegexConfigWidget *_subStringRegex;
|
||||
ResizingPlainTextEdit *_regexPattern;
|
||||
VariableSpinBox *_regexMatchIdx;
|
||||
QHBoxLayout *_findReplaceLayout;
|
||||
@@ -217,7 +236,16 @@ private:
|
||||
VariableDoubleSpinBox *_randomNumberStart;
|
||||
VariableDoubleSpinBox *_randomNumberEnd;
|
||||
QCheckBox *_generateInteger;
|
||||
QVBoxLayout *_randomLayout;
|
||||
QVBoxLayout *_randomNumberLayout;
|
||||
StringListEdit *_randomValues;
|
||||
QCheckBox *_allowRepeatValues;
|
||||
QVBoxLayout *_randomValueLayout;
|
||||
VariableLineEdit *_jsonQuery;
|
||||
HelpIcon *_jsonQueryHelp;
|
||||
VariableSpinBox *_jsonIndex;
|
||||
QCheckBox *_jsonExtractSingle;
|
||||
HelpIcon *_jsonExtractSingleHelp;
|
||||
QVBoxLayout *_jsonQueryLayout;
|
||||
QHBoxLayout *_entryLayout;
|
||||
|
||||
std::shared_ptr<MacroActionVariable> _entryData;
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
#include "macro-condition-edit.hpp"
|
||||
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "condition-logic.hpp"
|
||||
#include "macro-settings.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "path-helpers.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "section.hpp"
|
||||
#include "switch-button.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
@@ -100,14 +104,17 @@ void DurationModifierEdit::Collapse(bool collapse)
|
||||
|
||||
MacroConditionEdit::MacroConditionEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
||||
const std::string &id, bool isRootCondition)
|
||||
bool isRootCondition)
|
||||
: MacroSegmentEdit(parent),
|
||||
_enable(new SwitchButton()),
|
||||
_logicSelection(new QComboBox()),
|
||||
_conditionSelection(new FilterComboBox()),
|
||||
_dur(new DurationModifierEdit()),
|
||||
_entryData(entryData),
|
||||
_isRoot(isRootCondition)
|
||||
{
|
||||
QWidget::connect(_enable, SIGNAL(checked(bool)), this,
|
||||
SLOT(ConditionEnableChanged(bool)));
|
||||
QWidget::connect(_logicSelection, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(LogicSelectionChanged(int)));
|
||||
QWidget::connect(_conditionSelection,
|
||||
@@ -122,14 +129,17 @@ MacroConditionEdit::MacroConditionEdit(
|
||||
Logic::PopulateLogicTypeSelection(_logicSelection, isRootCondition);
|
||||
populateConditionSelection(_conditionSelection);
|
||||
|
||||
_section->AddHeaderWidget(_enable);
|
||||
_section->AddHeaderWidget(_logicSelection);
|
||||
_section->AddHeaderWidget(_conditionSelection);
|
||||
_section->AddHeaderWidget(_headerInfo);
|
||||
_section->AddHeaderWidget(_dur);
|
||||
_section->AddHeaderWidget(_varMappingToggle);
|
||||
|
||||
QVBoxLayout *conditionLayout = new QVBoxLayout;
|
||||
conditionLayout->setContentsMargins({7, 7, 7, 7});
|
||||
conditionLayout->addWidget(_section);
|
||||
conditionLayout->addWidget(_outputMappings);
|
||||
_contentLayout->addLayout(conditionLayout);
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
@@ -138,7 +148,7 @@ MacroConditionEdit::MacroConditionEdit(
|
||||
mainLayout->addWidget(_frame);
|
||||
setLayout(mainLayout);
|
||||
|
||||
UpdateEntryData(id);
|
||||
SetupWidgets(true);
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
@@ -152,11 +162,20 @@ 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()
|
||||
void MacroConditionEdit::ConditionEnableChanged(bool value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
(*_entryData)->SetEnabled(value);
|
||||
SetDisableEffect(!value);
|
||||
}
|
||||
|
||||
bool MacroConditionEdit::IsRootNode() const
|
||||
{
|
||||
return _isRoot;
|
||||
}
|
||||
@@ -166,7 +185,9 @@ void MacroConditionEdit::SetLogicSelection()
|
||||
const auto logic = (*_entryData)->GetLogicType();
|
||||
_logicSelection->setCurrentIndex(
|
||||
_logicSelection->findData(static_cast<int>(logic)));
|
||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
_enable->setChecked(enabled);
|
||||
SetEnableAppearance(enabled);
|
||||
}
|
||||
|
||||
void MacroConditionEdit::SetRootNode(bool root)
|
||||
@@ -178,23 +199,39 @@ 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 &)));
|
||||
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
|
||||
SLOT(ShowVariableMappings(bool)));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetupVarMappings((*_entryData).get());
|
||||
SetFocusPolicyOfWidgets();
|
||||
|
||||
_allWidgetsAreSetup = true;
|
||||
}
|
||||
|
||||
void MacroConditionEdit::SetEntryData(std::shared_ptr<MacroCondition> *data)
|
||||
@@ -221,20 +258,28 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto logic = (*_entryData)->GetLogicType();
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
_entryData->reset();
|
||||
*_entryData = MacroConditionFactory::Create(id, macro);
|
||||
(*_entryData)->SetIndex(idx);
|
||||
(*_entryData)->SetLogicType(logic);
|
||||
(*_entryData)->SetEnabled(enabled);
|
||||
(*_entryData)->PostLoad();
|
||||
RunPostLoadSteps();
|
||||
RunAndClearPostLoadSteps();
|
||||
}
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
QWidget::connect(widget, SIGNAL(ShowVariableMappings(bool)), this,
|
||||
SLOT(ShowVariableMappings(bool)));
|
||||
_section->SetContent(widget);
|
||||
SetupVarMappings((*_entryData).get());
|
||||
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
|
||||
SetFocusPolicyOfWidgets();
|
||||
|
||||
emit MacroSignalManager::Instance()->ConditionTypeCreated(
|
||||
QString::fromStdString(id));
|
||||
}
|
||||
|
||||
void MacroConditionEdit::DurationChanged(const Duration &seconds)
|
||||
@@ -262,289 +307,9 @@ std::shared_ptr<MacroSegment> MacroConditionEdit::Data() const
|
||||
return *_entryData;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroCondition(int idx)
|
||||
void MacroConditionEdit::FocusTypeSelection()
|
||||
{
|
||||
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());
|
||||
_conditionSelection->setFocus();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
class SwitchButton;
|
||||
|
||||
class DurationModifierEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -34,26 +36,27 @@ 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> *);
|
||||
void FocusTypeSelection() override;
|
||||
|
||||
private slots:
|
||||
void LogicSelectionChanged(int idx);
|
||||
void ConditionSelectionChanged(const QString &text);
|
||||
void DurationChanged(const Duration &value);
|
||||
void DurationModifierChanged(DurationModifier::Type m);
|
||||
void ConditionEnableChanged(bool);
|
||||
|
||||
private:
|
||||
void SetLogicSelection();
|
||||
std::shared_ptr<MacroSegment> Data() const;
|
||||
|
||||
SwitchButton *_enable;
|
||||
QComboBox *_logicSelection;
|
||||
FilterComboBox *_conditionSelection;
|
||||
DurationModifierEdit *_dur;
|
||||
|
||||
@@ -1,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,10 @@
|
||||
#include "macro-condition-macro.hpp"
|
||||
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-ref.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "macro.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -26,6 +30,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 +105,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 +127,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 +174,8 @@ bool MacroConditionMacro::CheckCondition()
|
||||
return CheckActionStateCondition();
|
||||
case Type::PAUSED:
|
||||
return CheckPauseState();
|
||||
case Type::ACTIONS_PERFORMED:
|
||||
return CheckActionsPerformed();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -300,6 +318,7 @@ MacroConditionMacroEdit::MacroConditionMacroEdit(
|
||||
_actionIndex(new MacroSegmentSelection(
|
||||
this, MacroSegmentSelection::Type::ACTION))
|
||||
{
|
||||
_macros->HideGroups();
|
||||
_count->setMaximum(10000000);
|
||||
populateTypeSelection(_types);
|
||||
populateCounterConditionSelection(_counterConditions);
|
||||
@@ -307,7 +326,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 +434,9 @@ void MacroConditionMacroEdit::SetupWidgets()
|
||||
case MacroConditionMacro::Type::PAUSED:
|
||||
SetupPauseWidgets();
|
||||
break;
|
||||
case MacroConditionMacro::Type::ACTIONS_PERFORMED:
|
||||
SetupActionsPerformedWidgets();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -472,6 +495,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 +512,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 +571,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 +580,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 +611,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 +657,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 +665,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 +680,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 +688,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 +697,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ public:
|
||||
ACTION_DISABLED,
|
||||
ACTION_ENABLED,
|
||||
PAUSED,
|
||||
ACTIONS_PERFORMED,
|
||||
};
|
||||
void SetType(Type);
|
||||
Type GetType() const { return _type; }
|
||||
@@ -66,6 +67,7 @@ private:
|
||||
bool CheckMultiStateCondition();
|
||||
bool CheckActionStateCondition();
|
||||
bool CheckPauseState();
|
||||
bool CheckActionsPerformed();
|
||||
|
||||
void SetupTempVars();
|
||||
|
||||
@@ -134,6 +136,7 @@ private:
|
||||
void SetupCountWidgets();
|
||||
void SetupActionStateWidgets(bool enable);
|
||||
void SetupPauseWidgets();
|
||||
void SetupActionsPerformedWidgets();
|
||||
void SetWidgetVisibility();
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
@@ -115,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(
|
||||
@@ -129,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()));
|
||||
@@ -141,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,15 @@ namespace advss {
|
||||
|
||||
const std::string MacroConditionTempVar::id = "temp_var";
|
||||
|
||||
std::vector<TempVariableRef> MacroConditionTempVar::GetTempVarRefs() const
|
||||
{
|
||||
auto refs = MacroSegment::GetTempVarRefs();
|
||||
if (_tempVar.HasValidID()) {
|
||||
refs.push_back(_tempVar);
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
bool MacroConditionTempVar::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionTempVar::id,
|
||||
{MacroConditionTempVar::Create, MacroConditionTempVarEdit::Create,
|
||||
@@ -154,7 +163,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 +273,20 @@ void MacroConditionTempVarEdit::UpdateEntryData()
|
||||
|
||||
void MacroConditionTempVarEdit::VariableChanged(const TempVariableRef &var)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_tempVar = var;
|
||||
IncrementTempVarInUseGeneration();
|
||||
}
|
||||
|
||||
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 +294,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 +302,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();
|
||||
|
||||
@@ -20,6 +20,7 @@ public:
|
||||
bool Load(obs_data_t *obj);
|
||||
std::string GetShortDesc() const;
|
||||
std::string GetId() const { return id; };
|
||||
std::vector<TempVariableRef> GetTempVarRefs() const;
|
||||
static std::shared_ptr<MacroCondition> Create(Macro *m)
|
||||
{
|
||||
return std::make_shared<MacroConditionTempVar>(m);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "macro-condition.hpp"
|
||||
|
||||
#include "condition-logic.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
MacroCondition::MacroCondition(Macro *m, bool supportsVariableValue)
|
||||
@@ -7,6 +9,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);
|
||||
@@ -20,6 +33,10 @@ bool MacroCondition::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroSegment::Load(obj);
|
||||
_logic.Load(obj, "logic");
|
||||
if (_logic.GetType() == Logic::Type::NONE) {
|
||||
SetEnabled(false);
|
||||
_logic.SetType(Logic::Type::AND);
|
||||
}
|
||||
_durationModifier.Load(obj);
|
||||
return true;
|
||||
}
|
||||
@@ -39,7 +56,8 @@ void MacroCondition::ValidateLogicSelection(bool isRootCondition,
|
||||
return;
|
||||
}
|
||||
|
||||
_logic.SetType(Logic::Type::NONE);
|
||||
_logic.SetType(Logic::Type::AND);
|
||||
SetEnabled(false);
|
||||
blog(LOG_WARNING,
|
||||
"setting invalid logic selection to 'ignore' for macro %s",
|
||||
context);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
397
lib/macro/macro-dock-settings.cpp
Normal file
397
lib/macro/macro-dock-settings.cpp
Normal file
@@ -0,0 +1,397 @@
|
||||
#include "macro-dock-settings.hpp"
|
||||
|
||||
#include "macro-dock-window.hpp"
|
||||
#include "macro-dock.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "variable-string.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");
|
||||
|
||||
1876
lib/macro/macro-edit.cpp
Normal file
1876
lib/macro/macro-edit.cpp
Normal file
File diff suppressed because it is too large
Load Diff
144
lib/macro/macro-edit.hpp
Normal file
144
lib/macro/macro-edit.hpp
Normal file
@@ -0,0 +1,144 @@
|
||||
#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();
|
||||
void HideElseSection() const;
|
||||
|
||||
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 ScrollAndFocusNewSegment(MacroSegmentList *list, int newIdx,
|
||||
int *currentIdx);
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user