mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 12:45:28 -05:00
Compare commits
158 Commits
1.29.3
...
1.32.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
|
||||
|
||||
@@ -22,7 +22,7 @@ runs:
|
||||
- name: Setup cmake
|
||||
uses: jwlawson/actions-setup-cmake@v1.13
|
||||
with:
|
||||
cmake-version: '3.24.x'
|
||||
cmake-version: '3.28.x'
|
||||
|
||||
- name: Restore cached dependencies
|
||||
id: restore-cache
|
||||
|
||||
7
.github/scripts/.Aptfile
vendored
7
.github/scripts/.Aptfile
vendored
@@ -10,4 +10,9 @@ package 'libxss-dev'
|
||||
package 'libopencv-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'
|
||||
|
||||
27
.github/scripts/.build-deps.zsh
vendored
27
.github/scripts/.build-deps.zsh
vendored
@@ -478,6 +478,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
|
||||
-DOPENSSL_ROOT_DIR="${advss_dep_path}"
|
||||
-DPAHO_WITH_SSL=OFF # TODO: figure out linking issues with openssl
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
3
.github/scripts/.package.zsh
vendored
3
.github/scripts/.package.zsh
vendored
@@ -258,6 +258,9 @@ ${_usage_host:-}"
|
||||
pushd ${project_root}
|
||||
cmake --build build_${target##*-} --config ${config} -t package ${cmake_args}
|
||||
|
||||
# Mark certain deps as optional
|
||||
build-aux/CI/linux/demote-deps.sh ${project_root}/release/*.deb Recommends '(mqtt)|(opencv)|(tesseract)|(usb)|(x11)'
|
||||
|
||||
if [ ! -e ${project_root}/release/${output_name}.deb ]; then
|
||||
mv ${project_root}/release/*.deb ${project_root}/release/${output_name}.deb
|
||||
mv ${project_root}/release/*.ddeb ${project_root}/release/${output_name}.ddeb
|
||||
|
||||
33
.github/scripts/Build-Deps-Windows.ps1
vendored
33
.github/scripts/Build-Deps-Windows.ps1
vendored
@@ -209,7 +209,9 @@ function Build {
|
||||
$msbuildExe = vswhere -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1
|
||||
|
||||
if ($msbuildExe) {
|
||||
$env:CL="/wd5287"
|
||||
Invoke-External $msbuildExe "${LibusbPath}/msvc/libusb.sln" /property:Configuration=Release /property:Platform=x64
|
||||
Remove-Item Env:CL
|
||||
|
||||
$libusbBuildResultDirectory = "${LibusbPath}/build/v143/x64/Release"
|
||||
if (-not (Test-Path -Path $libusbBuildResultDirectory)) {
|
||||
@@ -219,6 +221,37 @@ 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"
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
1
.github/scripts/utils.zsh/setup_ccache
vendored
1
.github/scripts/utils.zsh/setup_ccache
vendored
@@ -10,7 +10,6 @@ if (( ${+commands[ccache]} )) {
|
||||
|
||||
typeset -gx CCACHE_CONFIGPATH="${project_root}/.ccache.conf"
|
||||
|
||||
ccache --set-config=run_second_cpp=true
|
||||
ccache --set-config=direct_mode=true
|
||||
ccache --set-config=inode_cache=true
|
||||
ccache --set-config=compiler_check=content
|
||||
|
||||
1
.github/scripts/utils.zsh/setup_linux
vendored
1
.github/scripts/utils.zsh/setup_linux
vendored
@@ -41,6 +41,7 @@ if (( ! (${skips[(Ie)all]} + ${skips[(Ie)deps]}) )) {
|
||||
sudo apt-get install ${apt_args} \
|
||||
build-essential \
|
||||
libgles2-mesa-dev \
|
||||
libsimde-dev \
|
||||
obs-studio
|
||||
|
||||
local -a _qt_packages=()
|
||||
|
||||
8
.github/workflows/build-project.yaml
vendored
8
.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-2
|
||||
jobs:
|
||||
check-event:
|
||||
name: Check GitHub Event Data 🔎
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
macos-build:
|
||||
name: Build for macOS 🍏
|
||||
runs-on: macos-14
|
||||
runs-on: macos-15
|
||||
needs: check-event
|
||||
defaults:
|
||||
run:
|
||||
@@ -107,8 +107,8 @@ jobs:
|
||||
print "pluginName=${product_name}" >> $GITHUB_OUTPUT
|
||||
print "pluginVersion=${git_tag}" >> $GITHUB_OUTPUT
|
||||
|
||||
print '::group::Enable Xcode 15.2'
|
||||
sudo xcode-select --switch /Applications/Xcode_15.2.app/Contents/Developer
|
||||
print '::group::Enable Xcode 16.1'
|
||||
sudo xcode-select --switch /Applications/Xcode_16.1.0.app/Contents/Developer
|
||||
print '::endgroup::'
|
||||
|
||||
- uses: actions/cache@v4
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -31,3 +31,9 @@
|
||||
[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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -103,8 +103,6 @@ target_sources(
|
||||
lib/macro/macro-action-macro.hpp
|
||||
lib/macro/macro-action-queue.cpp
|
||||
lib/macro/macro-action-queue.hpp
|
||||
lib/macro/macro-action-script.cpp
|
||||
lib/macro/macro-action-script.hpp
|
||||
lib/macro/macro-action-variable.cpp
|
||||
lib/macro/macro-action-variable.hpp
|
||||
lib/macro/macro-action.cpp
|
||||
@@ -117,8 +115,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 +123,12 @@ target_sources(
|
||||
lib/macro/macro-condition.hpp
|
||||
lib/macro/macro-dock.cpp
|
||||
lib/macro/macro-dock.hpp
|
||||
lib/macro/macro-dock-settings.hpp
|
||||
lib/macro/macro-dock-settings.cpp
|
||||
lib/macro/macro-dock-window.cpp
|
||||
lib/macro/macro-dock-window.hpp
|
||||
lib/macro/macro-edit.cpp
|
||||
lib/macro/macro-edit.hpp
|
||||
lib/macro/macro-export-import-dialog.cpp
|
||||
lib/macro/macro-export-import-dialog.hpp
|
||||
lib/macro/macro-helpers.cpp
|
||||
@@ -139,22 +141,21 @@ 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-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
|
||||
@@ -172,6 +173,8 @@ target_sources(
|
||||
lib/utils/auto-update-tooltip-label.hpp
|
||||
lib/utils/backup.cpp
|
||||
lib/utils/backup.hpp
|
||||
lib/utils/canvas-helpers.cpp
|
||||
lib/utils/canvas-helpers.hpp
|
||||
lib/utils/condition-logic.cpp
|
||||
lib/utils/condition-logic.hpp
|
||||
lib/utils/curl-helper.cpp
|
||||
@@ -195,6 +198,8 @@ target_sources(
|
||||
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 +226,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
|
||||
@@ -358,6 +360,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 +428,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}")
|
||||
@@ -442,7 +460,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/.*")
|
||||
|
||||
@@ -19,6 +19,8 @@ The **Snap** package manager offers an OBS Studio installation which is bundled
|
||||
sudo snap install obs-studio
|
||||
```
|
||||
|
||||
More information can be found [here](https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation).
|
||||
|
||||
## Contributing
|
||||
|
||||
- If you wish to contribute code to the project, have a look at this [section](BUILDING.md) describing how to compile the plugin.
|
||||
|
||||
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"
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -80,6 +80,8 @@ function(set_target_properties_plugin target)
|
||||
|
||||
configure_file(cmake/windows/resources/installer-Windows.iss.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/installer-Windows.generated.iss")
|
||||
configure_file(data/res/images/logo.ico
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/installer.ico" COPYONLY)
|
||||
|
||||
configure_file(cmake/windows/resources/resource.rc.in
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.rc")
|
||||
|
||||
@@ -20,6 +20,9 @@ OutputBaseFilename={#MyAppName}-{#MyAppVersion}-Windows-Installer
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
DirExistsWarning=no
|
||||
SetupIconFile=installer.ico
|
||||
UninstallDisplayIcon={app}\data\obs-plugins\advanced-scene-switcher\res\images\logo.ico
|
||||
DisableDirPage=no
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
@@ -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"
|
||||
@@ -195,12 +194,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"
|
||||
@@ -384,8 +383,6 @@ AdvSceneSwitcher.condition.variable.type.greaterThanVariable="ist größer als d
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Szene wechseln"
|
||||
AdvSceneSwitcher.action.scene.entry="Wechsle{{sceneTypes}}Szene zu{{scenes}}mittels{{transitions}}mit einer Dauer von{{duration}}Sekunden"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Wechsle{{sceneTypes}}Szene zu{{scenes}}mittels{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Warten, bis der Übergang zur Zielszene abgeschlossen ist"
|
||||
AdvSceneSwitcher.action.wait="Warten"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fixe"
|
||||
@@ -467,7 +464,7 @@ AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenw
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="Einstellungen importieren aus"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Hinweis: Die Aktion wird ignoriert, solange das Einstellungsfenster geöffnet ist."
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Virtuelle Kamera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Virtuelle Kamera stoppen"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Virtuelle Kamera starten"
|
||||
@@ -753,9 +750,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Starte/Stoppe den Erweite
|
||||
AdvSceneSwitcher.hotkey.macro.pause="Pausiere Makro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.unpause="Makro %1 nicht mehr pausieren"
|
||||
AdvSceneSwitcher.hotkey.macro.togglePause="Pause von Makro %1 togglen"
|
||||
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Makro-Segmentauswahl nach oben verschieben"
|
||||
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Makro-Segmentauswahl nach unten verschieben"
|
||||
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Ausgewähltes Makro-Segment entfernen"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.up="Makro-Segmentauswahl nach oben verschieben"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.down="Makro-Segmentauswahl nach unten verschieben"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.remove="Ausgewähltes Makro-Segment entfernen"
|
||||
|
||||
AdvSceneSwitcher.askBackup="Neue Version des Erweiterten Automatischen Szenenwechslers wurde erkannt.\nSoll ein Backup der alten Einstellungen angelegt werden?"
|
||||
AdvSceneSwitcher.askForMacro="Makro auswählen {{macroSelection}}"
|
||||
|
||||
@@ -4,7 +4,7 @@ AdvSceneSwitcher.windowTitle="Advanced Scene Switcher"
|
||||
# General Tab
|
||||
AdvSceneSwitcher.generalTab.title="General"
|
||||
AdvSceneSwitcher.generalTab.status="Status"
|
||||
AdvSceneSwitcher.generalTab.status.hotkeytips="Hotkeys can be defined in the OBS settings"
|
||||
AdvSceneSwitcher.generalTab.status.hotkeytips="Start/stop hotkeys can be defined in the OBS settings"
|
||||
AdvSceneSwitcher.generalTab.status.currentStatus="Advanced Scene Switcher is:"
|
||||
AdvSceneSwitcher.generalTab.status.onStartup="On startup of OBS:"
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="Start the scene switcher if it was running"
|
||||
@@ -12,11 +12,12 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Always start the scene
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Do not start the scene switcher"
|
||||
AdvSceneSwitcher.generalTab.status.start="Start"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Stop"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Automatically start the scene switcher when:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Automatically start the scene switcher when:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Never"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Recording"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Streaming"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming="Recording or Streaming"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.scene="Automatically start the scene switcher on scene:"
|
||||
AdvSceneSwitcher.generalTab.status.checkInterval="Check conditions every"
|
||||
AdvSceneSwitcher.generalTab.status.checkIntervalTooLow="⚠️ Conflict with macro \"%1\"!"
|
||||
AdvSceneSwitcher.generalTab.status.checkIntervalTooLow.tooltip="Macro \"%1\" won't be able to check its condition at the desired interval of %2.\nEither change the condition check value on the General tab or in the settings of macro \"%3\"."
|
||||
@@ -29,11 +30,11 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Switch to:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="After performing actions skip performing actions for"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="During this time potential matches will be ignored!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel="Log level:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.disable="Disable logging"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default="Default"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logMacro="Log executed macros"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction="Log performed actions"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose="Verbose logging"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Enable verbose logging"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Save window position and size"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Show system tray notifications"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Disable UI hints"
|
||||
@@ -42,6 +43,7 @@ AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailure="Display warni
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailureMessage="<html><body>Loading of the following plugin libraries was unsuccessful, which could result in some Advanced Scene Switcher functions not being available:%1Check the OBS logs for details.<br>This message can be disabled on the General tab.</body></html>"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.warnCorruptedInstallMessage="The plugin installation seems to be corrupted and might crash!\nPlease make sure the plugin was installed correctly!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs="Hide tabs which can be represented via macros"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableMacroWidgetCache="Disable macro widget caching"
|
||||
AdvSceneSwitcher.generalTab.matchBehavior="Match behavior"
|
||||
AdvSceneSwitcher.generalTab.priority="Priority"
|
||||
AdvSceneSwitcher.generalTab.priority.description="Switching methods priority (Highest priority is at the top)"
|
||||
@@ -52,7 +54,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Export"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Import"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Export Advanced Scene Switcher settings to file ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Import Advanced Scene Switcher settings from file ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text files (*.txt)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text files (*.txt);;JSON files (*.json)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Advanced Scene Switcher failed to import settings"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Advanced Scene Switcher settings imported successfully"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportSensitiveDataWarning="Warning:\nThe exported data might contain sensitive information!"
|
||||
@@ -132,14 +134,26 @@ AdvSceneSwitcher.twitchConnectionTab.no="No"
|
||||
AdvSceneSwitcher.twitchConnectionTab.removeSingleConnectionPopup.text="Are you sure you want to remove \"%1\"?"
|
||||
AdvSceneSwitcher.twitchConnectionTab.removeMultipleConnectionsPopup.text="Are you sure you want to remove %1 Twitch connections?"
|
||||
|
||||
# MQTT Connections Tab
|
||||
AdvSceneSwitcher.mqttConnectionTab.title="MQTT Connections"
|
||||
AdvSceneSwitcher.mqttConnectionTab.help="MQTT connections can be used to communicate with other devices.\n\nClick on the highlighted plus symbol to add a new connection."
|
||||
AdvSceneSwitcher.mqttConnectionTab.mqttonnectionAddButton.tooltip="Add new MQTT connection"
|
||||
AdvSceneSwitcher.mqttConnectionTab.mqttConnectionRemoveButton.tooltip="Remove selected MQTT connections"
|
||||
AdvSceneSwitcher.mqttConnectionTab.name.header="Name"
|
||||
AdvSceneSwitcher.mqttConnectionTab.address.header="Address"
|
||||
AdvSceneSwitcher.mqttConnectionTab.topics.header="Topic subscription count"
|
||||
AdvSceneSwitcher.mqttConnectionTab.status.header="Status"
|
||||
AdvSceneSwitcher.mqttConnectionTab.removeSingleConnectionPopup.text="Are you sure you want to remove \"%1\"?"
|
||||
AdvSceneSwitcher.mqttConnectionTab.removeMultipleConnectionsPopup.text="Are you sure you want to remove %1 connections?"
|
||||
|
||||
# Macro Tab
|
||||
AdvSceneSwitcher.macroTab.title="Macro"
|
||||
AdvSceneSwitcher.macroTab.macros="Macros"
|
||||
AdvSceneSwitcher.macroTab.priorityWarning="Note: It is recommended to configure macros to be the highest priority functionality.\nThis setting can be changed on the General tab."
|
||||
AdvSceneSwitcher.macroTab.help="Macros allow you to execute a string of actions depending on multiple conditions.\n\nClick on the highlighted plus symbol to add a new Macro."
|
||||
AdvSceneSwitcher.macroTab.editConditionHelp="This section allows you to define Macro conditions.\n\nSelect an existing or add a new Macro on the left.\nThen click the plus button below to add a new condition."
|
||||
AdvSceneSwitcher.macroTab.editActionHelp="This section allows you to define Macro actions.\n\nSelect an existing or add a new Macro on the left.\nThen click the plus button below to add a new action."
|
||||
AdvSceneSwitcher.macroTab.editElseActionHelp="This section allows you to define Macro actions, which are executed if the conditions are *not* met.\n\nSelect an existing or add a new Macro on the left.\nThen click the plus button below to add a new action."
|
||||
AdvSceneSwitcher.macroTab.editConditionHelp="This section allows you to define macro conditions.\n\nSelect an existing or add a new macro on the left.\nThen click the plus button below to add a new condition."
|
||||
AdvSceneSwitcher.macroTab.editActionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are met.\n\nSelect an existing or add a new macro on the left.\nThen click the plus button below to add a new action."
|
||||
AdvSceneSwitcher.macroTab.editElseActionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are *not* met.\n\nSelect an existing or add a new macro on the left.\nThen click the plus button below to add a new action."
|
||||
AdvSceneSwitcher.macroTab.edit="Edit macro"
|
||||
AdvSceneSwitcher.macroTab.edit.logic="Logic type:"
|
||||
AdvSceneSwitcher.macroTab.edit.condition="Condition type:"
|
||||
@@ -164,6 +178,8 @@ AdvSceneSwitcher.macroTab.contextMenuAdd="Add"
|
||||
AdvSceneSwitcher.macroTab.copy="Duplicate Macro"
|
||||
AdvSceneSwitcher.macroTab.group="Group Selected Macros"
|
||||
AdvSceneSwitcher.macroTab.ungroup="Ungroup Selected Groups"
|
||||
AdvSceneSwitcher.macroTab.expandAllGroups="Expand all Groups"
|
||||
AdvSceneSwitcher.macroTab.collapseAllGroups="Collapse all Groups"
|
||||
AdvSceneSwitcher.macroTab.rename="Rename"
|
||||
AdvSceneSwitcher.macroTab.remove="Remove"
|
||||
AdvSceneSwitcher.macroTab.export="Export"
|
||||
@@ -199,8 +215,11 @@ AdvSceneSwitcher.macroTab.highlightTrueConditions="Highlight conditions of curre
|
||||
AdvSceneSwitcher.macroTab.highlightPerformedActions="Highlight recently performed actions of currently selected macro"
|
||||
AdvSceneSwitcher.macroTab.newMacroRegisterHotkey="Register hotkeys to control the pause state of new macros"
|
||||
AdvSceneSwitcher.macroTab.newMacroUseShortCircuitEvaluation="Enable short circuit evaluation of macro conditions for new macros"
|
||||
AdvSceneSwitcher.macroTab.saveSettingsOnMacroChange="Save settings when selecting a new macro"
|
||||
AdvSceneSwitcher.macroTab.newMacroCheckInParallel="Evaluate conditions of new macros in parallel to other macros"
|
||||
AdvSceneSwitcher.macroTab.checkInParallel.tooltip="If this option is not enabled, this macro's conditions will be evaluated after the preceeding macro's condition check has completed.\nSo, if there are three macros - Macro A, Macro B, and Macro C - in the macro list the order the conditions in are evaluated is:\n • Macro A's conditions\n • Macro B's conditions\n • Macro C's conditions\nIf this option is enabled, the order might differ.\nEnabling this option can be useful for scenarios in which you have multiple long running condition checks, which you don't want to result in \"blocking\" other macros."
|
||||
AdvSceneSwitcher.macroTab.saveSettingsOnMacroChange="Save settings when switching between macros"
|
||||
AdvSceneSwitcher.macroTab.saveSettingsOnMacroChange.tooltip="Saving the settings can be an expensive operation if you are working with a very large scene collection.\nIn this case, it might make sense to disable this option."
|
||||
AdvSceneSwitcher.macroTab.currentCheckInParallel="Evaluate conditions of selected macro in parallel to other macros (Experimental)"
|
||||
AdvSceneSwitcher.macroTab.currentRegisterHotkeys="Register hotkeys to control the pause state of selected macro"
|
||||
AdvSceneSwitcher.macroTab.currentUseShortCircuitEvaluation="Enable short circuit evaluation of macro conditions for currently selected macro"
|
||||
AdvSceneSwitcher.macroTab.shortCircuit.tooltip="Enabling short circuit evaluation might improve the performance, as some condition checks are skipped, if the overall macro cannot be evaluated to \"true\" anymore.\nHowever, please note that condition checks, which are skipped over, will also not update their duration modifier checks."
|
||||
@@ -213,6 +232,8 @@ AdvSceneSwitcher.macroTab.pauseStateSaveBehavior.persist="The state the macro wa
|
||||
AdvSceneSwitcher.macroTab.pauseStateSaveBehavior.pause="Paused"
|
||||
AdvSceneSwitcher.macroTab.pauseStateSaveBehavior.unpause="Unpaused"
|
||||
AdvSceneSwitcher.macroTab.currentRegisterDock="Register dock widget to control the pause state of selected macro or run it manually"
|
||||
AdvSceneSwitcher.macroTab.currentIsStandaloneDock="Is standalone dock"
|
||||
AdvSceneSwitcher.macroTab.currentDockWindowName="Add to macro dock with name:"
|
||||
AdvSceneSwitcher.macroTab.currentDockAddRunButton="Add button to run the macro"
|
||||
AdvSceneSwitcher.macroTab.currentDockAddPauseButton="Add button to pause or unpause the macro"
|
||||
AdvSceneSwitcher.macroTab.currentDockAddStatusLabel="Add status label"
|
||||
@@ -305,10 +326,11 @@ AdvSceneSwitcher.condition.scene.type.previousPattern="Previous scene matches"
|
||||
AdvSceneSwitcher.condition.scene.type.previewPattern="Preview scene matches"
|
||||
AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="During transition check for transition target scene"
|
||||
AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="During transition check for transition source scene"
|
||||
AdvSceneSwitcher.condition.scene.canvasNotSupported="This check is not supported for the currently selected canvas \"%1\""
|
||||
AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
|
||||
AdvSceneSwitcher.condition.window="Window"
|
||||
AdvSceneSwitcher.condition.window.entry.window="{{checkTitle}}Window title matches{{windowRegex}}{{windows}}"
|
||||
AdvSceneSwitcher.condition.window.entry.window="{{checkTitle}}Window title matches{{windows}}{{windowRegex}}"
|
||||
AdvSceneSwitcher.condition.window.entry.fullscreen="{{fullscreen}}Window is fullscreen"
|
||||
AdvSceneSwitcher.condition.window.entry.maximized="{{maximized}}Window is maximized"
|
||||
AdvSceneSwitcher.condition.window.entry.focused="{{focused}}Window is focused"
|
||||
@@ -320,6 +342,9 @@ AdvSceneSwitcher.condition.file="File"
|
||||
AdvSceneSwitcher.condition.file.type.match="matches"
|
||||
AdvSceneSwitcher.condition.file.type.contentChange="content changed"
|
||||
AdvSceneSwitcher.condition.file.type.dateChange="modification date changed"
|
||||
AdvSceneSwitcher.condition.file.type.exists="exists"
|
||||
AdvSceneSwitcher.condition.file.type.isFile="is a file"
|
||||
AdvSceneSwitcher.condition.file.type.isFolder="is a folder"
|
||||
AdvSceneSwitcher.condition.file.remote="Remote file"
|
||||
AdvSceneSwitcher.condition.file.local="Local file"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
@@ -377,6 +402,13 @@ AdvSceneSwitcher.condition.video.patternMatchSuccessFullImage="Full image matche
|
||||
AdvSceneSwitcher.condition.video.objectMatchFail="Object was not found!"
|
||||
AdvSceneSwitcher.condition.video.objectMatchSuccess="Object is highlighted in red"
|
||||
AdvSceneSwitcher.condition.video.ocrMatchSuccess="Detected text:\n\n%1"
|
||||
AdvSceneSwitcher.condition.video.ocrMatchFail="Could not detect any text!"
|
||||
AdvSceneSwitcher.condition.video.ocrUseConfigFile="Use custom tesseract config file"
|
||||
AdvSceneSwitcher.condition.video.ocrOpenConfigFile="Open"
|
||||
AdvSceneSwitcher.condition.video.ocrOpenConfig.createFailed="Could not create the config file!"
|
||||
AdvSceneSwitcher.condition.video.ocrOpenConfig.openFailed="Could not open the config file!"
|
||||
AdvSceneSwitcher.condition.video.ocrConfigReload="Reload configuration file"
|
||||
AdvSceneSwitcher.condition.video.ocrConfigHint="Tesseract config files consist of lines with parameter-value pairs (space separated).\nFor example:\n\ntessedit_char_blacklist\t\t\t\t\"abc\"\nlanguage_model_penalty_non_dict_word\t0"
|
||||
AdvSceneSwitcher.condition.video.modelLoadFail="Model data could not be loaded!"
|
||||
AdvSceneSwitcher.condition.video.selectColor="Select Color"
|
||||
AdvSceneSwitcher.condition.video.ocrMode.singleColumn="Single column of text of variable sizes"
|
||||
@@ -396,16 +428,18 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="How similar
|
||||
AdvSceneSwitcher.condition.video.type.main="OBS's main output"
|
||||
AdvSceneSwitcher.condition.video.type.source="Source"
|
||||
AdvSceneSwitcher.condition.video.type.scene="Scene"
|
||||
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="Model data (haar cascade classifier):{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimum neighbors:{{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduce CPU load by performing check only every{{throttleCount}}milliseconds"
|
||||
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Perform check only in area"
|
||||
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcColorPick="Check for text color:{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcTextType="Check for text type:{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcLanguage="Check for language:{{languageCode}}"
|
||||
AdvSceneSwitcher.condition.video.entry.color="Check for color:{{color}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.modelPath="Model data (haar cascade classifier):{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.minNeighbor="Minimum neighbors:{{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduce CPU load by performing check only every{{throttleCount}}milliseconds"
|
||||
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Perform check only in area"
|
||||
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrColorPick="Check for text color:{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrTextType="Check for text type:{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrBaseDir="Tesseract base directory:{{tesseractBaseDir}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrLanguage="Check for language:{{languageCode}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrConfig="Config file:{{configFile}}{{openConfigFile}}{{reloadConfig}}{{configFileHint}}"
|
||||
AdvSceneSwitcher.condition.video.layout.color="Check for color:{{color}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.minSize="Minimum size:"
|
||||
AdvSceneSwitcher.condition.video.maxSize="Maximum size:"
|
||||
AdvSceneSwitcher.condition.video.selectArea="Select area"
|
||||
@@ -460,6 +494,7 @@ AdvSceneSwitcher.condition.macro.type.multiState="Multiple macro condition state
|
||||
AdvSceneSwitcher.condition.macro.type.actionDisabled="Macro action disabled"
|
||||
AdvSceneSwitcher.condition.macro.type.actionEnabled="Macro action enabled"
|
||||
AdvSceneSwitcher.condition.macro.type.paused="Macro is paused"
|
||||
AdvSceneSwitcher.condition.macro.type.actionsPerformed="Macro actions were executed"
|
||||
AdvSceneSwitcher.condition.macro.type.selection="{{types}}"
|
||||
AdvSceneSwitcher.condition.macro.count.type.below="Less than"
|
||||
AdvSceneSwitcher.condition.macro.count.type.above="More than"
|
||||
@@ -476,12 +511,14 @@ AdvSceneSwitcher.condition.macro.count.entry.line2="Current count:{{currentCount
|
||||
AdvSceneSwitcher.condition.macro.actionState.disabled.entry="Action{{actionIndex}}of{{macros}}is disabled"
|
||||
AdvSceneSwitcher.condition.macro.actionState.enabled.entry="Action{{actionIndex}}of{{macros}}is enabled"
|
||||
AdvSceneSwitcher.condition.macro.paused.entry="Macro{{macros}}is paused"
|
||||
AdvSceneSwitcher.condition.macro.actionsPerformed.entry="The actions of macro{{macros}}were performed"
|
||||
AdvSceneSwitcher.condition.source="Source"
|
||||
AdvSceneSwitcher.condition.source.type.active="Is active"
|
||||
AdvSceneSwitcher.condition.source.type.showing="Is showing"
|
||||
AdvSceneSwitcher.condition.source.type.settingsMatch="Settings match"
|
||||
AdvSceneSwitcher.condition.source.type.settingsChanged="Settings changed"
|
||||
AdvSceneSwitcher.condition.source.type.individualSettingMatches="Setting value matches"
|
||||
AdvSceneSwitcher.condition.source.type.individualSettingListSelectionMatches="Settings value list selection matches"
|
||||
AdvSceneSwitcher.condition.source.type.individualSettingChanged="Setting value changed"
|
||||
AdvSceneSwitcher.condition.source.type.width="Width"
|
||||
AdvSceneSwitcher.condition.source.type.height="Height"
|
||||
@@ -490,6 +527,7 @@ AdvSceneSwitcher.condition.source.sizeCompare.equal="Equals"
|
||||
AdvSceneSwitcher.condition.source.sizeCompare.more="Bigger than"
|
||||
AdvSceneSwitcher.condition.source.refresh="Refresh"
|
||||
AdvSceneSwitcher.condition.source.refresh.tooltip="Repopulate the source settings selection with the settings of the source which's name matches the variable value."
|
||||
AdvSceneSwitcher.condition.source.includeDefaults="Include default settings values"
|
||||
AdvSceneSwitcher.condition.source.sceneVisibilityHint="Scene specific visibility can be checked using the \"Scene item visibility\" condition"
|
||||
AdvSceneSwitcher.condition.source.getSettings="Get current settings"
|
||||
AdvSceneSwitcher.condition.source.entry.line1="{{sources}}{{conditions}}{{settingSelection}}{{refresh}}{{sizeCompareMethods}}{{size}}"
|
||||
@@ -505,9 +543,11 @@ AdvSceneSwitcher.condition.filter.type.showing="Is disabled"
|
||||
AdvSceneSwitcher.condition.filter.type.settingsMatch="Settings match"
|
||||
AdvSceneSwitcher.condition.filter.type.settingsChanged="Settings changed"
|
||||
AdvSceneSwitcher.condition.filter.type.individualSettingMatches="Settings value matches"
|
||||
AdvSceneSwitcher.condition.filter.type.individualSettingListSelectionMatches="Settings value list selection matches"
|
||||
AdvSceneSwitcher.condition.filter.type.individualSettingChanged="Settings value changed"
|
||||
AdvSceneSwitcher.condition.filter.refresh="Refresh"
|
||||
AdvSceneSwitcher.condition.filter.refresh.tooltip="Repopulate the filter settings selection with the settings of the filter which's name matches the variable value."
|
||||
AdvSceneSwitcher.condition.filter.includeDefaults="Include default settings values"
|
||||
AdvSceneSwitcher.condition.filter.getSettings="Get current settings"
|
||||
AdvSceneSwitcher.condition.filter.entry.line1="On{{sources}}{{filters}}{{conditions}}{{settingSelection}}{{refresh}}"
|
||||
AdvSceneSwitcher.condition.filter.entry.line2="{{settings}}"
|
||||
@@ -668,6 +708,7 @@ AdvSceneSwitcher.condition.twitch.type.event.channel.raid.outbound="Raided someo
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.raid.inbound="Raid to your channel occured"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.shoutout.outbound="Shoutout to someone's channel given"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.shoutout.inbound="Shoutout to your channel received"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.commercial.start="Commercial break started"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.poll.start="Poll started"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.poll.progress="Poll votes changed (progress)"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.poll.end="Poll ended"
|
||||
@@ -705,6 +746,8 @@ AdvSceneSwitcher.condition.twitch.type.polling.channel.live="Stream is currently
|
||||
AdvSceneSwitcher.condition.twitch.type.polling.channel.title="Current title matches"
|
||||
AdvSceneSwitcher.condition.twitch.type.polling.channel.category="Current category is"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.message="Chat message received"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.messageRemoved="Single chat message removed"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.cleared="All messages of user or channel cleared"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties="Chat message properties:"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties.select="Select chat message property:"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties.firstMessage="Is first message"
|
||||
@@ -771,19 +814,31 @@ AdvSceneSwitcher.condition.streamDeck.stopListen="Stop listening"
|
||||
AdvSceneSwitcher.condition.streamDeck.pluginDownload="<html><head/><body><p>The Stream Deck plugin can be found <a href=\"https://github.com/WarmUpTill/advanced-scene-switcher-streamdeck-plugin/releases\"><span style=\" text-decoration: underline; color:#268bd2;\">here on GitHub</span></a>.</p></body></html>"
|
||||
AdvSceneSwitcher.condition.gameCapture="Game capture"
|
||||
AdvSceneSwitcher.condition.gameCapture.entry="{{sources}}hooked a game."
|
||||
|
||||
AdvSceneSwitcher.condition.screenshot="Screenshot"
|
||||
AdvSceneSwitcher.condition.screenshot.entry="A screenshot was taken"
|
||||
AdvSceneSwitcher.condition.mqtt="MQTT"
|
||||
AdvSceneSwitcher.condition.mqtt.layout.match="Message was received from{{connection}} which matches{{regex}}:"
|
||||
AdvSceneSwitcher.condition.mqtt.layout.listen="Set message selection to incoming message:{{listenButton}}"
|
||||
AdvSceneSwitcher.condition.script="Script"
|
||||
|
||||
# Macro Actions
|
||||
AdvSceneSwitcher.action.unknown="Unknown action"
|
||||
AdvSceneSwitcher.action.scene="Switch scene"
|
||||
AdvSceneSwitcher.action.scene.action.fixed="Scene with name"
|
||||
AdvSceneSwitcher.action.scene.action.sceneListNext="Next scene in scene list"
|
||||
AdvSceneSwitcher.action.scene.action.sceneListPrevious="Previous scene in scene list"
|
||||
AdvSceneSwitcher.action.scene.action.sceneListIndex="Scene in scene list at position"
|
||||
AdvSceneSwitcher.action.scene.type.program="Program"
|
||||
AdvSceneSwitcher.action.scene.type.preview="Preview"
|
||||
AdvSceneSwitcher.action.scene.entry="Switch{{sceneTypes}}scene to{{scenes}}using{{transitions}}with a duration of{{duration}}seconds"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Switch{{sceneTypes}}scene to{{scenes}}using{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.entry.preview="Switch{{sceneTypes}}scene to{{scenes}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.fixed="Switch{{sceneTypes}}to{{actions}}{{scenes}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.list="Switch{{sceneTypes}}to{{actions}}on{{canvas}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.list.noCanvasSelection="Switch{{sceneTypes}}to{{actions}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.listIndex="Switch{{sceneTypes}}to{{actions}}{{index}}on{{canvas}}{{sceneNameAtIndex}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.listIndex.noCanvasSelection="Switch{{sceneTypes}}to{{actions}}{{index}}{{sceneNameAtIndex}}"
|
||||
AdvSceneSwitcher.action.scene.layout.transition="Use transition{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.layout.transitionWithDuration="Use transition{{transitions}}with a duration of{{duration}}seconds"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Wait until transition to target scene is complete"
|
||||
AdvSceneSwitcher.action.scene.canvasNotSupported="Not supported by the currently selected canvas \"%1\""
|
||||
AdvSceneSwitcher.action.wait="Wait"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fixed"
|
||||
AdvSceneSwitcher.action.wait.type.random="random"
|
||||
@@ -792,6 +847,7 @@ AdvSceneSwitcher.action.wait.entry.random="Wait for{{waitType}}duration from{{du
|
||||
AdvSceneSwitcher.action.audio="Audio"
|
||||
AdvSceneSwitcher.action.audio.type.mute="Mute"
|
||||
AdvSceneSwitcher.action.audio.type.unmute="Unmute"
|
||||
AdvSceneSwitcher.action.audio.type.toggleMute="Toggle mute"
|
||||
AdvSceneSwitcher.action.audio.type.sourceVolume="Set source volume"
|
||||
AdvSceneSwitcher.action.audio.type.masterVolume="Set master volume"
|
||||
AdvSceneSwitcher.action.audio.type.syncOffset="Set sync offset"
|
||||
@@ -857,6 +913,7 @@ AdvSceneSwitcher.action.filter.entry="On{{sources}}{{actions}}{{filters}}{{refre
|
||||
AdvSceneSwitcher.action.filter.entry.settings="{{settings}}{{settingsInputMethod}}{{settingValue}}{{tempVar}}"
|
||||
AdvSceneSwitcher.action.filter.getSettings="Get current settings"
|
||||
AdvSceneSwitcher.action.filter.inputMethod.individualManual="Set to fixed value"
|
||||
AdvSceneSwitcher.action.filter.inputMethod.individualListEntryManual="Set to list entry"
|
||||
AdvSceneSwitcher.action.filter.inputMethod.individualTempvar="Set to macro property"
|
||||
AdvSceneSwitcher.action.filter.inputMethod.json="Set setting JSON string"
|
||||
AdvSceneSwitcher.action.source="Source"
|
||||
@@ -887,6 +944,7 @@ AdvSceneSwitcher.action.source.deinterlaceMode.yadif2x="Yadif 2x"
|
||||
AdvSceneSwitcher.action.source.deinterlaceOrder.topFieldFirst="Top Field First"
|
||||
AdvSceneSwitcher.action.source.deinterlaceOrder.bottomFieldFirst="Bottom Field First"
|
||||
AdvSceneSwitcher.action.source.inputMethod.individualManual="Set to fixed value"
|
||||
AdvSceneSwitcher.action.source.inputMethod.individualListEntryManual="Set to list entry"
|
||||
AdvSceneSwitcher.action.source.inputMethod.individualTempvar="Set to macro property"
|
||||
AdvSceneSwitcher.action.source.inputMethod.json="Set setting JSON string"
|
||||
AdvSceneSwitcher.action.source.refresh="Refresh"
|
||||
@@ -908,6 +966,7 @@ AdvSceneSwitcher.action.media.seek.percentage.label="Percentage of total duratio
|
||||
AdvSceneSwitcher.action.macro="Macro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pause"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Unpause"
|
||||
AdvSceneSwitcher.action.macro.type.togglePause="Toggle pause"
|
||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter"
|
||||
AdvSceneSwitcher.action.macro.type.run="Run macro"
|
||||
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Do not consider condition state"
|
||||
@@ -924,6 +983,10 @@ AdvSceneSwitcher.action.macro.type.stop="Stop actions"
|
||||
AdvSceneSwitcher.action.macro.type.disableAction="Disable action"
|
||||
AdvSceneSwitcher.action.macro.type.enableAction="Enable action"
|
||||
AdvSceneSwitcher.action.macro.type.toggleAction="Toggle action"
|
||||
AdvSceneSwitcher.action.macro.type.nestedMacro="Nested macro"
|
||||
AdvSceneSwitcher.action.macro.type.nestedMacro.conditionHelp="This section allows you to define macro conditions.\n\nClick the plus button below to add a new condition."
|
||||
AdvSceneSwitcher.action.macro.type.nestedMacro.actionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are met.\n\nClick the plus button below to add a new action."
|
||||
AdvSceneSwitcher.action.macro.type.nestedMacro.elseActionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are *not* met.\n\nClick the plus button below to add a new action."
|
||||
AdvSceneSwitcher.action.macro.entry.run="{{actions}}{{actionTypes}}of{{macros}}"
|
||||
AdvSceneSwitcher.action.macro.entry.run.condition="{{conditionBehaviors}}of{{conditionMacros}}"
|
||||
AdvSceneSwitcher.action.macro.entry.other="{{actions}}{{actionIndex}}{{macros}}"
|
||||
@@ -934,7 +997,11 @@ AdvSceneSwitcher.action.pluginState.type.import="Import settings from"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Note: Action will be ignored while settings window is opened."
|
||||
AdvSceneSwitcher.action.pluginState.type.terminate="Shut down OBS"
|
||||
AdvSceneSwitcher.action.pluginState.terminateConfirm="OBS will be shut down automatically in 10 seconds!\nDo you want to continue shutting down OBS?"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.type.enableMacroHighlighting="Enable macro highlighting"
|
||||
AdvSceneSwitcher.action.pluginState.type.disableMacroHighlighting="Disable macro highlighting"
|
||||
AdvSceneSwitcher.action.pluginState.type.toggleMacroHighlighting="Toggle macro highlighting"
|
||||
AdvSceneSwitcher.action.pluginState.confirmShutdown="Ask for shutdown confirmation"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Virtual camera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Stop virtual camera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Start virtual camera"
|
||||
@@ -1045,7 +1112,7 @@ AdvSceneSwitcher.action.websocket.api.genericWebsocket="Generic websocket messag
|
||||
AdvSceneSwitcher.action.websocket.type.request="Request"
|
||||
AdvSceneSwitcher.action.websocket.type.event="Event"
|
||||
AdvSceneSwitcher.action.websocket.settingsConflictGeneric="Possible settings conflict: Generic websocket message selection with connection which follows the OBS protocol!"
|
||||
AdvSceneSwitcher.action.websocket.settingsConflictOBS="Possible settings conflict: Connection selected which only supports generic websockte messages while message type requires OBS protocol!"
|
||||
AdvSceneSwitcher.action.websocket.settingsConflictOBS="Possible settings conflict: Connection selected which only supports generic websocket messages while message type requires OBS protocol!"
|
||||
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.request="Send{{api}}of type{{type}}via{{connection}}"
|
||||
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.event="Send{{api}}of type{{type}}to connected clients"
|
||||
AdvSceneSwitcher.action.websocket.entry.generic="Send{{api}}via{{connection}}"
|
||||
@@ -1066,7 +1133,7 @@ AdvSceneSwitcher.action.http.type.post="POST"
|
||||
AdvSceneSwitcher.action.http.type.put="PUT"
|
||||
AdvSceneSwitcher.action.http.type.patch="PATCH"
|
||||
AdvSceneSwitcher.action.http.type.delete="DELETE"
|
||||
AdvSceneSwitcher.action.http.layout.method="Send{{method}}to URL{{url}}at path{{path}}"
|
||||
AdvSceneSwitcher.action.http.layout.method="Send{{method}}to URL{{url}}"
|
||||
AdvSceneSwitcher.action.http.layout.contentType="Content type:{{contentType}}"
|
||||
AdvSceneSwitcher.action.http.layout.timeout="Timeout:{{timeout}}seconds"
|
||||
AdvSceneSwitcher.action.http.entry.line1="Send{{method}}to{{url}}"
|
||||
@@ -1087,7 +1154,10 @@ AdvSceneSwitcher.action.variable.type.askForValue="Get user input"
|
||||
AdvSceneSwitcher.action.variable.type.environmentVariable="Set to environment variable value"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemCount="Set to scene item count of scene"
|
||||
AdvSceneSwitcher.action.variable.type.stringLength="Set to length of string"
|
||||
AdvSceneSwitcher.action.variable.type.extractJson="Extract json field with name"
|
||||
AdvSceneSwitcher.action.variable.type.extractJsonField="Extract JSON field with name"
|
||||
AdvSceneSwitcher.action.variable.type.queryJson="Query JSON"
|
||||
AdvSceneSwitcher.action.variable.type.queryJson.info="You can use \"JSONPath\" (RFC 9535) syntax here.\nSo, for example:\n\n • $['books'][0]['category']\n • $.books[0].category\n\nIf the query or the JSON should be invalid, the variable value will not be changed.\nIf the input is valid, the result of the query will always be a JSON array."
|
||||
AdvSceneSwitcher.action.variable.type.accessJsonArray="Access JSON array at index"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar="Set to macro property"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar.help="This action type will allow you to extract values out of segments of the current macro and assign those values to the selected variable.\nFor example, you can get the current scene name from a scene condition and assign this name to a variable."
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemName="Set to scene item name at index"
|
||||
@@ -1116,15 +1186,15 @@ AdvSceneSwitcher.action.variable.invalidSelection="Invalid selection!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Getting variable values from %1 actions is not supported!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Getting variable values from %1 conditions is not supported!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Current value:"
|
||||
AdvSceneSwitcher.action.variable.entry.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}{{caseType}}"
|
||||
AdvSceneSwitcher.action.variable.entry.pad="{{actions}}of{{variables}}to length{{stringLength}}by adding{{paddingCharSelection}}to the{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.entry.truncate="{{actions}}of{{variables}}to length{{stringLength}}by removing characters from the{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
|
||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}Use custom prompt{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}Fill with placeholder{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.entry.randomNumber="Generate random number in range from{{randomNumberStart}}to{{randomNumberEnd}}"
|
||||
AdvSceneSwitcher.action.variable.layout.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}{{caseType}}{{jsonQuery}}{{jsonQueryHelp}}{{jsonIndex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}of{{variables}}to length{{stringLength}}by adding{{paddingCharSelection}}to the{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}of{{variables}}to length{{stringLength}}by removing characters from the{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
|
||||
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Use custom prompt{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Fill with placeholder{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.layout.randomNumber="Generate random number in range from{{randomNumberStart}}to{{randomNumberEnd}}"
|
||||
AdvSceneSwitcher.action.projector="Projector"
|
||||
AdvSceneSwitcher.action.projector.action.open="Open"
|
||||
AdvSceneSwitcher.action.projector.action.close="Close"
|
||||
@@ -1151,6 +1221,8 @@ AdvSceneSwitcher.action.sceneLock.entry="On{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.twitch="Twitch"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.title.set="Set stream title"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.category.set="Set stream category"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.tags.set="Set stream tags"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.language.set="Set stream language"
|
||||
AdvSceneSwitcher.action.twitch.type.raid.start="Start raid"
|
||||
AdvSceneSwitcher.action.twitch.type.commercial.start="Start commercial"
|
||||
AdvSceneSwitcher.action.twitch.type.marker.create="Create stream marker"
|
||||
@@ -1178,6 +1250,58 @@ AdvSceneSwitcher.action.twitch.announcement.orange="Orange"
|
||||
AdvSceneSwitcher.action.twitch.announcement.purple="Purple"
|
||||
AdvSceneSwitcher.action.twitch.user.getInfo.queryType.id="User Id"
|
||||
AdvSceneSwitcher.action.twitch.user.getInfo.queryType.login="User login"
|
||||
AdvSceneSwitcher.action.twitch.tags.add="Add Channel Tag"
|
||||
AdvSceneSwitcher.action.twitch.tags.getCurrent="Get current channel tags"
|
||||
AdvSceneSwitcher.action.twitch.tags.invalid="Invalid Tag"
|
||||
AdvSceneSwitcher.action.twitch.tags.invalid.info="Tags must be 1–%1 characters long, contain only letters or numbers, and have no spaces or special characters."
|
||||
AdvSceneSwitcher.action.twitch.tags.duplicate="Duplicate Tag"
|
||||
AdvSceneSwitcher.action.twitch.tags.duplicate.info="This tag is already in the list."
|
||||
AdvSceneSwitcher.action.twitch.tags.limit="Tag Limit Reached"
|
||||
AdvSceneSwitcher.action.twitch.tags.limit.info="You can only have up to %1 tags."
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.contentClassification.set="Set content classification labels"
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.debatedSocialIssuesAndPolitics="Discussions or debates about politics or sensitive social issues such as elections, civic integrity, military conflict, and civil rights."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.drugsIntoxication="Excessive tobacco glorification or promotion, any marijuana consumption/use, legal drug and alcohol induced intoxication, discussions of illegal drugs."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.sexualThemes="Content that focuses on sexualized activities, sexual topics, or experiences."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.violentGraphic="Simulations and/or depictions of realistic violence, gore, extreme injury, or death."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.gambling="Participating in or promoting online or in-person gambling, poker, or fantasy sports that involve the exchange of real money."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.profanityVulgarity="Prolonged and repeated use of obscenities, profanities, and vulgarities, especially as a regular part of speech."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.getCurrent="Get current content classification labels"
|
||||
AdvSceneSwitcher.action.twitch.language.english="English"
|
||||
AdvSceneSwitcher.action.twitch.language.indonesian="Bahasa Indonesia"
|
||||
AdvSceneSwitcher.action.twitch.language.catalan="Català"
|
||||
AdvSceneSwitcher.action.twitch.language.danish="Dansk"
|
||||
AdvSceneSwitcher.action.twitch.language.german="Deutsch"
|
||||
AdvSceneSwitcher.action.twitch.language.spanish="Español"
|
||||
AdvSceneSwitcher.action.twitch.language.french="Français"
|
||||
AdvSceneSwitcher.action.twitch.language.italian="Italiano"
|
||||
AdvSceneSwitcher.action.twitch.language.hungarian="Magyar"
|
||||
AdvSceneSwitcher.action.twitch.language.dutch="Nederlands"
|
||||
AdvSceneSwitcher.action.twitch.language.norwegian="Norsk"
|
||||
AdvSceneSwitcher.action.twitch.language.polish="Polski"
|
||||
AdvSceneSwitcher.action.twitch.language.portuguese="Português"
|
||||
AdvSceneSwitcher.action.twitch.language.romanian="Română"
|
||||
AdvSceneSwitcher.action.twitch.language.slovak="Slovenčina"
|
||||
AdvSceneSwitcher.action.twitch.language.finnish="Suomi"
|
||||
AdvSceneSwitcher.action.twitch.language.swedish="Svenska"
|
||||
AdvSceneSwitcher.action.twitch.language.tagalog="Tagalog"
|
||||
AdvSceneSwitcher.action.twitch.language.vietnamese="Tiếng Việt"
|
||||
AdvSceneSwitcher.action.twitch.language.turkish="Türkçe"
|
||||
AdvSceneSwitcher.action.twitch.language.czech="Čeština"
|
||||
AdvSceneSwitcher.action.twitch.language.greek="Ελληνικά"
|
||||
AdvSceneSwitcher.action.twitch.language.bulgarian="Български"
|
||||
AdvSceneSwitcher.action.twitch.language.russian="Русский"
|
||||
AdvSceneSwitcher.action.twitch.language.ukrainian="Українська"
|
||||
AdvSceneSwitcher.action.twitch.language.arabic="العربية"
|
||||
AdvSceneSwitcher.action.twitch.language.malay="بهاس ملايو"
|
||||
AdvSceneSwitcher.action.twitch.language.hindi="मानक हिन्दी"
|
||||
AdvSceneSwitcher.action.twitch.language.thai="ภาษาไทย"
|
||||
AdvSceneSwitcher.action.twitch.language.chinese="中文"
|
||||
AdvSceneSwitcher.action.twitch.language.japanese="日本語"
|
||||
AdvSceneSwitcher.action.twitch.language.cantonese="粵語"
|
||||
AdvSceneSwitcher.action.twitch.language.korean="한국어"
|
||||
AdvSceneSwitcher.action.twitch.language.asl="American Sign Language"
|
||||
AdvSceneSwitcher.action.twitch.language.other="Other"
|
||||
AdvSceneSwitcher.action.twitch.language.getCurrent="Get current language"
|
||||
AdvSceneSwitcher.action.clipboard="Clipboard"
|
||||
AdvSceneSwitcher.action.clipboard.type.copy.text="Copy text"
|
||||
AdvSceneSwitcher.action.clipboard.type.copy.image="Copy image"
|
||||
@@ -1202,6 +1326,27 @@ AdvSceneSwitcher.action.window.entry="{{actions}}{{windows}}{{regex}}"
|
||||
AdvSceneSwitcher.action.log="Log"
|
||||
AdvSceneSwitcher.action.log.placeholder="My log message!"
|
||||
AdvSceneSwitcher.action.log.entry="Write to OBS log:{{logMessage}}"
|
||||
AdvSceneSwitcher.action.mqtt="MQTT"
|
||||
AdvSceneSwitcher.action.mqtt.topic="Topic:"
|
||||
AdvSceneSwitcher.action.mqtt.qos="QoS:"
|
||||
AdvSceneSwitcher.action.mqtt.retain="Retained message:"
|
||||
AdvSceneSwitcher.action.mqtt.layout="Send message to{{connection}}"
|
||||
AdvSceneSwitcher.action.obsSetting="OBS setting"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setFPSType="Set FPS selection type to"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setFPSCommonValue="Set FPS common selection to"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setFPSIntegerValue="Set FPS integer selection to"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setFPSFractionNumeratorValue="Set fractional FPS numerator selection to"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setFPSFractionDenominatorValue="Set fractional FPS denominator selection to"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setBaseCanvasX="Set base resolution X value"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setBaseCanvasY="Set base resolution Y value"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setOutputCanvasX="Set output resolution X value"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setOutputCanvasY="Set output resolution Y value"
|
||||
AdvSceneSwitcher.action.obsSetting.action.enablePreview="Enable preview"
|
||||
AdvSceneSwitcher.action.obsSetting.action.disablePreview="Disable preview"
|
||||
AdvSceneSwitcher.action.obsSetting.action.togglePreview="Toggle preview enable"
|
||||
AdvSceneSwitcher.action.obsSetting.getCurrentValue="Get current value"
|
||||
AdvSceneSwitcher.action.obsSettings.layout="{{actions}}{{fpsType}}{{fpsIntValue}}{{fpsStringValue}}{{canvasSizeValue}}{{getCurrentValue}}"
|
||||
AdvSceneSwitcher.action.script="Script"
|
||||
|
||||
# Hotkey
|
||||
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher"
|
||||
@@ -1210,9 +1355,10 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Toggle Start/Stop for the
|
||||
AdvSceneSwitcher.hotkey.macro.pause="Pause macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.unpause="Unpause macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.togglePause="Toggle pause of macro %1"
|
||||
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Move macro segment selection up"
|
||||
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Move macro segment selection down"
|
||||
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Remove selected macro segment"
|
||||
AdvSceneSwitcher.hotkey.macro.new="Add new macro"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.up="Move macro segment selection up"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.down="Move macro segment selection down"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.remove="Remove selected macro segment"
|
||||
|
||||
AdvSceneSwitcher.askBackup="Detected a new version of the Advanced Scene Switcher.\nShould a backup of the old settings be created?"
|
||||
AdvSceneSwitcher.askForMacro="Select macro{{macroSelection}}"
|
||||
@@ -1358,6 +1504,35 @@ AdvSceneSwitcher.osc.message.type.false="False"
|
||||
AdvSceneSwitcher.osc.message.type.infinity="Infinitum"
|
||||
AdvSceneSwitcher.osc.message.type.null="Nil"
|
||||
|
||||
AdvSceneSwitcher.mqttConnection.startListen="Start listening"
|
||||
AdvSceneSwitcher.mqttConnection.stopListen="Stop listening"
|
||||
AdvSceneSwitcher.mqttConnection.select="--select connection--"
|
||||
AdvSceneSwitcher.mqttConnection.add="Add new connection"
|
||||
AdvSceneSwitcher.mqttConnection.configure="Configure connection settings"
|
||||
AdvSceneSwitcher.mqttConnection.invalid="Invalid connection selection"
|
||||
AdvSceneSwitcher.mqttConnection.name="Name:"
|
||||
AdvSceneSwitcher.mqttConnection.address="Address:"
|
||||
AdvSceneSwitcher.mqttConnection.username="Username:"
|
||||
AdvSceneSwitcher.mqttConnection.password="Password:"
|
||||
AdvSceneSwitcher.mqttConnection.reconnect="Reconnect automatically:"
|
||||
AdvSceneSwitcher.mqttConnection.reconnectDelay="Automatically reconnect after:"
|
||||
AdvSceneSwitcher.mqttConnection.connectOnStart="Connect on startup:"
|
||||
AdvSceneSwitcher.mqttConnection.test="Test connection"
|
||||
AdvSceneSwitcher.mqttConnection.status.connected="Connected!"
|
||||
AdvSceneSwitcher.mqttConnection.status.connecting="Connecting ..."
|
||||
AdvSceneSwitcher.mqttConnection.status.disconnected="Could not connect!"
|
||||
AdvSceneSwitcher.mqttConnection.topic="Topic"
|
||||
AdvSceneSwitcher.mqttConnection.qos="QoS"
|
||||
AdvSceneSwitcher.mqttConnection.topics="Topic subscriptions:"
|
||||
AdvSceneSwitcher.mqttConnection.inputWarning.emptyTopic="Topic cannot be empty."
|
||||
AdvSceneSwitcher.mqttConnection.inputWarning.emptyTopic.title="Input Error"
|
||||
AdvSceneSwitcher.mqttConnection.inputWarning.duplicateTopic="This topic already exists."
|
||||
AdvSceneSwitcher.mqttConnection.inputWarning.duplicateTopic.title="Duplicate Topic"
|
||||
AdvSceneSwitcher.mqttConnection.inputWarning.qosRange="QoS must be 0, 1, or 2."
|
||||
AdvSceneSwitcher.mqttConnection.inputWarning.qosRange.title="Invalid QoS"
|
||||
AdvSceneSwitcher.mqttConnection.add.layout="Add topic subscription{{topic}}with QoS{{QoS}}"
|
||||
AdvSceneSwitcher.mqttConnection.add.title="Add MQTT Topic Subscription"
|
||||
|
||||
AdvSceneSwitcher.twitchToken.name="Account name:"
|
||||
AdvSceneSwitcher.twitchToken.nameNotAvailable="Account already in use"
|
||||
AdvSceneSwitcher.twitchToken.select="--select Twitch connection--"
|
||||
@@ -1384,6 +1559,7 @@ AdvSceneSwitcher.twitchToken.bits.read="Read channel's Bits information."
|
||||
AdvSceneSwitcher.twitchToken.channel.raids.manage="Manage channel's raids."
|
||||
AdvSceneSwitcher.twitchToken.moderator.shoutouts.read="Read channel's shoutouts."
|
||||
AdvSceneSwitcher.twitchToken.moderator.shoutouts.manage="Manage channel's shoutouts."
|
||||
AdvSceneSwitcher.twitchToken.channel.ads.read="Read the ads schedule and details on your channel."
|
||||
AdvSceneSwitcher.twitchToken.channel.polls.read="Read channel's polls' state."
|
||||
AdvSceneSwitcher.twitchToken.channel.polls.manage="Manage channel's polls."
|
||||
AdvSceneSwitcher.twitchToken.channel.predictions.read="Read channel's predictions' state."
|
||||
@@ -1409,6 +1585,7 @@ AdvSceneSwitcher.twitchToken.moderator.chat.settings.manage="Manage channel's ch
|
||||
AdvSceneSwitcher.twitchToken.user.whispers.manage="Manage user's whispers."
|
||||
AdvSceneSwitcher.twitchToken.chat.read="View live stream chat messages."
|
||||
AdvSceneSwitcher.twitchToken.chat.edit="Send live stream chat messages."
|
||||
AdvSceneSwitcher.twitchToken.validateTimestamps="Validate timestamps of received Twitch event messages. (Recommended)"
|
||||
|
||||
AdvSceneSwitcher.twitch.selection.channel.open="Open channel"
|
||||
AdvSceneSwitcher.twitch.selection.channel.open.tooltip.details="Open channel in external application handling the HTTPS protocol."
|
||||
@@ -1435,6 +1612,20 @@ AdvSceneSwitcher.twitch.selection.points.reward.tooltip.noPermission="Can't sele
|
||||
AdvSceneSwitcher.twitch.selection.points.reward.tooltip.noChannel="Can't select points reward without entering a channel first!"
|
||||
AdvSceneSwitcher.twitch.selection.points.reward.tooltip.error="Can't select points reward because Twitch responded with an error! Check OBS logs for more details."
|
||||
|
||||
AdvSceneSwitcher.script.type.inline="Inline"
|
||||
AdvSceneSwitcher.script.type.file="File"
|
||||
AdvSceneSwitcher.script.type.layout="Script type:{{scriptType}}"
|
||||
AdvSceneSwitcher.script.language.python="Python"
|
||||
AdvSceneSwitcher.script.language.lua="LUA"
|
||||
AdvSceneSwitcher.script.language.select="--select language--"
|
||||
AdvSceneSwitcher.script.language.layout="Script language:{{language}}"
|
||||
AdvSceneSwitcher.script.file.open="Open"
|
||||
AdvSceneSwitcher.script.file.open.failed="Could not open script file!"
|
||||
AdvSceneSwitcher.script.file.warning.notFound="Warning: The given file path was not found!"
|
||||
AdvSceneSwitcher.script.file.warning.openFail="Warning: Could not open the script file!"
|
||||
AdvSceneSwitcher.script.file.warning.loadMissing="Warning: The script is missing a 'script_load' function!"
|
||||
AdvSceneSwitcher.script.file.layout="Script file:{{path}}{{open}}"
|
||||
|
||||
AdvSceneSwitcher.tempVar.select="--select value--"
|
||||
AdvSceneSwitcher.tempVar.selectionInfo.lastValues="Last values:"
|
||||
|
||||
@@ -1828,6 +2019,24 @@ AdvSceneSwitcher.tempVar.twitch.is_turbo.chatReceive.description="'true' if the
|
||||
AdvSceneSwitcher.tempVar.twitch.is_vip.chatReceive="Is chatter a VIP"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_vip.chatReceive.description="'true' if the chatter is a VIP in the channel, 'false' otherwise."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.login.chatRemove="User login"
|
||||
AdvSceneSwitcher.tempVar.twitch.login.chatRemove.description="The name of the user who sent the message."
|
||||
AdvSceneSwitcher.tempVar.twitch.message.chatRemove="Chat message"
|
||||
AdvSceneSwitcher.tempVar.twitch.message_id.chatRemove.description="The chat message that was removed."
|
||||
AdvSceneSwitcher.tempVar.twitch.message_id.chatRemove="Chat message ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.message_id.chatRemove.description="The ID of the message in UUID format."
|
||||
AdvSceneSwitcher.tempVar.twitch.timestamp.chatRemove="Chat message timestamp"
|
||||
AdvSceneSwitcher.tempVar.twitch.timestamp.chatRemove.description="The UNIX timestamp."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.login.chatClear="User login"
|
||||
AdvSceneSwitcher.tempVar.twitch.login.chatClear.description="The login name of the user whose messages were removed from the chat room because they were banned or put in a timeout."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.chatClear="User ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.chatClear.description="Optional.\nThe User ID of the user that was banned or put in a timeout.\nEmpty in case the complete chat was cleared."
|
||||
AdvSceneSwitcher.tempVar.twitch.ban_duration.chatClear="Ban duration"
|
||||
AdvSceneSwitcher.tempVar.twitch.ban_duration.chatClear.description="Set to zero if the complete chat was cleared or a user was banned indefinitely.\nIs set to non-zero value, if a user was put in a timeout.\nWill contain the duration of the timeout in seconds."
|
||||
AdvSceneSwitcher.tempVar.twitch.timestamp.chatClear="Timestamp"
|
||||
AdvSceneSwitcher.tempVar.twitch.timestamp.chatClear.description="The UNIX timestamp."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.chatJoin="User login"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.chatJoin.description="The user login of the person who joined the chat room."
|
||||
|
||||
@@ -1866,6 +2075,18 @@ AdvSceneSwitcher.tempVar.twitch.offline_image_url.user.getInfo="Offline image UR
|
||||
AdvSceneSwitcher.tempVar.twitch.created_at.user.getInfo="Account creation date"
|
||||
AdvSceneSwitcher.tempVar.twitch.created_at.user.getInfo.description="The UTC date and time that the user's account was created. The timestamp is in RFC3339 format."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.duration_seconds.commercial="Duration"
|
||||
AdvSceneSwitcher.tempVar.twitch.duration_seconds.commercial.description="Length in seconds of the mid-roll ad break requested."
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.commercial="Started at"
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.commercial.description="The UTC timestamp of when the ad break began, in RFC3339 format. Note that there is potential delay between this event, when the streamer requested the ad break, and when the viewers will see ads."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_automatic.commercial="Was automatic"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_automatic.commercial.description="Indicates if the ad was automatically scheduled via Ads Manager"
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_id.commercial="Requester user ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_id.commercial.description="The ID of the user that requested the ad. For automatic ads, this will be the ID of the broadcaster."
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_login.commercial="Requester user login"
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_login.commercial.description="The login of the user that requested the ad."
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_name.commercial="Requester user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_name.commercial.description="The display name of the user that requested the ad."
|
||||
|
||||
AdvSceneSwitcher.tempVar.audio.output_volume="Output volume"
|
||||
AdvSceneSwitcher.tempVar.audio.output_volume.description="The volume the audio source is outputting."
|
||||
@@ -1884,6 +2105,7 @@ AdvSceneSwitcher.tempVar.clipboard.mimeType.all.description="All MIME types of t
|
||||
AdvSceneSwitcher.tempVar.scene.current="Current scene"
|
||||
AdvSceneSwitcher.tempVar.scene.previous="Previous scene"
|
||||
AdvSceneSwitcher.tempVar.scene.preview="Preview scene"
|
||||
AdvSceneSwitcher.tempVar.scene.position="Position in scenes list"
|
||||
|
||||
AdvSceneSwitcher.tempVar.window.window="Window title"
|
||||
AdvSceneSwitcher.tempVar.window.window.description="The window title of the matching window."
|
||||
@@ -1967,6 +2189,19 @@ AdvSceneSwitcher.tempVar.clipboard.text.description="The text contained in the c
|
||||
|
||||
AdvSceneSwitcher.tempVar.file.content="File content"
|
||||
AdvSceneSwitcher.tempVar.file.date="File modification date"
|
||||
AdvSceneSwitcher.tempVar.file.basename="File basename"
|
||||
AdvSceneSwitcher.tempVar.file.basename.description="Returns the base name of the file without the path.\nThe base name consists of all characters in the file up to (but not including) the first '.' character."
|
||||
AdvSceneSwitcher.tempVar.file.basenameComplete="File basename (complete)"
|
||||
AdvSceneSwitcher.tempVar.file.basenameComplete.description="Returns the complete base name of the file without the path.\nThe complete base name consists of all characters in the file up to (but not including) the last '.' character."
|
||||
AdvSceneSwitcher.tempVar.file.suffix="File suffix"
|
||||
AdvSceneSwitcher.tempVar.file.suffix.description="Returns the suffix (extension) of the file.\nThe suffix consists of all characters in the file after (but not including) the last '.'."
|
||||
AdvSceneSwitcher.tempVar.file.suffixComplete="File suffix (complete)"
|
||||
AdvSceneSwitcher.tempVar.file.suffixComplete.description="Returns the complete suffix (extension) of the file.\nThe complete suffix consists of all characters in the file after (but not including) the first '.'."
|
||||
AdvSceneSwitcher.tempVar.file.filename="File name"
|
||||
AdvSceneSwitcher.tempVar.file.absoluteFilePath="Absolute file path"
|
||||
AdvSceneSwitcher.tempVar.file.absolutePath="Absolute path"
|
||||
AdvSceneSwitcher.tempVar.file.isAbsolutePath="Path is absolute"
|
||||
|
||||
|
||||
AdvSceneSwitcher.tempVar.folder.newFiles="New files"
|
||||
AdvSceneSwitcher.tempVar.folder.changedFiles="Changed files"
|
||||
@@ -2000,6 +2235,8 @@ AdvSceneSwitcher.tempVar.usb.serialNumber="Serial Number"
|
||||
AdvSceneSwitcher.tempVar.transform.setting="Setting value"
|
||||
AdvSceneSwitcher.tempVar.transform.settings="Settings string"
|
||||
|
||||
AdvSceneSwitcher.tempVar.media.source="Source"
|
||||
AdvSceneSwitcher.tempVar.media.source.description="The name of the source which matched.\nIf multiple sources matched the last one is returned."
|
||||
AdvSceneSwitcher.tempVar.media.state="State"
|
||||
AdvSceneSwitcher.tempVar.media.state.description="The current media state represented as an integer value:\n0 being 'None'\n1 being 'Playing'\n2 being 'Opening'\n3 being 'Buffering'\n4 being 'Paused'\n5 being 'Stopped'\n6 being 'Ended'\n7 being 'Error'"
|
||||
AdvSceneSwitcher.tempVar.media.time="Current time"
|
||||
@@ -2059,7 +2296,13 @@ AdvSceneSwitcher.tempVar.http.body="Message body"
|
||||
AdvSceneSwitcher.tempVar.http.error="Error"
|
||||
AdvSceneSwitcher.tempVar.http.error.description="Empty when no error occurred.\nOther possible values:\n\n * Could not establish connection\n * Failed to bind IP address\n * Failed to read connection\n * Failed to write connection\n * Maximum redirect count exceeded\n * Connection handling canceled\n * SSL connection failed\n * SSL certificate loading failed\n * SSL server verification failed\n * Unsupported HTTP multipart boundary characters\n * Compression failed\n * Connection timed out\n * Proxy connection failed\n * Unknown"
|
||||
|
||||
AdvSceneSwitcher.tempVar.mqtt.message="Message"
|
||||
|
||||
AdvSceneSwitcher.tempVar.cursor.x="Cursor position (X)"
|
||||
AdvSceneSwitcher.tempVar.cursor.y="Cursor position (Y)"
|
||||
|
||||
AdvSceneSwitcher.selectScene="--select scene--"
|
||||
AdvSceneSwitcher.selectCanvas="--select canvas--"
|
||||
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
||||
AdvSceneSwitcher.selectCurrentScene="Current Scene"
|
||||
AdvSceneSwitcher.selectPreviewScene="Preview Scene"
|
||||
@@ -2120,21 +2363,23 @@ AdvSceneSwitcher.setting.transform.width="Width"
|
||||
|
||||
AdvSceneSwitcher.sceneItemSelection.configure="Configure scene item selection type"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Source name"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.layout="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Variable name"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.layout="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Source name matches pattern"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}matching{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}matching{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup="Sources in source group"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.entry="Sources in{{sourceGroups}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.layout="{{nameConflictIndex}}Sources in{{sourceGroups}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="Sources of type"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="Source type{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="Source type{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="Source with index"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="Sources in index range"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Sources from{{index}}to{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="Sources from{{index}}to{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="All sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="All sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="All sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.any="Any source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.any.layout="Any source"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="All"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="Any"
|
||||
|
||||
@@ -2178,13 +2423,12 @@ AdvSceneSwitcher.script.timeout="Script timeout:{{timeout}}"
|
||||
|
||||
# This secion is copied from the OBS locale files
|
||||
|
||||
# commonly shared locale
|
||||
# OBS commonly shared locale
|
||||
Browse="Browse"
|
||||
Show="Show"
|
||||
Hide="Hide"
|
||||
|
||||
|
||||
# properties window
|
||||
# OBS properties window
|
||||
Basic.PropertiesWindow="Properties for '%1'"
|
||||
Basic.PropertiesWindow.AutoSelectFormat="%1 (autoselect: %2)"
|
||||
Basic.PropertiesWindow.SelectColor="Select color"
|
||||
@@ -2201,7 +2445,7 @@ Basic.PropertiesWindow.AddEditableListFiles="Add files to '%1'"
|
||||
Basic.PropertiesWindow.AddEditableListEntry="Add entry to '%1'"
|
||||
Basic.PropertiesWindow.EditEditableListEntry="Edit entry from '%1'"
|
||||
|
||||
# properties view
|
||||
# OBS properties view
|
||||
Basic.PropertiesView.FPS.Simple="Simple FPS Values"
|
||||
Basic.PropertiesView.FPS.Rational="Rational FPS Values"
|
||||
Basic.PropertiesView.FPS.ValidFPSRanges="Valid FPS Ranges:"
|
||||
@@ -2209,6 +2453,11 @@ Basic.PropertiesView.UrlButton.Text="Open this link in your default web browser?
|
||||
Basic.PropertiesView.UrlButton.Text.Url="URL: %1"
|
||||
Basic.PropertiesView.UrlButton.OpenUrl="Open URL"
|
||||
|
||||
# OBS settings
|
||||
Basic.Settings.Video.FPSCommon="Common FPS Values"
|
||||
Basic.Settings.Video.FPSInteger="Integer FPS Value"
|
||||
Basic.Settings.Video.FPSFraction="Fractional FPS Value"
|
||||
|
||||
# Legacy tabs below - please don't waste your time adding translations for these :)
|
||||
# Transition Tab
|
||||
AdvSceneSwitcher.transitionTab.title="Transition"
|
||||
|
||||
@@ -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"
|
||||
@@ -155,12 +154,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"
|
||||
@@ -312,7 +311,6 @@ AdvSceneSwitcher.condition.stats.entry="{{stats}} esta {{condition}} {{value}}"
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Cambiar escena"
|
||||
AdvSceneSwitcher.action.scene.entry="Cambiar a la{{sceneTypes}}escena{{scenes}}usando{{transitions}}con una duración de{{duration}} segundos"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Espere hasta que se complete la transición a la escena de destino"
|
||||
AdvSceneSwitcher.action.wait="Esperar"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fijo"
|
||||
@@ -384,7 +382,7 @@ AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced S
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="Importar configuración desde"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Nota: la acción se ignorará mientras se abra la ventana de configuración."
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Cámara virtual"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Detener cámara virtual"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Iniciar cámara virtual"
|
||||
@@ -641,9 +639,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Alternar inicio / detenci
|
||||
AdvSceneSwitcher.hotkey.macro.pause="Pausar macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.unpause="Despausar macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.togglePause="Alternar pausa de macro %1"
|
||||
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Mover selección de segmento de macro hacia arriba"
|
||||
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Mover selección de segmento de macro hacia abajo"
|
||||
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Eliminar segmento de macro seleccionado"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.up="Mover selección de segmento de macro hacia arriba"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.down="Mover selección de segmento de macro hacia abajo"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.remove="Eliminar segmento de macro seleccionado"
|
||||
|
||||
AdvSceneSwitcher.askBackup="Se detectó una nueva versión de Advanced Scene Switcher.\n¿Crear una copia de seguridad de la configuración anterior?"
|
||||
AdvSceneSwitcher.askForMacro="Select macro {{macroSelection}}"
|
||||
|
||||
@@ -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"
|
||||
@@ -258,14 +257,14 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="À quel poi
|
||||
AdvSceneSwitcher.condition.video.type.main="Sortie principale d'OBS"
|
||||
AdvSceneSwitcher.condition.video.type.source="Source"
|
||||
AdvSceneSwitcher.condition.video.type.scene="Scène"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="Données du modèle (classificateur de cascade de Haar) :{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="Nombre minimum de voisins :{{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Réduire la charge CPU en effectuant la vérification uniquement toutes les{{throttleCount}}millisecondes"
|
||||
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Effectuer la vérification uniquement dans la zone"
|
||||
AdvSceneSwitcher.condition.video.entry.orcColorPick="Vérifier la couleur du texte :{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcTextType="Vérifier le type de texte :{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcLanguage="Vérifier la langue :{{languageCode}}"
|
||||
AdvSceneSwitcher.condition.video.entry.color="Vérifier la couleur :{{color}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.layout.modelPath="Données du modèle (classificateur de cascade de Haar) :{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.minNeighbor="Nombre minimum de voisins :{{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Réduire la charge CPU en effectuant la vérification uniquement toutes les{{throttleCount}}millisecondes"
|
||||
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Effectuer la vérification uniquement dans la zone"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrColorPick="Vérifier la couleur du texte :{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrTextType="Vérifier le type de texte :{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrLanguage="Vérifier la langue :{{languageCode}}"
|
||||
AdvSceneSwitcher.condition.video.layout.color="Vérifier la couleur :{{color}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.minSize="Taille minimale :"
|
||||
AdvSceneSwitcher.condition.video.maxSize="Taille maximale :"
|
||||
AdvSceneSwitcher.condition.video.selectArea="Sélectionner la zone"
|
||||
@@ -460,8 +459,6 @@ AdvSceneSwitcher.condition.slideshow.updateInterval.tooltip="Les informations su
|
||||
AdvSceneSwitcher.action.scene="Changer de scène"
|
||||
AdvSceneSwitcher.action.scene.type.program="Programme"
|
||||
AdvSceneSwitcher.action.scene.type.preview="Aperçu"
|
||||
AdvSceneSwitcher.action.scene.entry="Changer la scène{{sceneTypes}}{{scenes}}en utilisant{{transitions}}avec une durée de{{duration}}secondes"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Changer la scène{{sceneTypes}}{{scenes}}en utilisant{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Attendre que la transition vers la scène cible soit terminée"
|
||||
AdvSceneSwitcher.action.wait="Attendre"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fixe"
|
||||
@@ -704,10 +701,10 @@ AdvSceneSwitcher.action.variable.invalidSelection="Sélection invalide !"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="La récupération de valeurs de variables à partir d'actions %1 n'est pas prise en charge !"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="La récupération de valeurs de variables à partir de conditions %1 n'est pas prise en charge !"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Valeur actuelle :"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière :"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}Utiliser un message personnalisé{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}Remplir avec un indicateur de position{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière :"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Utiliser un message personnalisé{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Remplir avec un indicateur de position{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.projector="Projecteur"
|
||||
AdvSceneSwitcher.action.projector.type.source="Source"
|
||||
AdvSceneSwitcher.action.projector.type.scene="Scène"
|
||||
@@ -921,9 +918,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Basculer le démarrage/ar
|
||||
AdvSceneSwitcher.hotkey.macro.pause="Mettre en pause la macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.unpause="Reprendre la macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.togglePause="Basculer la pause de la macro %1"
|
||||
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Déplacer la sélection du segment de macro vers le haut"
|
||||
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Déplacer la sélection du segment de macro vers le bas"
|
||||
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Supprimer le segment de macro sélectionné"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.up="Déplacer la sélection du segment de macro vers le haut"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.down="Déplacer la sélection du segment de macro vers le bas"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.remove="Supprimer le segment de macro sélectionné"
|
||||
|
||||
AdvSceneSwitcher.askBackup="Une nouvelle version du commutateur de scènes avancé a été détectée.\nSouhaitez-vous créer une sauvegarde des anciens paramètres ?"
|
||||
AdvSceneSwitcher.askForMacro="Sélectionnez la macro{{macroSelection}}"
|
||||
@@ -1108,15 +1105,15 @@ AdvSceneSwitcher.sceneItemSelection.configure="Configurer le type de sélection
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Nom de la source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Nom de la variable"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Le nom de la source correspond au motif"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}correspondant à{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}correspondant à{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="Sources de type"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="{{nameConflictIndex}}Type de source{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="{{nameConflictIndex}}Type de source{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="Source avec index"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="Sources dans la plage d'index"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Sources de{{index}}à{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="Sources de{{index}}à{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="Toutes les sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="Toutes les sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="Toutes les sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="Tout"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="N'importe lequel"
|
||||
|
||||
|
||||
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!"
|
||||
@@ -373,16 +372,16 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="Quão semel
|
||||
AdvSceneSwitcher.condition.video.type.main="Saída principal do OBS"
|
||||
AdvSceneSwitcher.condition.video.type.source="Fonte"
|
||||
AdvSceneSwitcher.condition.video.type.scene="Cena"
|
||||
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="Dados do modelo (classificador em cascata haar):{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="Vizinhos mínimos:{{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzir carga de CPU realizando a verificação apenas a cada {{throttleCount}} milissegundos"
|
||||
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Realizar verificação apenas na área"
|
||||
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcColorPick="Verificar cor do texto:{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcTextType="Verificar tipo de texto:{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcLanguage="Verificar idioma:{{languageCode}}"
|
||||
AdvSceneSwitcher.condition.video.entry.color="Verificar cor:{{color}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.modelPath="Dados do modelo (classificador em cascata haar):{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.minNeighbor="Vizinhos mínimos:{{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzir carga de CPU realizando a verificação apenas a cada {{throttleCount}} milissegundos"
|
||||
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Realizar verificação apenas na área"
|
||||
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrColorPick="Verificar cor do texto:{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrTextType="Verificar tipo de texto:{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrLanguage="Verificar idioma:{{languageCode}}"
|
||||
AdvSceneSwitcher.condition.video.layout.color="Verificar cor:{{color}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.minSize="Tamanho mínimo:"
|
||||
AdvSceneSwitcher.condition.video.maxSize="Tamanho máximo:"
|
||||
AdvSceneSwitcher.condition.video.selectArea="Selecionar área"
|
||||
@@ -721,9 +720,6 @@ AdvSceneSwitcher.condition.noDevicesFoundWarning="Nenhum dispositivo USB detecta
|
||||
AdvSceneSwitcher.action.scene="Trocar cena"
|
||||
AdvSceneSwitcher.action.scene.type.program="Programa"
|
||||
AdvSceneSwitcher.action.scene.type.preview="Pré-visualização"
|
||||
AdvSceneSwitcher.action.scene.entry="Trocar{{sceneTypes}}cena para{{scenes}}usando{{transitions}}com duração de{{duration}}segundos"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Trocar{{sceneTypes}}cena para{{scenes}}usando{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.entry.preview="Trocar{{sceneTypes}}cena para{{scenes}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Aguardar até que a transição para a cena de destino seja concluída"
|
||||
AdvSceneSwitcher.action.wait="Aguardar"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fixo"
|
||||
@@ -875,7 +871,7 @@ AdvSceneSwitcher.action.pluginState.type.import="Importar configurações de"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Nota: Ação será ignorada enquanto a janela de configurações estiver aberta."
|
||||
AdvSceneSwitcher.action.pluginState.type.terminate="Desligar OBS"
|
||||
AdvSceneSwitcher.action.pluginState.terminateConfirm="O OBS será desligado automaticamente em 10 segundos!\nDeseja continuar com o desligamento do OBS?"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Câmera virtual"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Parar câmera virtual"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Iniciar câmera virtual"
|
||||
@@ -1012,7 +1008,7 @@ AdvSceneSwitcher.action.variable.type.askForValue="Obter entrada do usuário"
|
||||
AdvSceneSwitcher.action.variable.type.environmentVariable="Definir valor da variável de ambiente"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemCount="Definir para contagem de itens de cena"
|
||||
AdvSceneSwitcher.action.variable.type.stringLength="Definir comprimento da string"
|
||||
AdvSceneSwitcher.action.variable.type.extractJson="Extrair campo json com nome"
|
||||
AdvSceneSwitcher.action.variable.type.extractJsonField="Extrair campo json com nome"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar="Definir para propriedade da macro"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar.help="Este tipo de ação permite extrair valores de segmentos da macro atual e atribuir esses valores à variável selecionada.\nPor exemplo, você pode obter o nome da cena atual de uma condição de cena e atribuir esse nome a uma variável."
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemName="Definir para nome do item de cena no índice"
|
||||
@@ -1032,13 +1028,13 @@ AdvSceneSwitcher.action.variable.invalidSelection="Seleção inválida!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Obter valores de variáveis das ações %1 não é suportado!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Obter valores de variáveis das condições %1 não é suportado!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Valor atual:"
|
||||
AdvSceneSwitcher.action.variable.entry.pad="{{actions}}de{{variables}}para comprimento{{stringLength}}adicionando{{paddingCharSelection}}ao{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.entry.truncate="{{actions}}de{{variables}}para comprimento{{stringLength}}removendo caracteres da{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Início da substring:{{subStringStart}}Tamanho da substring:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:"
|
||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}Usar prompt personalizado{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}Preencher com placeholder{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}de{{variables}}para comprimento{{stringLength}}adicionando{{paddingCharSelection}}ao{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}de{{variables}}para comprimento{{stringLength}}removendo caracteres da{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Início da substring:{{subStringStart}}Tamanho da substring:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:"
|
||||
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Usar prompt personalizado{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Preencher com placeholder{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.projector="Projetor"
|
||||
AdvSceneSwitcher.action.projector.type.source="Fonte"
|
||||
AdvSceneSwitcher.action.projector.type.scene="Cena"
|
||||
@@ -1112,9 +1108,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Alternar Iniciar/Parar pa
|
||||
AdvSceneSwitcher.hotkey.macro.pause="Pausar macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.unpause="Retomar macro %1"
|
||||
AdvSceneSwitcher.hotkey.macro.togglePause="Alternar pausa da macro %1"
|
||||
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Mover seleção de segmento de macro para cima"
|
||||
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Mover seleção de segmento de macro para baixo"
|
||||
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Remover segmento de macro selecionado"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.up="Mover seleção de segmento de macro para cima"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.down="Mover seleção de segmento de macro para baixo"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.remove="Remover segmento de macro selecionado"
|
||||
|
||||
AdvSceneSwitcher.askBackup="Detectada uma nova versão do Advanced Scene Switcher.\nDeve ser criado um backup das configurações antigas?"
|
||||
AdvSceneSwitcher.askForMacro="Selecionar macro{{macroSelection}}"
|
||||
@@ -1852,19 +1848,19 @@ AdvSceneSwitcher.setting.transform.width="Largura"
|
||||
|
||||
AdvSceneSwitcher.sceneItemSelection.configure="Configurar tipo de seleção de item de cena"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Nome da fonte"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.layout="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Nome da variável"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.layout="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Nome da fonte corresponde ao padrão"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}correspondendo{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}correspondendo{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="Fontes do tipo"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="Tipo de fonte{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="Tipo de fonte{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="Fonte com índice"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}fonte"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}fonte"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="Fontes no intervalo de índices"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Fontes de{{index}}para{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="Fontes de{{index}}para{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="Todas as fontes"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="Todas as fontes"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="Todas as fontes"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="Todas"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="Qualquer"
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Всегда запу
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Не запускать переключатель сцен"
|
||||
AdvSceneSwitcher.generalTab.status.start="Старт"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Стоп"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Автоматически запускать переключатель сцен, когда:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Автоматически запускать переключатель сцен, когда:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Никогда"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Запись"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Вещание"
|
||||
@@ -25,7 +25,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.dontSwitch="Не пере
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Переключиться на любую сцену на вкладке Random"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Переключиться на:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="В течение этого времени потенциальные совпадения будут игнорироваться!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Включить ведение подробного журнала"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Сохранять положение и размер окна"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Отключить подсказки пользовательского интерфейса"
|
||||
AdvSceneSwitcher.generalTab.priority="Приоритет"
|
||||
@@ -37,7 +36,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Экспорт"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Импорт"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Экспортировать настройки расширенного переключателя сцен в файл ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Импортировать настройки Advanced Scene Switcher из файла ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Текстовые файлы (*.txt)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Текстовые файлы (*.txt *.json)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Advanced Scene Switcher не удалось импортировать настройки"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Настройки Advanced Scene Switcher импортированы успешно"
|
||||
AdvSceneSwitcher.generalTab.priority.fileContent="Содержание файла"
|
||||
@@ -115,7 +114,6 @@ AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Переключить сцену"
|
||||
AdvSceneSwitcher.action.scene.entry="Перейти к сцене{{sceneTypes}}{{scenes}}используя{{transitions}}с продолжительностью{{duration}}секунд"
|
||||
AdvSceneSwitcher.action.wait="Подождать"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="фиксированный"
|
||||
AdvSceneSwitcher.action.wait.type.random="случайный"
|
||||
|
||||
@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Her zaman sahne deği
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Sahne değiştiriciyi başlatma"
|
||||
AdvSceneSwitcher.generalTab.status.start="Başlat"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Durdur"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Aşağıdaki durumlarda sahne değiştiriciyi otomatik olarak başlatın:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Aşağıdaki durumlarda sahne değiştiriciyi otomatik olarak başlatın:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Asla"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Kayıt"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Yayın"
|
||||
@@ -26,7 +26,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom="Rastgele s
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo="Değiştirmek:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="Bir eşleşmeden sonra aşağıdakiler için işlem yapmayın:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="Bu süre zarfında olası eşleşmeler göz ardı edilecektir!"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Ayrıntılı günlük kaydını etkinleştir"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Pencere konumunu ve boyutunu kaydet"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Sistem tepsisi bildirimlerini göster"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="UI ipuçlarını devre dışı bırak"
|
||||
@@ -39,7 +38,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Dışa Aktar"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="İçe Aktar"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Gelişmiş Sahne Değiştirici ayarlarını dosyaya aktar ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Gelişmiş Sahne Değiştirici ayarlarını dosyadan içe aktar ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text dosyası (*.txt)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text dosyası (*.txt *.json)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Gelişmiş Sahne Değiştirici ayarları dosyadan içe aktarmakta başarısız oldu"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Gelişmiş Sahne Değiştirici ayarları başarılı bir şekilde dosyadan içe aktarıldı"
|
||||
AdvSceneSwitcher.generalTab.priority.fileContent="Dosya İçeriği"
|
||||
@@ -140,10 +139,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"
|
||||
@@ -250,7 +249,6 @@ AdvSceneSwitcher.condition.openvr.entry.line3="HMD mevcut {{xPos}} x {{yPos}} x
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Sahne Degistirici"
|
||||
AdvSceneSwitcher.action.scene.entry="Sahneyi{{sceneTypes}}{{scenes}}kullanarak{{transitions}}süresi olan{{duration}}saniye"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Hedef sahneye geçiş tamamlanana kadar bekleyin"
|
||||
AdvSceneSwitcher.action.wait="Bekle"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="sabit"
|
||||
@@ -313,7 +311,7 @@ AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisi
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="Ayarları şuradan içe aktar:"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Not: Ayarlar penceresi açılırken eylem göz ardı edilecektir."
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Sanal Kamera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Sanal Kamerayı Durdur"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Sanal Kamerayı Başlat"
|
||||
|
||||
@@ -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="直播"
|
||||
@@ -33,7 +33,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default="默认"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logMacro="记录已执行的宏"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction="记录已执行的操作"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose="记录所有信息"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="详细日志输出"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="保存窗口位置和大小"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="显示系统托盘通知"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="禁用UI提示"
|
||||
@@ -52,7 +51,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="导出设置"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="导入设置"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="导出高级场景切换器到文件..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="导入高级场景切换器到文件..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="文本文件 (*.txt)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="文本文件 (*.txt *.json)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="高级场景切换器导入设置失败"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="高级场景切换器导入设置成功"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportSensitiveDataWarning="警告:\n导出的数据可能包含敏感信息!"
|
||||
@@ -396,16 +395,16 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="颜色与
|
||||
AdvSceneSwitcher.condition.video.type.main="OBS的主输出"
|
||||
AdvSceneSwitcher.condition.video.type.source="源"
|
||||
AdvSceneSwitcher.condition.video.type.scene="场景"
|
||||
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="模型数据 (haar级联分类器): {{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="最小区域: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}每隔{{throttleCount}} 毫秒,才执行一次检查,从而减少 CPU 负载."
|
||||
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="仅在区域内执行检查"
|
||||
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcColorPick="文本检查颜色:{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcTextType="文本检查类型:{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.entry.orcLanguage="语言检查:{{languageCode}}"
|
||||
AdvSceneSwitcher.condition.video.entry.color="颜色检查:{{color}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.modelPath="模型数据 (haar级联分类器): {{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.minNeighbor="最小区域: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}每隔{{throttleCount}} 毫秒,才执行一次检查,从而减少 CPU 负载."
|
||||
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="仅在区域内执行检查"
|
||||
AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrColorPick="文本检查颜色:{{textColor}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrTextType="文本检查类型:{{textType}}"
|
||||
AdvSceneSwitcher.condition.video.layout.ocrLanguage="语言检查:{{languageCode}}"
|
||||
AdvSceneSwitcher.condition.video.layout.color="颜色检查:{{color}}{{selectColor}}"
|
||||
AdvSceneSwitcher.condition.video.minSize="最小尺寸:"
|
||||
AdvSceneSwitcher.condition.video.maxSize="最大尺寸:"
|
||||
AdvSceneSwitcher.condition.video.selectArea="选择区域"
|
||||
@@ -699,7 +698,7 @@ AdvSceneSwitcher.condition.twitch.type.event.channel.user.moderator.deletion="
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.live="开始直播"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.playlist="开始播放列表"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.watchParty="开始观看派对"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.premiere="开始首播
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.premiere="开始首播"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.rerun="开始重播"
|
||||
AdvSceneSwitcher.condition.twitch.type.polling.channel.live="当前正在直播"
|
||||
AdvSceneSwitcher.condition.twitch.type.polling.channel.title="当前为头衔赛"
|
||||
@@ -780,9 +779,6 @@ AdvSceneSwitcher.action.unknown="未知操作"
|
||||
AdvSceneSwitcher.action.scene="切换场景"
|
||||
AdvSceneSwitcher.action.scene.type.program="程序"
|
||||
AdvSceneSwitcher.action.scene.type.preview="预览"
|
||||
AdvSceneSwitcher.action.scene.entry="切换到场景{{sceneTypes}}{{scenes}}使用{{transitions}}时长{{duration}}秒"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="切换到场景{{sceneTypes}}{{scenes}}使用{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.entry.preview="将{{sceneTypes}}场景切换到{{scenes}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="等待转场到目标场景的动画完成"
|
||||
AdvSceneSwitcher.action.wait="等待"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="固定"
|
||||
@@ -934,7 +930,7 @@ AdvSceneSwitcher.action.pluginState.type.import="导入设置"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="注意:当设置窗口打开时,操作将被忽略."
|
||||
AdvSceneSwitcher.action.pluginState.type.terminate="关闭OBS"
|
||||
AdvSceneSwitcher.action.pluginState.terminateConfirm="OBS将在10秒后自动关闭!\n你想继续关闭OBS吗?"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="虚拟摄像机"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="停止虚拟摄像机"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="启动虚拟摄像机"
|
||||
@@ -1073,7 +1069,7 @@ AdvSceneSwitcher.action.variable.type.askForValue="获取用户输入内容"
|
||||
AdvSceneSwitcher.action.variable.type.environmentVariable="设置为环境变量值"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemCount="设置为场景内的场景项目计数"
|
||||
AdvSceneSwitcher.action.variable.type.stringLength="设置为字符串长度"
|
||||
AdvSceneSwitcher.action.variable.type.extractJson="取JSON内字段的值"
|
||||
AdvSceneSwitcher.action.variable.type.extractJsonField="取JSON内字段的值"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar="设置为宏属性"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar.help="此操作类型将允许您从当前宏的部分中提取值,并将这些值分配给所选变量.\n例如,可以从场景条件中获取当前场景名称,并将该名称分配给变量."
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemName="设置为场景项目索引的名称"
|
||||
@@ -1102,15 +1098,14 @@ AdvSceneSwitcher.action.variable.invalidSelection="无效选择!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="不支持从 %1 操作中获取变量值!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="不支持从 %1 条件中获取变量值!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="当前值:"
|
||||
AdvSceneSwitcher.action.variable.entry.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}{{caseType}}"
|
||||
AdvSceneSwitcher.action.variable.entry.pad="{{actions}}于{{variables}}的{{direction}}起,内容为{{paddingCharSelection}}将其变量值长度增加至{{stringLength}}."
|
||||
AdvSceneSwitcher.action.variable.entry.truncate="{{actions}}于{{variables}}的{{direction}}起,将变量长度缩减至{{stringLength}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="截取字符串开始位置:{{subStringStart}} 截取字符串长度:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
|
||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}使用自定义提示{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}用占位符填充{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.entry.randomNumber="在以下范围内生成随机数{{randomNumberStart}}到{{randomNumberEnd}}"
|
||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}于{{variables}}的{{direction}}起,内容为{{paddingCharSelection}}将其变量值长度增加至{{stringLength}}."
|
||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}于{{variables}}的{{direction}}起,将变量长度缩减至{{stringLength}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringIndex="截取字符串开始位置:{{subStringStart}} 截取字符串长度:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.layout.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
|
||||
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}使用自定义提示{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}用占位符填充{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.variable.layout.randomNumber="在以下范围内生成随机数{{randomNumberStart}}到{{randomNumberEnd}}"
|
||||
AdvSceneSwitcher.action.projector="投影仪"
|
||||
AdvSceneSwitcher.action.projector.type.source="源"
|
||||
AdvSceneSwitcher.action.projector.type.scene="场景"
|
||||
@@ -1191,9 +1186,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="切换(启动/停止)高
|
||||
AdvSceneSwitcher.hotkey.macro.pause="停用宏 %1"
|
||||
AdvSceneSwitcher.hotkey.macro.unpause="启用宏 %1"
|
||||
AdvSceneSwitcher.hotkey.macro.togglePause="切换(停用/启用)宏 %1"
|
||||
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="上移选择宏"
|
||||
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="下移选择宏"
|
||||
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="删除选定的宏"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.up="上移选择宏"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.down="下移选择宏"
|
||||
AdvSceneSwitcher.hotkey.macro.segment.remove="删除选定的宏"
|
||||
|
||||
AdvSceneSwitcher.askBackup="检测到新版本的高级场景切换器。\n是否要创建旧版本的设置备份?"
|
||||
AdvSceneSwitcher.askForMacro="选择宏 {{macroSelection}}"
|
||||
@@ -2097,21 +2092,19 @@ AdvSceneSwitcher.setting.transform.width="宽度"
|
||||
|
||||
AdvSceneSwitcher.sceneItemSelection.configure="配置场景项目选择类型"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="源名称"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="变量名称"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="源名称与匹配相符"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}匹配{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}匹配{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup="源分组中的来源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.entry="{{sourceGroups}}中的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.layout="{{nameConflictIndex}}{{sourceGroups}}中的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="源类型"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="源类型{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="源类型{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="附有索引的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="索引范围内的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="从{{index}}到{{indexEnd}}的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="从{{index}}到{{indexEnd}}的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="所有源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="所有源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="所有源"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="全部"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="任何"
|
||||
|
||||
@@ -2135,9 +2128,9 @@ AdvSceneSwitcher.unit.weeks="周"
|
||||
AdvSceneSwitcher.unit.months="月"
|
||||
AdvSceneSwitcher.unit.years="年"
|
||||
AdvSceneSwitcher.duration.condition.none="没有时间限制"
|
||||
AdvSceneSwitcher.duration.condition.more="时间少于"
|
||||
AdvSceneSwitcher.duration.condition.more="时间大于"
|
||||
AdvSceneSwitcher.duration.condition.equal="时间等于"
|
||||
AdvSceneSwitcher.duration.condition.less="时间大于"
|
||||
AdvSceneSwitcher.duration.condition.less="时间少于"
|
||||
AdvSceneSwitcher.duration.condition.within="最后"
|
||||
|
||||
AdvSceneSwitcher.time.relative="%1 %2 之前"
|
||||
|
||||
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 |
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/libusb
vendored
2
deps/libusb
vendored
Submodule deps/libusb updated: d52e355daa...15a7ebb4d4
1
deps/paho.mqtt.cpp
vendored
Submodule
1
deps/paho.mqtt.cpp
vendored
Submodule
Submodule deps/paho.mqtt.cpp added at 165476b1dc
@@ -87,6 +87,40 @@
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="autoStartEvent"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.status.autoStart.startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_33">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.status.checkInterval</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="checkIntervalTooLowWarning">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="startupBehavior"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QWidget" name="placeholder3" native="true"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QWidget" name="placeholder" native="true"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_64">
|
||||
<property name="text">
|
||||
@@ -94,16 +128,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="startupBehavior"/>
|
||||
<item row="2" column="1">
|
||||
<widget class="QWidget" name="placeholder2" native="true"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QWidget" name="placeholder" native="true"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.status.autoStart</string>
|
||||
<string>AdvSceneSwitcher.generalTab.status.hotkeytips</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -130,36 +161,25 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<widget class="QCheckBox" name="autoStartSceneEnable">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.status.hotkeytips</string>
|
||||
<string>AdvSceneSwitcher.generalTab.status.autoStart.scene</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_33">
|
||||
<item row="5" column="1">
|
||||
<layout class="QHBoxLayout" name="autoStartSceneLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.status.checkInterval</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="advss::SceneSelectionWidget" name="autoStartScene" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="checkIntervalTooLowWarning">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="advss::VariableLineEdit" name="autoStartSceneName"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="advss::RegexConfigWidget" name="autoStartSceneNameRegex" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QWidget" name="placeholder2" native="true"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QWidget" name="placeholder3" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -181,28 +201,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="logLevel">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logMacro</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
<widget class="QComboBox" name="logLevel"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_49">
|
||||
@@ -315,6 +314,17 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="disableMacroWidgetCache">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.disableMacroWidgetCache</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_26">
|
||||
<item>
|
||||
@@ -479,16 +489,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="noMatchSwitchScene">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<widget class="advss::SceneSelectionWidget" name="noMatchSwitchScene">
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -800,7 +801,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="macroEdit">
|
||||
<widget class="QGroupBox" name="macroEditGroup">
|
||||
<property name="title">
|
||||
<string>AdvSceneSwitcher.macroTab.edit</string>
|
||||
</property>
|
||||
@@ -906,339 +907,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<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>
|
||||
<widget class="advss::MacroEdit" name="macroEdit" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -4450,12 +4119,6 @@
|
||||
<extends>QListView</extends>
|
||||
<header>macro-tree.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>advss::MacroSegmentList</class>
|
||||
<extends>QScrollArea</extends>
|
||||
<header>macro-segment-list.hpp</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>advss::MacroRunButton</class>
|
||||
<extends>QPushButton</extends>
|
||||
@@ -4466,6 +4129,29 @@
|
||||
<extends>QWidget</extends>
|
||||
<header>duration-control.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>advss::MacroEdit</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>macro-edit.hpp</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>advss::SceneSelectionWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>scene-selection.hpp</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>advss::VariableLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>variable-line-edit.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>advss::RegexConfigWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>regex-config.hpp</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>tabWidget</tabstop>
|
||||
@@ -4473,6 +4159,10 @@
|
||||
<tabstop>checkInterval</tabstop>
|
||||
<tabstop>startupBehavior</tabstop>
|
||||
<tabstop>autoStartEvent</tabstop>
|
||||
<tabstop>autoStartSceneEnable</tabstop>
|
||||
<tabstop>autoStartScene</tabstop>
|
||||
<tabstop>autoStartSceneName</tabstop>
|
||||
<tabstop>autoStartSceneNameRegex</tabstop>
|
||||
<tabstop>logLevel</tabstop>
|
||||
<tabstop>saveWindowGeo</tabstop>
|
||||
<tabstop>showTrayNotifications</tabstop>
|
||||
@@ -4502,28 +4192,7 @@
|
||||
<tabstop>runMacroInParallel</tabstop>
|
||||
<tabstop>runMacroOnChange</tabstop>
|
||||
<tabstop>macroSettings</tabstop>
|
||||
<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>
|
||||
<tabstop>macroEdit</tabstop>
|
||||
<tabstop>sceneGroups</tabstop>
|
||||
<tabstop>sceneGroupAdd</tabstop>
|
||||
<tabstop>sceneGroupRemove</tabstop>
|
||||
|
||||
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>
|
||||
@@ -146,16 +146,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();
|
||||
|
||||
@@ -547,6 +538,7 @@ static void handleSceneChange()
|
||||
}
|
||||
|
||||
switcher->checkDefaultSceneTransitions();
|
||||
switcher->CheckAutoStart();
|
||||
}
|
||||
|
||||
static void setLiveTime()
|
||||
@@ -561,18 +553,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 +610,7 @@ static void handleSceneCollectionChanging()
|
||||
AdvSceneSwitcher::window->close();
|
||||
}
|
||||
if (!switcher->stop) {
|
||||
switcher->sceneColletionStop = true;
|
||||
switcher->sceneCollectionStop = true;
|
||||
switcher->Stop();
|
||||
}
|
||||
}
|
||||
@@ -744,6 +746,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();
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace advss {
|
||||
|
||||
class MacroActionEdit;
|
||||
class MacroConditionEdit;
|
||||
class MacroSegment;
|
||||
class Duration;
|
||||
class SequenceWidget;
|
||||
struct SceneGroup;
|
||||
@@ -44,7 +45,6 @@ protected:
|
||||
/* --- Begin of general tab section --- */
|
||||
public:
|
||||
void SetupGeneralTab();
|
||||
void UpdateNonMatchingScene(const QString &name);
|
||||
void SetDeprecationWarnings();
|
||||
|
||||
public slots:
|
||||
@@ -57,7 +57,6 @@ public slots:
|
||||
void on_startupBehavior_currentIndexChanged(int index);
|
||||
void on_logLevel_currentIndexChanged(int index);
|
||||
void on_autoStartEvent_currentIndexChanged(int index);
|
||||
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
|
||||
void on_checkInterval_valueChanged(int value);
|
||||
void on_tabWidget_currentChanged(int index);
|
||||
void on_exportSettings_clicked();
|
||||
@@ -66,6 +65,7 @@ public slots:
|
||||
void on_showTrayNotifications_stateChanged(int state);
|
||||
void on_uiHintsDisable_stateChanged(int state);
|
||||
void on_disableComboBoxFilter_stateChanged(int state);
|
||||
void on_disableMacroWidgetCache_stateChanged(int state);
|
||||
void on_warnPluginLoadFailure_stateChanged(int state);
|
||||
void on_hideLegacyTabs_stateChanged(int state);
|
||||
void on_priorityUp_clicked();
|
||||
@@ -77,24 +77,26 @@ public slots:
|
||||
/* --- 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 +104,22 @@ 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_runMacroOnChange_stateChanged(int value) const;
|
||||
void MacroSelectionChanged();
|
||||
void UpMacroSegementHotkey();
|
||||
void DownMacroSegementHotkey();
|
||||
void DeleteMacroSegementHotkey();
|
||||
void ShowMacroContextMenu(const QPoint &);
|
||||
void ShowMacroActionsContextMenu(const QPoint &);
|
||||
void ShowMacroElseActionsContextMenu(const QPoint &);
|
||||
void ShowMacroConditionsContextMenu(const QPoint &);
|
||||
void CopyMacro();
|
||||
void RenameSelectedMacro();
|
||||
void ExportMacros();
|
||||
void ExportMacros() const;
|
||||
void ImportMacros();
|
||||
void ExpandAllActions();
|
||||
void ExpandAllElseActions();
|
||||
void ExpandAllConditions();
|
||||
void CollapseAllActions();
|
||||
void CollapseAllElseActions();
|
||||
void CollapseAllConditions();
|
||||
void MinimizeActions();
|
||||
void MaximizeActions();
|
||||
void MinimizeElseActions();
|
||||
void MaximizeElseActions();
|
||||
void MinimizeConditions();
|
||||
void MaximizeConditions();
|
||||
void SetElseActionsStateToHidden();
|
||||
void SetElseActionsStateToVisible();
|
||||
void MacroActionSelectionChanged(int idx);
|
||||
void MacroActionReorder(int to, int target);
|
||||
void AddMacroAction(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data);
|
||||
void AddMacroAction(int idx);
|
||||
void RemoveMacroAction(int idx);
|
||||
void MoveMacroActionUp(int idx);
|
||||
void MoveMacroActionDown(int idx);
|
||||
void MacroElseActionSelectionChanged(int idx);
|
||||
void MacroElseActionReorder(int to, int target);
|
||||
void AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data);
|
||||
void AddMacroElseAction(int idx);
|
||||
void RemoveMacroElseAction(int idx);
|
||||
void SwapElseActions(Macro *m, int pos1, int pos2);
|
||||
void MoveMacroElseActionUp(int idx);
|
||||
void MoveMacroElseActionDown(int idx);
|
||||
void MacroConditionSelectionChanged(int idx);
|
||||
void MacroConditionReorder(int to, int target);
|
||||
void AddMacroCondition(int idx);
|
||||
void AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data, Logic::Type logic);
|
||||
void RemoveMacroCondition(int idx);
|
||||
void MoveMacroConditionUp(int idx);
|
||||
void MoveMacroConditionDown(int idx);
|
||||
void HighlightControls();
|
||||
void HighlightOnChange();
|
||||
void HighlightOnChange() const;
|
||||
void on_macroSettings_clicked();
|
||||
void CopyMacroSegment();
|
||||
void PasteMacroSegment();
|
||||
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void MacroSegmentOrderChanged();
|
||||
void SegmentTempVarsChanged();
|
||||
void HighlightMacrosChanged(bool value);
|
||||
|
||||
void ConnectionAdded(const QString &);
|
||||
void ConnectionRenamed(const QString &oldName, const QString &newName);
|
||||
void ConnectionRemoved(const QString &);
|
||||
|
||||
private:
|
||||
enum class MacroSection { CONDITIONS, ACTIONS, ELSE_ACTIONS };
|
||||
|
||||
void SetupMacroSegmentSelection(MacroSection type, int idx);
|
||||
bool ResolveMacroImportNameConflict(std::shared_ptr<Macro> &);
|
||||
bool MacroTabIsInFocus();
|
||||
|
||||
MacroSection lastInteracted = MacroSection::CONDITIONS;
|
||||
int currentConditionIdx = -1;
|
||||
int currentActionIdx = -1;
|
||||
int currentElseActionIdx = -1;
|
||||
|
||||
/* --- End of macro tab section --- */
|
||||
|
||||
|
||||
243
lib/general.cpp
243
lib/general.cpp
@@ -3,6 +3,7 @@
|
||||
#include "filter-combo-box.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-settings.hpp"
|
||||
#include "path-helpers.hpp"
|
||||
#include "selection-helpers.hpp"
|
||||
#include "source-helpers.hpp"
|
||||
@@ -25,15 +26,6 @@ void AdvSceneSwitcher::reject()
|
||||
close();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::UpdateNonMatchingScene(const QString &name)
|
||||
{
|
||||
OBSSourceAutoRelease scene =
|
||||
obs_get_source_by_name(name.toUtf8().constData());
|
||||
OBSWeakSourceAutoRelease ws = obs_source_get_weak_source(scene);
|
||||
|
||||
switcher->nonMatchingScene = ws;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
|
||||
{
|
||||
if (loading) {
|
||||
@@ -55,7 +47,6 @@ void AdvSceneSwitcher::on_noMatchSwitch_clicked()
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = NoMatchBehavior::SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||
ui->randomDisabledWarning->setVisible(true);
|
||||
}
|
||||
|
||||
@@ -113,12 +104,12 @@ void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
|
||||
static_cast<SwitcherData::StartupBehavior>(index);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_logLevel_currentIndexChanged(int value)
|
||||
void AdvSceneSwitcher::on_logLevel_currentIndexChanged(int idx)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
switcher->logLevel = static_cast<SwitcherData::LogLevel>(value);
|
||||
SetLogLevel(static_cast<LogLevel>(ui->logLevel->itemData(idx).toInt()));
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
|
||||
@@ -131,17 +122,6 @@ void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
|
||||
switcher->autoStartEvent = static_cast<SwitcherData::AutoStart>(index);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
|
||||
const QString &text)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
UpdateNonMatchingScene(text);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
|
||||
{
|
||||
if (loading) {
|
||||
@@ -163,7 +143,7 @@ void AdvSceneSwitcher::closeEvent(QCloseEvent *)
|
||||
switcher->windowSize = this->size();
|
||||
switcher->macroListMacroEditSplitterPosition =
|
||||
ui->macroListMacroEditSplitter->sizes();
|
||||
MacroSelectionAboutToChange(); // Trigger saving of splitter states
|
||||
ui->macroEdit->SetMacro(nullptr); // Trigger saving of splitter states
|
||||
|
||||
obs_frontend_save();
|
||||
}
|
||||
@@ -205,6 +185,16 @@ void AdvSceneSwitcher::on_disableComboBoxFilter_stateChanged(int state)
|
||||
FilterComboBox::SetFilterBehaviourEnabled(!state);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_disableMacroWidgetCache_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
switcher->disableMacroWidgetCache = state;
|
||||
MacroSegmentList::SetCachingEnabled(!state);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_warnPluginLoadFailure_stateChanged(int state)
|
||||
{
|
||||
if (loading) {
|
||||
@@ -275,12 +265,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()
|
||||
@@ -383,6 +376,7 @@ void AdvSceneSwitcher::CheckFirstTimeSetup()
|
||||
switcher->firstBoot = false;
|
||||
DisplayMessage(
|
||||
obs_module_text("AdvSceneSwitcher.firstBootMessage"));
|
||||
switcher->Start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -437,16 +431,14 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
||||
}
|
||||
|
||||
// New post load steps to be declared during load
|
||||
postLoadSteps.clear();
|
||||
ClearPostLoadSteps();
|
||||
|
||||
// Needs to be loaded before any entries which might rely on scene group
|
||||
// selections to be available.
|
||||
loadSceneGroups(obj);
|
||||
LoadVariables(obj);
|
||||
|
||||
for (const auto &func : loadSteps) {
|
||||
func(obj);
|
||||
}
|
||||
RunLoadSteps(obj);
|
||||
|
||||
LoadMacros(obj);
|
||||
LoadGlobalMacroSettings(obj);
|
||||
@@ -502,18 +494,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,21 +511,28 @@ 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);
|
||||
obs_data_set_bool(obj, "disableFilterComboboxFilter",
|
||||
disableFilterComboboxFilter);
|
||||
obs_data_set_bool(obj, "disableMacroWidgetCache",
|
||||
disableMacroWidgetCache);
|
||||
obs_data_set_bool(obj, "warnPluginLoadFailure", warnPluginLoadFailure);
|
||||
obs_data_set_bool(obj, "hideLegacyTabs", hideLegacyTabs);
|
||||
|
||||
@@ -560,9 +557,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,34 +585,25 @@ 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");
|
||||
disableHints = obs_data_get_bool(obj, "disableHints");
|
||||
disableFilterComboboxFilter =
|
||||
obs_data_get_bool(obj, "disableFilterComboboxFilter");
|
||||
disableMacroWidgetCache =
|
||||
obs_data_get_bool(obj, "disableMacroWidgetCache");
|
||||
obs_data_set_default_bool(obj, "warnPluginLoadFailure", true);
|
||||
warnPluginLoadFailure = obs_data_get_bool(obj, "warnPluginLoadFailure");
|
||||
obs_data_set_default_bool(obj, "hideLegacyTabs", true);
|
||||
@@ -680,10 +673,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 +684,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 +847,7 @@ static void setupGeneralTabInactiveWarning(QTabWidget *tabs)
|
||||
inactiveTimer->start();
|
||||
}
|
||||
|
||||
void advss::AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
|
||||
void AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
|
||||
{
|
||||
auto macro = GetMacroWithInvalidConditionInterval();
|
||||
if (!macro) {
|
||||
@@ -857,8 +871,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 +882,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 +915,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(
|
||||
@@ -904,6 +927,9 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
||||
switcher->disableFilterComboboxFilter);
|
||||
FilterComboBox::SetFilterBehaviourEnabled(
|
||||
!switcher->disableFilterComboboxFilter);
|
||||
ui->disableMacroWidgetCache->setChecked(
|
||||
switcher->disableMacroWidgetCache);
|
||||
MacroSegmentList::SetCachingEnabled(!switcher->disableMacroWidgetCache);
|
||||
ui->warnPluginLoadFailure->setChecked(switcher->warnPluginLoadFailure);
|
||||
ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs);
|
||||
|
||||
@@ -917,6 +943,75 @@ 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();
|
||||
});
|
||||
|
||||
// Set up status control
|
||||
auto statusControl = new StatusControl(this, true);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#endif
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "kwin-helpers.h"
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -44,6 +45,10 @@ static XScreenSaverAllocInfoFunc allocSSFunc = nullptr;
|
||||
static XScreenSaverQueryInfoFunc querySSFunc = nullptr;
|
||||
bool canGetIdleTime = false;
|
||||
|
||||
static bool KWin = false;
|
||||
static FocusNotifier notifier;
|
||||
static QString KWinScriptObjectPath;
|
||||
|
||||
static QLibrary *libprocps = nullptr;
|
||||
#ifdef PROCPS_AVAILABLE
|
||||
typedef PROCTAB *(*openproc_func)(int flags);
|
||||
@@ -275,6 +280,11 @@ int getActiveWindow(Window *&window)
|
||||
|
||||
void GetCurrentWindowTitle(std::string &title)
|
||||
{
|
||||
if (KWin) {
|
||||
title = FocusNotifier::getActiveWindowTitle();
|
||||
return;
|
||||
}
|
||||
|
||||
Window *data = 0;
|
||||
if (getActiveWindow(data) != Success || !data) {
|
||||
return;
|
||||
@@ -286,6 +296,7 @@ void GetCurrentWindowTitle(std::string &title)
|
||||
|
||||
auto name = getWindowName(data[0]);
|
||||
XFree(data);
|
||||
|
||||
if (name.empty()) {
|
||||
return;
|
||||
}
|
||||
@@ -412,6 +423,10 @@ void GetProcessList(QStringList &processes)
|
||||
|
||||
long getForegroundProcessPid()
|
||||
{
|
||||
if (KWin) {
|
||||
return FocusNotifier::getActiveWindowPID();
|
||||
}
|
||||
|
||||
Window *window;
|
||||
if (getActiveWindow(window) != Success || !window || !*window) {
|
||||
return -1;
|
||||
@@ -437,6 +452,7 @@ long getForegroundProcessPid()
|
||||
|
||||
pid = *((long *)prop);
|
||||
XFree(prop);
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
@@ -562,6 +578,17 @@ void PlatformInit()
|
||||
return;
|
||||
}
|
||||
|
||||
KWin = isKWinAvailable();
|
||||
if (!(KWin && startKWinScript(KWinScriptObjectPath) &&
|
||||
registerKWinDBusListener(¬ifier))) {
|
||||
// something bad happened while trying to initialize
|
||||
// the KWin script/dbus so disable it
|
||||
KWin = false;
|
||||
blog(LOG_INFO, "not using KWin compat");
|
||||
} else {
|
||||
blog(LOG_INFO, "using KWin compat");
|
||||
}
|
||||
|
||||
initXss();
|
||||
initProcps();
|
||||
initProc2();
|
||||
@@ -583,6 +610,8 @@ void PlatformCleanup()
|
||||
cleanupHelper(libproc2);
|
||||
cleanupDisplay();
|
||||
XSetErrorHandler(NULL);
|
||||
if (KWin && !KWinScriptObjectPath.isEmpty())
|
||||
stopKWinScript(KWinScriptObjectPath);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
166
lib/linux/kwin-helpers.cpp
Normal file
166
lib/linux/kwin-helpers.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "kwin-helpers.h"
|
||||
|
||||
#include "log-helper.hpp"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileDevice>
|
||||
#include <QTextStream>
|
||||
#include <QtDBus/QDBusConnectionInterface>
|
||||
#include <QtDBus/QDBusInterface>
|
||||
#include <QtDBus/QDBusReply>
|
||||
|
||||
namespace advss {
|
||||
|
||||
int FocusNotifier::activePID = -1;
|
||||
std::string FocusNotifier::activeTitle = {};
|
||||
|
||||
int FocusNotifier::getActiveWindowPID()
|
||||
{
|
||||
return activePID;
|
||||
}
|
||||
|
||||
std::string FocusNotifier::getActiveWindowTitle()
|
||||
{
|
||||
return activeTitle;
|
||||
}
|
||||
|
||||
void FocusNotifier::focusChanged(const int pid)
|
||||
{
|
||||
activePID = pid;
|
||||
}
|
||||
|
||||
void FocusNotifier::focusTitle(const QString &title)
|
||||
{
|
||||
activeTitle = title.toStdString();
|
||||
}
|
||||
|
||||
bool isKWinAvailable()
|
||||
{
|
||||
const QDBusConnectionInterface *interface =
|
||||
QDBusConnection::sessionBus().interface();
|
||||
if (!interface)
|
||||
return false;
|
||||
|
||||
const QStringList services =
|
||||
interface->registeredServiceNames().value();
|
||||
return services.contains("org.kde.KWin");
|
||||
}
|
||||
|
||||
bool startKWinScript(QString &scriptObjectPath)
|
||||
{
|
||||
const QString scriptPath =
|
||||
"/tmp/AdvancedSceneSwitcher/KWinFocusNotifier.js";
|
||||
|
||||
const QString script =
|
||||
R"(workspace.windowActivated.connect(function(client) {
|
||||
if (!client) return;
|
||||
if (!client.pid) return;
|
||||
if (!client.caption) return;
|
||||
|
||||
callDBus(
|
||||
"com.github.AdvancedSceneSwitcher",
|
||||
"/com/github/AdvancedSceneSwitcher",
|
||||
"com.github.AdvancedSceneSwitcher",
|
||||
"focusChanged",
|
||||
client.pid
|
||||
);
|
||||
callDBus(
|
||||
"com.github.AdvancedSceneSwitcher",
|
||||
"/com/github/AdvancedSceneSwitcher",
|
||||
"com.github.AdvancedSceneSwitcher",
|
||||
"focusTitle",
|
||||
client.caption
|
||||
);
|
||||
}))";
|
||||
|
||||
if (const QDir dir; !dir.mkpath(QFileInfo(scriptPath).absolutePath())) {
|
||||
blog(LOG_ERROR, "error creating /tmp/AdvancedSceneSwitcher");
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile scriptFile(scriptPath);
|
||||
if (!scriptFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
blog(LOG_ERROR,
|
||||
"error opening KWinFocusNotifier.js for writing");
|
||||
return false;
|
||||
}
|
||||
|
||||
scriptFile.setPermissions(QFileDevice::ReadOwner |
|
||||
QFileDevice::WriteOwner);
|
||||
QTextStream outputStream(&scriptFile);
|
||||
outputStream << script;
|
||||
scriptFile.close();
|
||||
|
||||
const QDBusConnection bus = QDBusConnection::sessionBus();
|
||||
|
||||
QDBusInterface scriptingIface("org.kde.KWin", "/Scripting",
|
||||
"org.kde.kwin.Scripting", bus);
|
||||
if (!scriptingIface.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const QDBusReply<bool> scriptRunningReply =
|
||||
scriptingIface.call("isScriptLoaded", scriptPath);
|
||||
if (scriptRunningReply.isValid() && scriptRunningReply.value()) {
|
||||
// script already registered and running, don't do it again
|
||||
// this will leave the script running since we do not have
|
||||
// a valid script id anymore, but at the very least this prevents
|
||||
// it from running multiple times
|
||||
return true;
|
||||
}
|
||||
|
||||
const QDBusReply<int> scriptIdReply =
|
||||
scriptingIface.call("loadScript", scriptPath);
|
||||
if (!scriptIdReply.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int scriptId = scriptIdReply.value();
|
||||
scriptObjectPath =
|
||||
QString("/Scripting/Script%1").arg(QString::number(scriptId));
|
||||
|
||||
QDBusInterface scriptRunner("org.kde.KWin", scriptObjectPath,
|
||||
"org.kde.kwin.Script", bus);
|
||||
if (!scriptRunner.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const QDBusReply<void> runReply = scriptRunner.call("run");
|
||||
return runReply.isValid();
|
||||
}
|
||||
|
||||
bool stopKWinScript(const QString &scriptObjectPath)
|
||||
{
|
||||
QDBusInterface scriptRunner("org.kde.KWin", scriptObjectPath,
|
||||
"org.kde.kwin.Script",
|
||||
QDBusConnection::sessionBus());
|
||||
if (!scriptRunner.isValid()) {
|
||||
return false;
|
||||
}
|
||||
const QDBusReply<void> stopReply = scriptRunner.call("stop");
|
||||
return stopReply.isValid();
|
||||
}
|
||||
|
||||
bool registerKWinDBusListener(FocusNotifier *notifier)
|
||||
{
|
||||
static const QString serviceName = "com.github.AdvancedSceneSwitcher";
|
||||
static const QString objectPath = "/com/github/AdvancedSceneSwitcher";
|
||||
auto bus = QDBusConnection::sessionBus();
|
||||
|
||||
if (bus.objectRegisteredAt(objectPath)) {
|
||||
// already registered?
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!bus.registerService(serviceName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!bus.registerObject(objectPath, notifier,
|
||||
QDBusConnection::ExportAllSlots)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace advss
|
||||
33
lib/linux/kwin-helpers.h
Normal file
33
lib/linux/kwin-helpers.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <string>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class FocusNotifier final : public QObject {
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "com.github.AdvancedSceneSwitcher")
|
||||
|
||||
static int activePID;
|
||||
static std::string activeTitle;
|
||||
|
||||
public:
|
||||
using QObject::QObject;
|
||||
|
||||
static int getActiveWindowPID();
|
||||
static std::string getActiveWindowTitle();
|
||||
|
||||
public slots:
|
||||
void focusChanged(const int pid);
|
||||
void focusTitle(const QString &title);
|
||||
};
|
||||
|
||||
bool isKWinAvailable();
|
||||
bool startKWinScript(QString &scriptObjectPath);
|
||||
bool stopKWinScript(const QString &scriptObjectPath);
|
||||
bool registerKWinDBusListener(FocusNotifier *notifier);
|
||||
void printDBusError();
|
||||
|
||||
} // namespace advss
|
||||
@@ -35,12 +35,14 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
_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);
|
||||
@@ -61,12 +63,40 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData(id);
|
||||
SetupWidgets(true);
|
||||
|
||||
_actionStateTimer.start(300);
|
||||
actionStateTimer->start(300);
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetupWidgets(bool basicSetup)
|
||||
{
|
||||
if (_allWidgetsAreSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto id = (*_entryData)->GetId();
|
||||
_actionSelection->setCurrentText(
|
||||
obs_module_text(MacroActionFactory::GetActionName(id).c_str()));
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
_enable->setChecked(enabled);
|
||||
SetDisableEffect(!enabled);
|
||||
HeaderInfoChanged(
|
||||
QString::fromStdString((*_entryData)->GetShortDesc()));
|
||||
|
||||
if (basicSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetFocusPolicyOfWidgets();
|
||||
|
||||
_allWidgetsAreSetup = true;
|
||||
}
|
||||
|
||||
void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
@@ -96,22 +126,6 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
SetFocusPolicyOfWidgets();
|
||||
}
|
||||
|
||||
void MacroActionEdit::UpdateEntryData(const std::string &id)
|
||||
{
|
||||
_actionSelection->setCurrentText(
|
||||
obs_module_text(MacroActionFactory::GetActionName(id).c_str()));
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
_enable->setChecked(enabled);
|
||||
SetDisableEffect(!enabled);
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
HeaderInfoChanged(
|
||||
QString::fromStdString((*_entryData)->GetShortDesc()));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetFocusPolicyOfWidgets();
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetEntryData(std::shared_ptr<MacroAction> *data)
|
||||
{
|
||||
_entryData = data;
|
||||
@@ -144,473 +158,4 @@ std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
||||
return *_entryData;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroAction(Macro *macro, int idx,
|
||||
const std::string &id, obs_data_t *data)
|
||||
{
|
||||
if (idx < 0 || idx > (int)macro->Actions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
macro->Actions().emplace(macro->Actions().begin() + idx,
|
||||
MacroActionFactory::Create(id, macro));
|
||||
if (data) {
|
||||
macro->Actions().at(idx)->Load(data);
|
||||
}
|
||||
macro->Actions().at(idx)->PostLoad();
|
||||
RunPostLoadSteps();
|
||||
macro->UpdateActionIndices();
|
||||
ui->actionsList->Insert(
|
||||
idx,
|
||||
new MacroActionEdit(this, ¯o->Actions()[idx], id));
|
||||
SetActionData(*macro);
|
||||
}
|
||||
HighlightAction(idx);
|
||||
ui->actionsList->SetHelpMsgVisible(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroAction(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > (int)macro->Actions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id;
|
||||
if (idx - 1 >= 0) {
|
||||
id = macro->Actions().at(idx - 1)->GetId();
|
||||
} else {
|
||||
id = MacroAction::GetDefaultID();
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data;
|
||||
if (idx - 1 >= 0) {
|
||||
data = obs_data_create();
|
||||
macro->Actions().at(idx - 1)->Save(data);
|
||||
}
|
||||
AddMacroAction(macro.get(), idx, id, data);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionAdd_clicked()
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentActionIdx == -1) {
|
||||
AddMacroAction((int)macro->Actions().size());
|
||||
} else {
|
||||
AddMacroAction(currentActionIdx + 1);
|
||||
}
|
||||
if (currentActionIdx != -1) {
|
||||
MacroActionSelectionChanged(currentActionIdx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacroAction(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= (int)macro->Actions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
ui->actionsList->Remove(idx);
|
||||
macro->Actions().erase(macro->Actions().begin() + idx);
|
||||
SetMacroAbortWait(true);
|
||||
GetMacroWaitCV().notify_all();
|
||||
macro->UpdateActionIndices();
|
||||
SetActionData(*macro);
|
||||
}
|
||||
MacroActionSelectionChanged(-1);
|
||||
lastInteracted = MacroSection::ACTIONS;
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionRemove_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1) {
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
RemoveMacroAction((int)macro->Actions().size() - 1);
|
||||
} else {
|
||||
RemoveMacroAction(currentActionIdx);
|
||||
}
|
||||
MacroActionSelectionChanged(-1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionTop_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
MacroActionReorder(0, currentActionIdx);
|
||||
MacroActionSelectionChanged(0);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionUp_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1 || currentActionIdx == 0) {
|
||||
return;
|
||||
}
|
||||
MoveMacroActionUp(currentActionIdx);
|
||||
MacroActionSelectionChanged(currentActionIdx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionDown_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1 ||
|
||||
currentActionIdx == ui->actionsList->ContentLayout()->count() - 1) {
|
||||
return;
|
||||
}
|
||||
MoveMacroActionDown(currentActionIdx);
|
||||
MacroActionSelectionChanged(currentActionIdx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionBottom_clicked()
|
||||
{
|
||||
if (currentActionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
const int newIdx = ui->actionsList->ContentLayout()->count() - 1;
|
||||
MacroActionReorder(newIdx, currentActionIdx);
|
||||
MacroActionSelectionChanged(newIdx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionAdd_clicked()
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentElseActionIdx == -1) {
|
||||
AddMacroElseAction((int)macro->ElseActions().size());
|
||||
} else {
|
||||
AddMacroElseAction(currentElseActionIdx + 1);
|
||||
}
|
||||
if (currentElseActionIdx != -1) {
|
||||
MacroElseActionSelectionChanged(currentElseActionIdx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionRemove_clicked()
|
||||
{
|
||||
if (currentElseActionIdx == -1) {
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
RemoveMacroElseAction((int)macro->ElseActions().size() - 1);
|
||||
} else {
|
||||
RemoveMacroElseAction(currentElseActionIdx);
|
||||
}
|
||||
MacroElseActionSelectionChanged(-1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionTop_clicked()
|
||||
{
|
||||
if (currentElseActionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
MacroElseActionReorder(0, currentElseActionIdx);
|
||||
MacroElseActionSelectionChanged(0);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionUp_clicked()
|
||||
{
|
||||
if (currentElseActionIdx == -1 || currentElseActionIdx == 0) {
|
||||
return;
|
||||
}
|
||||
MoveMacroElseActionUp(currentElseActionIdx);
|
||||
MacroElseActionSelectionChanged(currentElseActionIdx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionDown_clicked()
|
||||
{
|
||||
if (currentElseActionIdx == -1 ||
|
||||
currentElseActionIdx ==
|
||||
ui->elseActionsList->ContentLayout()->count() - 1) {
|
||||
return;
|
||||
}
|
||||
MoveMacroElseActionDown(currentElseActionIdx);
|
||||
MacroElseActionSelectionChanged(currentElseActionIdx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_elseActionBottom_clicked()
|
||||
{
|
||||
if (currentElseActionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
const int newIdx = ui->elseActionsList->ContentLayout()->count() - 1;
|
||||
MacroElseActionReorder(newIdx, currentElseActionIdx);
|
||||
MacroElseActionSelectionChanged(newIdx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SwapActions(Macro *m, int pos1, int pos2)
|
||||
{
|
||||
if (pos1 == pos2) {
|
||||
return;
|
||||
}
|
||||
if (pos1 > pos2) {
|
||||
std::swap(pos1, pos2);
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
iter_swap(m->Actions().begin() + pos1, m->Actions().begin() + pos2);
|
||||
m->UpdateActionIndices();
|
||||
auto widget1 = static_cast<MacroActionEdit *>(
|
||||
ui->actionsList->ContentLayout()->takeAt(pos1)->widget());
|
||||
auto widget2 = static_cast<MacroActionEdit *>(
|
||||
ui->actionsList->ContentLayout()->takeAt(pos2 - 1)->widget());
|
||||
ui->actionsList->Insert(pos1, widget2);
|
||||
ui->actionsList->Insert(pos2, widget1);
|
||||
SetActionData(*m);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroActionUp(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 1 || idx >= (int)macro->Actions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapActions(macro.get(), idx, idx - 1);
|
||||
HighlightAction(idx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroActionDown(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= (int)macro->Actions().size() - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapActions(macro.get(), idx, idx + 1);
|
||||
HighlightAction(idx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroElseActionSelectionChanged(int idx)
|
||||
{
|
||||
SetupMacroSegmentSelection(MacroSection::ELSE_ACTIONS, idx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroElseActionReorder(int to, int from)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (to == from || from < 0 || from > (int)macro->ElseActions().size() ||
|
||||
to < 0 || to > (int)macro->ElseActions().size()) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto action = macro->ElseActions().at(from);
|
||||
macro->ElseActions().erase(macro->ElseActions().begin() + from);
|
||||
macro->ElseActions().insert(macro->ElseActions().begin() + to,
|
||||
action);
|
||||
macro->UpdateElseActionIndices();
|
||||
ui->elseActionsList->ContentLayout()->insertItem(
|
||||
to, ui->elseActionsList->ContentLayout()->takeAt(from));
|
||||
SetElseActionData(*macro);
|
||||
}
|
||||
HighlightElseAction(to);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroElseAction(Macro *macro, int idx,
|
||||
const std::string &id,
|
||||
obs_data_t *data)
|
||||
{
|
||||
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
macro->ElseActions().emplace(macro->ElseActions().begin() + idx,
|
||||
MacroActionFactory::Create(id,
|
||||
macro));
|
||||
if (data) {
|
||||
macro->ElseActions().at(idx)->Load(data);
|
||||
}
|
||||
macro->ElseActions().at(idx)->PostLoad();
|
||||
RunPostLoadSteps();
|
||||
macro->UpdateElseActionIndices();
|
||||
ui->elseActionsList->Insert(
|
||||
idx, new MacroActionEdit(
|
||||
this, ¯o->ElseActions()[idx], id));
|
||||
SetElseActionData(*macro);
|
||||
}
|
||||
HighlightElseAction(idx);
|
||||
ui->elseActionsList->SetHelpMsgVisible(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroElseAction(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id;
|
||||
if (idx - 1 >= 0) {
|
||||
id = macro->ElseActions().at(idx - 1)->GetId();
|
||||
} else {
|
||||
id = MacroAction::GetDefaultID();
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data;
|
||||
if (idx - 1 >= 0) {
|
||||
data = obs_data_create();
|
||||
macro->ElseActions().at(idx - 1)->Save(data);
|
||||
}
|
||||
AddMacroElseAction(macro.get(), idx, id, data);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacroElseAction(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= (int)macro->ElseActions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
ui->elseActionsList->Remove(idx);
|
||||
macro->ElseActions().erase(macro->ElseActions().begin() + idx);
|
||||
SetMacroAbortWait(true);
|
||||
GetMacroWaitCV().notify_all();
|
||||
macro->UpdateElseActionIndices();
|
||||
SetElseActionData(*macro);
|
||||
}
|
||||
MacroElseActionSelectionChanged(-1);
|
||||
lastInteracted = MacroSection::ELSE_ACTIONS;
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SwapElseActions(Macro *m, int pos1, int pos2)
|
||||
{
|
||||
if (pos1 == pos2) {
|
||||
return;
|
||||
}
|
||||
if (pos1 > pos2) {
|
||||
std::swap(pos1, pos2);
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
iter_swap(m->ElseActions().begin() + pos1,
|
||||
m->ElseActions().begin() + pos2);
|
||||
m->UpdateElseActionIndices();
|
||||
auto widget1 = static_cast<MacroActionEdit *>(
|
||||
ui->elseActionsList->ContentLayout()->takeAt(pos1)->widget());
|
||||
auto widget2 = static_cast<MacroActionEdit *>(
|
||||
ui->elseActionsList->ContentLayout()
|
||||
->takeAt(pos2 - 1)
|
||||
->widget());
|
||||
ui->elseActionsList->Insert(pos1, widget2);
|
||||
ui->elseActionsList->Insert(pos2, widget1);
|
||||
SetElseActionData(*m);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroElseActionUp(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 1 || idx >= (int)macro->ElseActions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapElseActions(macro.get(), idx, idx - 1);
|
||||
HighlightElseAction(idx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroElseActionDown(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= (int)macro->ElseActions().size() - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapElseActions(macro.get(), idx, idx + 1);
|
||||
HighlightElseAction(idx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroActionSelectionChanged(int idx)
|
||||
{
|
||||
SetupMacroSegmentSelection(MacroSection::ACTIONS, idx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroActionReorder(int to, int from)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (to == from || from < 0 || from > (int)macro->Actions().size() ||
|
||||
to < 0 || to > (int)macro->Actions().size()) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto action = macro->Actions().at(from);
|
||||
macro->Actions().erase(macro->Actions().begin() + from);
|
||||
macro->Actions().insert(macro->Actions().begin() + to, action);
|
||||
macro->UpdateActionIndices();
|
||||
ui->actionsList->ContentLayout()->insertItem(
|
||||
to, ui->actionsList->ContentLayout()->takeAt(from));
|
||||
SetActionData(*macro);
|
||||
}
|
||||
HighlightAction(to);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
QWidget *parent = nullptr,
|
||||
std::shared_ptr<MacroAction> * = nullptr,
|
||||
const std::string &id = MacroAction::GetDefaultID().data());
|
||||
void UpdateEntryData(const std::string &id);
|
||||
void SetupWidgets(bool basicSetup = false);
|
||||
void SetEntryData(std::shared_ptr<MacroAction> *);
|
||||
|
||||
private slots:
|
||||
@@ -32,7 +32,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,
|
||||
|
||||
@@ -12,27 +12,13 @@ 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()
|
||||
{
|
||||
if (_action == Action::NESTED_MACRO) {
|
||||
const bool conditionsMatched = _nestedMacro->CheckConditions();
|
||||
return _nestedMacro->PerformActions(conditionsMatched);
|
||||
}
|
||||
|
||||
auto macro = _macro.GetMacro();
|
||||
if (!macro) {
|
||||
return true;
|
||||
@@ -45,10 +31,13 @@ bool MacroActionMacro::PerformAction()
|
||||
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:
|
||||
case Action::RUN_ACTIONS:
|
||||
RunActions(macro.get());
|
||||
break;
|
||||
case Action::STOP:
|
||||
@@ -96,7 +85,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 +104,9 @@ void MacroActionMacro::LogAction() const
|
||||
ablog(LOG_INFO, "toggled action %d of macro \"%s\"",
|
||||
_actionIndex.GetValue(), macro->Name().c_str());
|
||||
break;
|
||||
case Action::NESTED_MACRO:
|
||||
ablog(LOG_INFO, "run nested macro");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -127,6 +119,10 @@ bool MacroActionMacro::Save(obs_data_t *obj) const
|
||||
_actionIndex.Save(obj, "actionIndex");
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
_runOptions.Save(obj);
|
||||
OBSDataAutoRelease nestedMacroData = obs_data_create();
|
||||
_nestedMacro->Save(nestedMacroData);
|
||||
obs_data_set_obj(obj, "nestedMacro", nestedMacroData);
|
||||
obs_data_set_int(obj, "customWidgetHeight", _customWidgetHeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -138,6 +134,15 @@ bool MacroActionMacro::Load(obs_data_t *obj)
|
||||
_action = static_cast<MacroActionMacro::Action>(
|
||||
obs_data_get_int(obj, "action"));
|
||||
_runOptions.Load(obj);
|
||||
|
||||
if (obs_data_has_user_value(obj, "nestedMacro")) {
|
||||
OBSDataAutoRelease nestedMacroData =
|
||||
obs_data_get_obj(obj, "nestedMacro");
|
||||
_nestedMacro->Load(nestedMacroData);
|
||||
}
|
||||
|
||||
_customWidgetHeight = obs_data_get_int(obj, "customWidgetHeight");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -146,6 +151,7 @@ bool MacroActionMacro::PostLoad()
|
||||
MacroRefAction::PostLoad();
|
||||
MacroAction::PostLoad();
|
||||
_runOptions.macro.PostLoad();
|
||||
_nestedMacro->PostLoad();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -161,7 +167,17 @@ 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()
|
||||
@@ -210,8 +226,33 @@ void MacroActionMacro::RunActions(Macro *actionMacro) const
|
||||
|
||||
static void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[_, name] : actionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()));
|
||||
static const std::vector<std::pair<MacroActionMacro::Action, std::string>>
|
||||
actions = {
|
||||
{MacroActionMacro::Action::PAUSE,
|
||||
"AdvSceneSwitcher.action.macro.type.pause"},
|
||||
{MacroActionMacro::Action::UNPAUSE,
|
||||
"AdvSceneSwitcher.action.macro.type.unpause"},
|
||||
{MacroActionMacro::Action::TOGGLE_PAUSE,
|
||||
"AdvSceneSwitcher.action.macro.type.togglePause"},
|
||||
{MacroActionMacro::Action::RESET_COUNTER,
|
||||
"AdvSceneSwitcher.action.macro.type.resetCounter"},
|
||||
{MacroActionMacro::Action::NESTED_MACRO,
|
||||
"AdvSceneSwitcher.action.macro.type.nestedMacro"},
|
||||
{MacroActionMacro::Action::RUN_ACTIONS,
|
||||
"AdvSceneSwitcher.action.macro.type.run"},
|
||||
{MacroActionMacro::Action::STOP,
|
||||
"AdvSceneSwitcher.action.macro.type.stop"},
|
||||
{MacroActionMacro::Action::DISABLE_ACTION,
|
||||
"AdvSceneSwitcher.action.macro.type.disableAction"},
|
||||
{MacroActionMacro::Action::ENABLE_ACTION,
|
||||
"AdvSceneSwitcher.action.macro.type.enableAction"},
|
||||
{MacroActionMacro::Action::TOGGLE_ACTION,
|
||||
"AdvSceneSwitcher.action.macro.type.toggleAction"},
|
||||
};
|
||||
|
||||
for (const auto &[value, name] : actions) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +276,7 @@ static void populateActionTypeSelection(QComboBox *list)
|
||||
|
||||
MacroActionMacroEdit::MacroActionMacroEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionMacro> entryData)
|
||||
: QWidget(parent),
|
||||
: ResizableWidget(parent),
|
||||
_macros(new MacroSelection(parent)),
|
||||
_actionIndex(new MacroSegmentSelection(
|
||||
this, MacroSegmentSelection::Type::ACTION)),
|
||||
@@ -254,7 +295,13 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
||||
_entryLayout(new QHBoxLayout()),
|
||||
_conditionLayout(new QHBoxLayout()),
|
||||
_reevaluateConditionStateLayout(new QHBoxLayout()),
|
||||
_setInputsLayout(new QHBoxLayout())
|
||||
_setInputsLayout(new QHBoxLayout()),
|
||||
_nestedMacro(new MacroEdit(
|
||||
this,
|
||||
QStringList()
|
||||
<< "AdvSceneSwitcher.action.macro.type.nestedMacro.conditionHelp"
|
||||
<< "AdvSceneSwitcher.action.macro.type.nestedMacro.actionHelp"
|
||||
<< "AdvSceneSwitcher.action.macro.type.nestedMacro.elseActionHelp"))
|
||||
{
|
||||
populateActionSelection(_actions);
|
||||
populateConditionBehaviorSelection(_conditionBehaviors);
|
||||
@@ -303,6 +350,7 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
||||
layout->addLayout(_setInputsLayout);
|
||||
layout->addWidget(_inputs);
|
||||
layout->addWidget(_skipWhenPaused);
|
||||
layout->addWidget(_nestedMacro);
|
||||
setLayout(layout);
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
@@ -314,6 +362,12 @@ void HighlightMacroSettingsButton(bool enable);
|
||||
MacroActionMacroEdit::~MacroActionMacroEdit()
|
||||
{
|
||||
HighlightMacroSettingsButton(false);
|
||||
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
_entryData->_customWidgetHeight = GetCustomHeight();
|
||||
_nestedMacro->SetMacro({}); // Save splitter states
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::UpdateEntryData()
|
||||
@@ -321,7 +375,8 @@ void MacroActionMacroEdit::UpdateEntryData()
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
_actions->setCurrentIndex(
|
||||
_actions->findData(static_cast<int>(_entryData->_action)));
|
||||
_actionIndex->SetValue(_entryData->_actionIndex);
|
||||
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
|
||||
_macros->SetCurrentMacro(_entryData->_macro);
|
||||
@@ -335,9 +390,20 @@ void MacroActionMacroEdit::UpdateEntryData()
|
||||
_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 +416,11 @@ void MacroActionMacroEdit::MacroChanged(const QString &text)
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::ActionChanged(int value)
|
||||
void MacroActionMacroEdit::ActionChanged(int idx)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_action = static_cast<MacroActionMacro::Action>(value);
|
||||
_entryData->_action = static_cast<MacroActionMacro::Action>(
|
||||
_actions->itemData(idx).toInt());
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -435,7 +502,8 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
_entryData->_action == MacroActionMacro::Action::RUN
|
||||
_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN_ACTIONS
|
||||
? "AdvSceneSwitcher.action.macro.entry.run"
|
||||
: "AdvSceneSwitcher.action.macro.entry.other"),
|
||||
_entryLayout, placeholders);
|
||||
@@ -451,7 +519,7 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
||||
_conditionLayout, placeholders);
|
||||
}
|
||||
|
||||
if (_entryData->_action == MacroActionMacro::Action::RUN ||
|
||||
if (_entryData->_action == MacroActionMacro::Action::RUN_ACTIONS ||
|
||||
_entryData->_action == MacroActionMacro::Action::STOP) {
|
||||
_macros->HideSelectedMacro();
|
||||
} else {
|
||||
@@ -467,27 +535,43 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
||||
_actionIndex->setVisible(isModifyingActionState);
|
||||
|
||||
SetLayoutVisible(_conditionLayout,
|
||||
_entryData->_action == MacroActionMacro::Action::RUN);
|
||||
_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN_ACTIONS);
|
||||
const bool needsAdditionalConditionWidgets =
|
||||
_entryData->_action == MacroActionMacro::Action::RUN &&
|
||||
_entryData->_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);
|
||||
_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN_ACTIONS);
|
||||
_inputs->setVisible(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN &&
|
||||
MacroActionMacro::Action::RUN_ACTIONS &&
|
||||
_entryData->_runOptions.setInputs);
|
||||
HighlightMacroSettingsButton(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN &&
|
||||
_entryData->_runOptions.setInputs &&
|
||||
!_inputs->HasInputsToSet());
|
||||
HighlightMacroSettingsButton(
|
||||
_entryData->_action == MacroActionMacro::Action::RUN_ACTIONS &&
|
||||
_entryData->_runOptions.setInputs &&
|
||||
!_inputs->HasInputsToSet());
|
||||
_actionTypes->setVisible(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN);
|
||||
MacroActionMacro::Action::RUN_ACTIONS);
|
||||
_skipWhenPaused->setVisible(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN);
|
||||
MacroActionMacro::Action::RUN_ACTIONS);
|
||||
|
||||
_nestedMacro->setVisible(_entryData->_action ==
|
||||
MacroActionMacro::Action::NESTED_MACRO);
|
||||
_macros->setVisible(_entryData->_action !=
|
||||
MacroActionMacro::Action::NESTED_MACRO);
|
||||
SetResizingEnabled(_entryData->_action ==
|
||||
MacroActionMacro::Action::NESTED_MACRO);
|
||||
|
||||
if (_nestedMacro->IsEmpty()) {
|
||||
_nestedMacro->ShowAllMacroSections();
|
||||
// TODO: find a better solution than setting a fixed height
|
||||
_entryData->_customWidgetHeight = 600;
|
||||
}
|
||||
SetCustomHeight(_entryData->_customWidgetHeight);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#pragma once
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-edit.hpp"
|
||||
#include "macro-input.hpp"
|
||||
#include "macro-selection.hpp"
|
||||
#include "macro-segment-selection.hpp"
|
||||
#include "resizable-widget.hpp"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QHBoxLayout>
|
||||
@@ -44,15 +47,19 @@ public:
|
||||
PAUSE,
|
||||
UNPAUSE,
|
||||
RESET_COUNTER,
|
||||
RUN,
|
||||
RUN_ACTIONS,
|
||||
STOP,
|
||||
DISABLE_ACTION,
|
||||
ENABLE_ACTION,
|
||||
TOGGLE_ACTION,
|
||||
TOGGLE_PAUSE,
|
||||
NESTED_MACRO,
|
||||
};
|
||||
Action _action = Action::RUN;
|
||||
Action _action = Action::NESTED_MACRO;
|
||||
IntVariable _actionIndex = 1;
|
||||
RunOptions _runOptions = {};
|
||||
std::shared_ptr<Macro> _nestedMacro = std::make_shared<Macro>();
|
||||
int _customWidgetHeight = 0;
|
||||
|
||||
private:
|
||||
void RunActions(Macro *actionMacro) const;
|
||||
@@ -61,7 +68,7 @@ private:
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionMacroEdit final : public QWidget {
|
||||
class MacroActionMacroEdit final : public ResizableWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@@ -70,13 +77,7 @@ 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);
|
||||
@@ -111,6 +112,7 @@ private:
|
||||
QHBoxLayout *_conditionLayout;
|
||||
QHBoxLayout *_reevaluateConditionStateLayout;
|
||||
QHBoxLayout *_setInputsLayout;
|
||||
MacroEdit *_nestedMacro;
|
||||
|
||||
std::shared_ptr<MacroActionMacro> _entryData;
|
||||
bool _loading = true;
|
||||
|
||||
@@ -170,11 +170,7 @@ void MacroActionQueueEdit::UpdateEntryData()
|
||||
|
||||
void MacroActionQueueEdit::MacroChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_macro = text;
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
@@ -182,11 +178,7 @@ void MacroActionQueueEdit::MacroChanged(const QString &text)
|
||||
|
||||
void MacroActionQueueEdit::QueueChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_queue = GetWeakActionQueueByQString(text);
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
@@ -194,11 +186,7 @@ void MacroActionQueueEdit::QueueChanged(const QString &text)
|
||||
|
||||
void MacroActionQueueEdit::ActionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_action = static_cast<MacroActionQueue::Action>(value);
|
||||
SetWidgetVisibility();
|
||||
emit HeaderInfoChanged(
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#include "macro-action-variable.hpp"
|
||||
#include "advanced-scene-switcher.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>
|
||||
@@ -385,6 +387,22 @@ bool MacroActionVariable::PerformAction()
|
||||
var->SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
case Action::QUERY_JSON: {
|
||||
auto value = QueryJson(var->Value(), _jsonQuery);
|
||||
if (!value.has_value()) {
|
||||
return true;
|
||||
}
|
||||
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) {
|
||||
@@ -462,7 +480,7 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
_inputPlaceholder.Save(obj, "inputPlaceholder");
|
||||
_envVariableName.Save(obj, "environmentVariableName");
|
||||
_scene.Save(obj);
|
||||
_tempVar.Save(obj);
|
||||
_tempVar.Save(obj, GetMacro());
|
||||
_sceneItemIndex.Save(obj, "sceneItemIndex");
|
||||
obs_data_set_int(obj, "direction", static_cast<int>(_direction));
|
||||
_stringLength.Save(obj, "stringLength");
|
||||
@@ -471,6 +489,8 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
_randomNumberStart.Save(obj, "randomNumberStart");
|
||||
_randomNumberEnd.Save(obj, "randomNumberEnd");
|
||||
obs_data_set_bool(obj, "generateInteger", _generateInteger);
|
||||
_jsonQuery.Save(obj, "jsonQuery");
|
||||
_jsonIndex.Save(obj, "jsonIndex");
|
||||
|
||||
obs_data_set_int(obj, "version", 1);
|
||||
|
||||
@@ -527,6 +547,8 @@ bool MacroActionVariable::Load(obs_data_t *obj)
|
||||
_randomNumberStart.Load(obj, "randomNumberStart");
|
||||
_randomNumberEnd.Load(obj, "randomNumberEnd");
|
||||
_generateInteger = obs_data_get_bool(obj, "generateInteger");
|
||||
_jsonQuery.Load(obj, "jsonQuery");
|
||||
_jsonIndex.Load(obj, "jsonIndex");
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -626,6 +648,8 @@ void MacroActionVariable::ResolveVariablesToFixedValues()
|
||||
_envVariableName.ResolveVariables();
|
||||
_scene.ResolveVariables();
|
||||
_sceneItemIndex.ResolveVariables();
|
||||
_jsonQuery.ResolveVariables();
|
||||
_jsonIndex.ResolveVariables();
|
||||
}
|
||||
|
||||
void MacroActionVariable::DecrementCurrentSegmentVariableRef()
|
||||
@@ -655,8 +679,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 +687,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,
|
||||
@@ -797,6 +827,9 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
"AdvSceneSwitcher.action.variable.generateInteger"),
|
||||
this)),
|
||||
_randomLayout(new QVBoxLayout()),
|
||||
_jsonQuery(new VariableLineEdit(this)),
|
||||
_jsonQueryHelp(new QLabel(this)),
|
||||
_jsonIndex(new VariableSpinBox(this)),
|
||||
_entryLayout(new QHBoxLayout())
|
||||
{
|
||||
_numValue->setMinimum(-9999999999);
|
||||
@@ -826,6 +859,15 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_randomNumberStart->setMaximum(9999999999);
|
||||
_randomNumberEnd->setMinimum(-9999999999);
|
||||
_randomNumberEnd->setMaximum(9999999999);
|
||||
const QString path = GetThemeTypeName() == "Light"
|
||||
? ":/res/images/help.svg"
|
||||
: ":/res/images/help_light.svg";
|
||||
const QIcon icon(path);
|
||||
const QPixmap pixmap = icon.pixmap(QSize(16, 16));
|
||||
_jsonQueryHelp->setPixmap(pixmap);
|
||||
_jsonQueryHelp->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.queryJson.info"));
|
||||
_jsonIndex->setMaximum(999);
|
||||
|
||||
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
||||
this, SLOT(VariableChanged(const QString &)));
|
||||
@@ -842,7 +884,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,
|
||||
@@ -912,6 +955,12 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
SLOT(RandomNumberEndChanged(const NumberVariable<double> &)));
|
||||
QWidget::connect(_generateInteger, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(GenerateIntegerChanged(int)));
|
||||
QWidget::connect(_jsonQuery, SIGNAL(editingFinished()), this,
|
||||
SLOT(JsonQueryChanged()));
|
||||
QWidget::connect(
|
||||
_jsonIndex,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(JsonIndexChanged(const NumberVariable<int> &)));
|
||||
|
||||
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{variables}}", _variables},
|
||||
@@ -943,39 +992,42 @@ 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"),
|
||||
"AdvSceneSwitcher.action.variable.layout.substringIndex"),
|
||||
_subStringIndexEntryLayout, widgetPlaceholders);
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.substringRegex"),
|
||||
"AdvSceneSwitcher.action.variable.layout.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);
|
||||
@@ -1057,17 +1109,15 @@ void MacroActionVariableEdit::UpdateEntryData()
|
||||
_randomNumberStart->SetValue(_entryData->_randomNumberStart);
|
||||
_randomNumberEnd->SetValue(_entryData->_randomNumberEnd);
|
||||
_generateInteger->setChecked(_entryData->_generateInteger);
|
||||
_jsonQuery->setText(_entryData->_jsonQuery);
|
||||
_jsonIndex->SetValue(_entryData->_jsonIndex);
|
||||
|
||||
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 +1125,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 +1151,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 +1160,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 +1272,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 +1293,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 +1302,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 +1316,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 +1324,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 +1332,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,73 +1350,45 @@ 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;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
@@ -1426,21 +1396,13 @@ void MacroActionVariableEdit::SelectionChanged(const TempVariableRef &var)
|
||||
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 +1410,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 +1426,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 +1451,18 @@ void MacroActionVariableEdit::GenerateIntegerChanged(int value)
|
||||
_entryData->_generateInteger = 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::SetWidgetVisibility()
|
||||
{
|
||||
if (!_entryData) {
|
||||
@@ -1524,19 +1486,22 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
{"{{stringLength}}", _stringLength},
|
||||
{"{{paddingCharSelection}}", _paddingCharSelection},
|
||||
{"{{caseType}}", _caseType},
|
||||
{"{{jsonQuery}}", _jsonQuery},
|
||||
{"{{jsonQueryHelp}}", _jsonQueryHelp},
|
||||
{"{{jsonIndex}}", _jsonIndex},
|
||||
};
|
||||
|
||||
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 {
|
||||
layoutString = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.entry.other");
|
||||
"AdvSceneSwitcher.action.variable.layout.other");
|
||||
}
|
||||
|
||||
for (const auto &[_, widget] : widgetPlaceholders) {
|
||||
@@ -1552,7 +1517,8 @@ 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);
|
||||
@@ -1664,6 +1630,12 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
SetLayoutVisible(_randomLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionVariable::Action::RANDOM_NUMBER);
|
||||
_jsonQuery->setVisible(_entryData->_action ==
|
||||
MacroActionVariable::Action::QUERY_JSON);
|
||||
_jsonQueryHelp->setVisible(_entryData->_action ==
|
||||
MacroActionVariable::Action::QUERY_JSON);
|
||||
_jsonIndex->setVisible(_entryData->_action ==
|
||||
MacroActionVariable::Action::ARRAY_JSON);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
@@ -53,6 +53,8 @@ public:
|
||||
TRIM,
|
||||
CHANGE_CASE,
|
||||
RANDOM_NUMBER,
|
||||
QUERY_JSON,
|
||||
ARRAY_JSON,
|
||||
};
|
||||
|
||||
Action _action = Action::SET_VALUE;
|
||||
@@ -104,6 +106,9 @@ public:
|
||||
DoubleVariable _randomNumberEnd = 100;
|
||||
bool _generateInteger = true;
|
||||
|
||||
StringVariable _jsonQuery = "$.some.nested.value";
|
||||
IntVariable _jsonIndex = 0;
|
||||
|
||||
private:
|
||||
void DecrementCurrentSegmentVariableRef();
|
||||
void HandleIndexSubString(Variable *);
|
||||
@@ -169,6 +174,8 @@ private slots:
|
||||
void RandomNumberStartChanged(const NumberVariable<double> &);
|
||||
void RandomNumberEndChanged(const NumberVariable<double> &);
|
||||
void GenerateIntegerChanged(int);
|
||||
void JsonQueryChanged();
|
||||
void JsonIndexChanged(const NumberVariable<int> &);
|
||||
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
@@ -218,6 +225,9 @@ private:
|
||||
VariableDoubleSpinBox *_randomNumberEnd;
|
||||
QCheckBox *_generateInteger;
|
||||
QVBoxLayout *_randomLayout;
|
||||
VariableLineEdit *_jsonQuery;
|
||||
QLabel *_jsonQueryHelp;
|
||||
VariableSpinBox *_jsonIndex;
|
||||
QHBoxLayout *_entryLayout;
|
||||
|
||||
std::shared_ptr<MacroActionVariable> _entryData;
|
||||
|
||||
@@ -138,7 +138,7 @@ MacroConditionEdit::MacroConditionEdit(
|
||||
mainLayout->addWidget(_frame);
|
||||
setLayout(mainLayout);
|
||||
|
||||
UpdateEntryData(id);
|
||||
SetupWidgets(true);
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ void MacroConditionEdit::LogicSelectionChanged(int idx)
|
||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||
}
|
||||
|
||||
bool MacroConditionEdit::IsRootNode()
|
||||
bool MacroConditionEdit::IsRootNode() const
|
||||
{
|
||||
return _isRoot;
|
||||
}
|
||||
@@ -178,23 +178,36 @@ void MacroConditionEdit::SetRootNode(bool root)
|
||||
SetLogicSelection();
|
||||
}
|
||||
|
||||
void MacroConditionEdit::UpdateEntryData(const std::string &id)
|
||||
void MacroConditionEdit::SetupWidgets(bool basicSetup)
|
||||
{
|
||||
if (_allWidgetsAreSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto id = (*_entryData)->GetId();
|
||||
_conditionSelection->setCurrentText(obs_module_text(
|
||||
MacroConditionFactory::GetConditionName(id).c_str()));
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
|
||||
HeaderInfoChanged(
|
||||
QString::fromStdString((*_entryData)->GetShortDesc()));
|
||||
SetLogicSelection();
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
|
||||
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
|
||||
auto modifier = (*_entryData)->GetDurationModifier();
|
||||
_dur->SetValue(modifier);
|
||||
|
||||
if (basicSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetFocusPolicyOfWidgets();
|
||||
|
||||
_allWidgetsAreSetup = true;
|
||||
}
|
||||
|
||||
void MacroConditionEdit::SetEntryData(std::shared_ptr<MacroCondition> *data)
|
||||
@@ -262,289 +275,4 @@ std::shared_ptr<MacroSegment> MacroConditionEdit::Data() const
|
||||
return *_entryData;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroCondition(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx > (int)macro->Conditions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id;
|
||||
Logic::Type logic;
|
||||
if (idx >= 1) {
|
||||
id = macro->Conditions().at(idx - 1)->GetId();
|
||||
if (idx == 1) {
|
||||
logic = Logic::Type::OR;
|
||||
} else {
|
||||
logic = macro->Conditions().at(idx - 1)->GetLogicType();
|
||||
}
|
||||
} else {
|
||||
id = MacroCondition::GetDefaultID();
|
||||
logic = Logic::Type::ROOT_NONE;
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data;
|
||||
if (idx - 1 >= 0) {
|
||||
data = obs_data_create();
|
||||
macro->Conditions().at(idx - 1)->Save(data);
|
||||
}
|
||||
AddMacroCondition(macro.get(), idx, id, data.Get(), logic);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::AddMacroCondition(Macro *macro, int idx,
|
||||
const std::string &id,
|
||||
obs_data_t *data, Logic::Type logic)
|
||||
{
|
||||
if (idx < 0 || idx > (int)macro->Conditions().size()) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto cond = macro->Conditions().emplace(
|
||||
macro->Conditions().begin() + idx,
|
||||
MacroConditionFactory::Create(id, macro));
|
||||
if (data) {
|
||||
macro->Conditions().at(idx)->Load(data);
|
||||
}
|
||||
macro->Conditions().at(idx)->PostLoad();
|
||||
RunPostLoadSteps();
|
||||
(*cond)->SetLogicType(logic);
|
||||
macro->UpdateConditionIndices();
|
||||
ui->conditionsList->Insert(
|
||||
idx,
|
||||
new MacroConditionEdit(this, ¯o->Conditions()[idx],
|
||||
id, idx == 0));
|
||||
SetConditionData(*macro);
|
||||
}
|
||||
HighlightCondition(idx);
|
||||
ui->conditionsList->SetHelpMsgVisible(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionAdd_clicked()
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentConditionIdx == -1) {
|
||||
AddMacroCondition((int)macro->Conditions().size());
|
||||
} else {
|
||||
AddMacroCondition(currentConditionIdx + 1);
|
||||
}
|
||||
if (currentConditionIdx != -1) {
|
||||
MacroConditionSelectionChanged(currentConditionIdx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacroCondition(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= (int)macro->Conditions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
ui->conditionsList->Remove(idx);
|
||||
macro->Conditions().erase(macro->Conditions().begin() + idx);
|
||||
macro->UpdateConditionIndices();
|
||||
if (idx == 0 && macro->Conditions().size() > 0) {
|
||||
auto newRoot = macro->Conditions().at(0);
|
||||
newRoot->SetLogicType(Logic::Type::ROOT_NONE);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->WidgetAt(0))
|
||||
->SetRootNode(true);
|
||||
}
|
||||
SetConditionData(*macro);
|
||||
}
|
||||
MacroConditionSelectionChanged(-1);
|
||||
lastInteracted = MacroSection::CONDITIONS;
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionRemove_clicked()
|
||||
{
|
||||
if (currentConditionIdx == -1) {
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
RemoveMacroCondition((int)macro->Conditions().size() - 1);
|
||||
} else {
|
||||
RemoveMacroCondition(currentConditionIdx);
|
||||
}
|
||||
MacroConditionSelectionChanged(-1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionTop_clicked()
|
||||
{
|
||||
if (currentConditionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
MacroConditionReorder(0, currentConditionIdx);
|
||||
MacroConditionSelectionChanged(0);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionUp_clicked()
|
||||
{
|
||||
if (currentConditionIdx == -1 || currentConditionIdx == 0) {
|
||||
return;
|
||||
}
|
||||
MoveMacroConditionUp(currentConditionIdx);
|
||||
MacroConditionSelectionChanged(currentConditionIdx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionDown_clicked()
|
||||
{
|
||||
if (currentConditionIdx == -1 ||
|
||||
currentConditionIdx ==
|
||||
ui->conditionsList->ContentLayout()->count() - 1) {
|
||||
return;
|
||||
}
|
||||
MoveMacroConditionDown(currentConditionIdx);
|
||||
MacroConditionSelectionChanged(currentConditionIdx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionBottom_clicked()
|
||||
{
|
||||
if (currentConditionIdx == -1) {
|
||||
return;
|
||||
}
|
||||
const int newIdx = ui->conditionsList->ContentLayout()->count() - 1;
|
||||
MacroConditionReorder(newIdx, currentConditionIdx);
|
||||
MacroConditionSelectionChanged(newIdx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SwapConditions(Macro *m, int pos1, int pos2)
|
||||
{
|
||||
if (pos1 == pos2) {
|
||||
return;
|
||||
}
|
||||
if (pos1 > pos2) {
|
||||
std::swap(pos1, pos2);
|
||||
}
|
||||
|
||||
bool root = pos1 == 0;
|
||||
auto lock = LockContext();
|
||||
iter_swap(m->Conditions().begin() + pos1,
|
||||
m->Conditions().begin() + pos2);
|
||||
m->UpdateConditionIndices();
|
||||
|
||||
auto c1 = m->Conditions().begin() + pos1;
|
||||
auto c2 = m->Conditions().begin() + pos2;
|
||||
if (root) {
|
||||
auto logic1 = (*c1)->GetLogicType();
|
||||
auto logic2 = (*c2)->GetLogicType();
|
||||
(*c1)->SetLogicType(logic2);
|
||||
(*c2)->SetLogicType(logic1);
|
||||
}
|
||||
|
||||
auto widget1 = static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->ContentLayout()->takeAt(pos1)->widget());
|
||||
auto widget2 = static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->ContentLayout()->takeAt(pos2 - 1)->widget());
|
||||
ui->conditionsList->Insert(pos1, widget2);
|
||||
ui->conditionsList->Insert(pos2, widget1);
|
||||
SetConditionData(*m);
|
||||
widget2->SetRootNode(root);
|
||||
widget1->SetRootNode(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroConditionUp(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 1 || idx >= (int)macro->Conditions().size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapConditions(macro.get(), idx, idx - 1);
|
||||
HighlightCondition(idx - 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MoveMacroConditionDown(int idx)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx < 0 || idx >= (int)macro->Conditions().size() - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
SwapConditions(macro.get(), idx, idx + 1);
|
||||
HighlightCondition(idx + 1);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroConditionSelectionChanged(int idx)
|
||||
{
|
||||
SetupMacroSegmentSelection(MacroSection::CONDITIONS, idx);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroConditionReorder(int to, int from)
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (to == from || from < 0 || from > (int)macro->Conditions().size() ||
|
||||
to < 0 || to > (int)macro->Conditions().size()) {
|
||||
return;
|
||||
}
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto condition = macro->Conditions().at(from);
|
||||
if (to == 0) {
|
||||
condition->SetLogicType(Logic::Type::ROOT_NONE);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->WidgetAt(from))
|
||||
->SetRootNode(true);
|
||||
macro->Conditions().at(0)->SetLogicType(
|
||||
Logic::Type::AND);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->WidgetAt(0))
|
||||
->SetRootNode(false);
|
||||
}
|
||||
if (from == 0) {
|
||||
condition->SetLogicType(Logic::Type::AND);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->WidgetAt(from))
|
||||
->SetRootNode(false);
|
||||
macro->Conditions().at(1)->SetLogicType(
|
||||
Logic::Type::ROOT_NONE);
|
||||
static_cast<MacroConditionEdit *>(
|
||||
ui->conditionsList->WidgetAt(1))
|
||||
->SetRootNode(true);
|
||||
}
|
||||
macro->Conditions().erase(macro->Conditions().begin() + from);
|
||||
macro->Conditions().insert(macro->Conditions().begin() + to,
|
||||
condition);
|
||||
macro->UpdateConditionIndices();
|
||||
ui->conditionsList->ContentLayout()->insertItem(
|
||||
to, ui->conditionsList->ContentLayout()->takeAt(from));
|
||||
SetConditionData(*macro);
|
||||
}
|
||||
HighlightCondition(to);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -39,9 +39,9 @@ public:
|
||||
std::shared_ptr<MacroCondition> * = nullptr,
|
||||
const std::string &id = MacroCondition::GetDefaultID().data(),
|
||||
bool root = true);
|
||||
bool IsRootNode();
|
||||
bool IsRootNode() const;
|
||||
void SetRootNode(bool);
|
||||
void UpdateEntryData(const std::string &id);
|
||||
void SetupWidgets(bool basicSetup = false);
|
||||
void SetEntryData(std::shared_ptr<MacroCondition> *);
|
||||
|
||||
private slots:
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "macro-segment-unknown.hpp"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace advss {
|
||||
|
||||
namespace {
|
||||
|
||||
class MacroConditionUnknown : public MacroCondition {
|
||||
public:
|
||||
MacroConditionUnknown(Macro *m) : MacroCondition(m) {}
|
||||
bool CheckCondition() { return false; }
|
||||
bool Save(obs_data_t *obj) const { return MacroCondition::Save(obj); };
|
||||
bool Load(obs_data_t *obj) { return MacroCondition::Load(obj); };
|
||||
std::string GetId() const { return "unknown"; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
using MacroConditionUnknown = MacroSegmentUnknown<MacroCondition>;
|
||||
|
||||
static std::recursive_mutex mutex;
|
||||
|
||||
@@ -46,9 +36,10 @@ bool MacroConditionFactory::Deregister(const std::string &id)
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::shared_ptr<MacroCondition> createUnknownCondition(Macro *m)
|
||||
static std::shared_ptr<MacroCondition>
|
||||
createUnknownCondition(Macro *m, const std::string &id)
|
||||
{
|
||||
return std::make_shared<MacroConditionUnknown>(m);
|
||||
return std::make_shared<MacroConditionUnknown>(m, id);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroCondition>
|
||||
@@ -58,13 +49,7 @@ MacroConditionFactory::Create(const std::string &id, Macro *m)
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._create(m);
|
||||
}
|
||||
return createUnknownCondition(m);
|
||||
}
|
||||
|
||||
static QWidget *createUnknownConditionWidget()
|
||||
{
|
||||
return new QLabel(
|
||||
obs_module_text("AdvSceneSwitcher.condition.unknown"));
|
||||
return createUnknownCondition(m, id);
|
||||
}
|
||||
|
||||
QWidget *
|
||||
@@ -75,7 +60,7 @@ MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._createWidget(parent, cond);
|
||||
}
|
||||
return createUnknownConditionWidget();
|
||||
return CreateUnknownSegmentWidget(false);
|
||||
}
|
||||
|
||||
std::string MacroConditionFactory::GetConditionName(const std::string &id)
|
||||
|
||||
@@ -20,7 +20,7 @@ class MacroConditionFactory {
|
||||
public:
|
||||
MacroConditionFactory() = delete;
|
||||
EXPORT static bool Register(const std::string &, MacroConditionInfo);
|
||||
static bool Deregister(const std::string &);
|
||||
EXPORT static bool Deregister(const std::string &);
|
||||
static std::shared_ptr<MacroCondition> Create(const std::string &,
|
||||
Macro *m);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "macro-condition-macro.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "macro.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -26,6 +27,8 @@ const static std::map<MacroConditionMacro::Type, std::string>
|
||||
"AdvSceneSwitcher.condition.macro.type.actionEnabled"},
|
||||
{MacroConditionMacro::Type::PAUSED,
|
||||
"AdvSceneSwitcher.condition.macro.type.paused"},
|
||||
{MacroConditionMacro::Type::ACTIONS_PERFORMED,
|
||||
"AdvSceneSwitcher.condition.macro.type.actionsPerformed"},
|
||||
};
|
||||
|
||||
const static std::map<MacroConditionMacro::CounterCondition, std::string>
|
||||
@@ -121,6 +124,16 @@ bool MacroConditionMacro::CheckPauseState()
|
||||
return macro->Paused();
|
||||
}
|
||||
|
||||
bool MacroConditionMacro::CheckActionsPerformed()
|
||||
{
|
||||
auto macro = _macro.GetMacro();
|
||||
if (!macro) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return macro->WasExecutedSince(macro->LastConditionCheckTime());
|
||||
}
|
||||
|
||||
bool MacroConditionMacro::CheckCountCondition()
|
||||
{
|
||||
auto macro = _macro.GetMacro();
|
||||
@@ -158,6 +171,8 @@ bool MacroConditionMacro::CheckCondition()
|
||||
return CheckActionStateCondition();
|
||||
case Type::PAUSED:
|
||||
return CheckPauseState();
|
||||
case Type::ACTIONS_PERFORMED:
|
||||
return CheckActionsPerformed();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -307,7 +322,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 +430,9 @@ void MacroConditionMacroEdit::SetupWidgets()
|
||||
case MacroConditionMacro::Type::PAUSED:
|
||||
SetupPauseWidgets();
|
||||
break;
|
||||
case MacroConditionMacro::Type::ACTIONS_PERFORMED:
|
||||
SetupActionsPerformedWidgets();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -472,6 +491,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 +508,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 +567,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 +576,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 +607,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 +653,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 +661,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 +676,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 +684,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 +693,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ bool MacroConditionTempVar::CheckCondition()
|
||||
bool MacroConditionTempVar::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
_tempVar.Save(obj);
|
||||
_tempVar.Save(obj, GetMacro());
|
||||
obs_data_set_string(obj, "variableName",
|
||||
GetWeakVariableName(_variable2).c_str());
|
||||
_strValue.Save(obj, "strValue");
|
||||
@@ -264,32 +264,19 @@ void MacroConditionTempVarEdit::UpdateEntryData()
|
||||
|
||||
void MacroConditionTempVarEdit::VariableChanged(const TempVariableRef &var)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_tempVar = var;
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::Variable2Changed(const QString &text)
|
||||
{
|
||||
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_variable2 = GetWeakVariableByQString(text);
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::ConditionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_type =
|
||||
static_cast<MacroConditionTempVar::Condition>(value);
|
||||
SetWidgetVisibility();
|
||||
@@ -297,11 +284,7 @@ void MacroConditionTempVarEdit::ConditionChanged(int value)
|
||||
|
||||
void MacroConditionTempVarEdit::StrValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_strValue = _strValue->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -309,21 +292,13 @@ void MacroConditionTempVarEdit::StrValueChanged()
|
||||
|
||||
void MacroConditionTempVarEdit::NumValueChanged(double val)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_numValue = val;
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::RegexChanged(const RegexConfig &conf)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_regex = conf;
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
@@ -236,11 +236,7 @@ void MacroConditionVariableEdit::UpdateEntryData()
|
||||
|
||||
void MacroConditionVariableEdit::VariableChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_variable = GetWeakVariableByQString(text);
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
@@ -248,22 +244,13 @@ void MacroConditionVariableEdit::VariableChanged(const QString &text)
|
||||
|
||||
void MacroConditionVariableEdit::Variable2Changed(const QString &text)
|
||||
{
|
||||
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_variable2 = GetWeakVariableByQString(text);
|
||||
}
|
||||
|
||||
void MacroConditionVariableEdit::ConditionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_type =
|
||||
static_cast<MacroConditionVariable::Condition>(value);
|
||||
SetWidgetVisibility();
|
||||
@@ -271,11 +258,7 @@ void MacroConditionVariableEdit::ConditionChanged(int value)
|
||||
|
||||
void MacroConditionVariableEdit::StrValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_strValue = _strValue->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -283,21 +266,13 @@ void MacroConditionVariableEdit::StrValueChanged()
|
||||
|
||||
void MacroConditionVariableEdit::NumValueChanged(double val)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_numValue = val;
|
||||
}
|
||||
|
||||
void MacroConditionVariableEdit::RegexChanged(const RegexConfig &conf)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_regex = conf;
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
394
lib/macro/macro-dock-settings.cpp
Normal file
394
lib/macro/macro-dock-settings.cpp
Normal file
@@ -0,0 +1,394 @@
|
||||
#include "macro-dock-settings.hpp"
|
||||
#include "macro-dock.hpp"
|
||||
#include "macro-dock-window.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
#include <util/platform.h>
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(30, 0, 0)
|
||||
#include <QDockWidget>
|
||||
|
||||
namespace {
|
||||
|
||||
struct DockMapEntry {
|
||||
QAction *action = nullptr;
|
||||
QWidget *dock = nullptr;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static std::unordered_map<const char *, DockMapEntry> dockIds;
|
||||
static std::mutex dockMutex;
|
||||
|
||||
static bool obs_frontend_add_dock_by_id(const char *id, const char *title,
|
||||
QWidget *widget)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(dockMutex);
|
||||
if (dockIds.count(id) > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
widget->setObjectName(id);
|
||||
|
||||
auto dock = new QDockWidget();
|
||||
dock->setWindowTitle(title);
|
||||
dock->setWidget(widget);
|
||||
dock->setFloating(true);
|
||||
dock->setVisible(false);
|
||||
dock->setFeatures(QDockWidget::DockWidgetClosable |
|
||||
QDockWidget::DockWidgetMovable |
|
||||
QDockWidget::DockWidgetFloatable);
|
||||
|
||||
auto action = static_cast<QAction *>(obs_frontend_add_dock(dock));
|
||||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
dockIds[id] = {action, dock};
|
||||
return true;
|
||||
}
|
||||
|
||||
static void obs_frontend_remove_dock(const char *id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(dockMutex);
|
||||
auto it = dockIds.find(id);
|
||||
if (it == dockIds.end()) {
|
||||
return;
|
||||
}
|
||||
it->second.action->deleteLater();
|
||||
it->second.dock->deleteLater();
|
||||
dockIds.erase(it);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace advss {
|
||||
|
||||
MacroDockSettings::MacroDockSettings(Macro *macro) : _macro(macro) {}
|
||||
|
||||
MacroDockSettings::~MacroDockSettings()
|
||||
{
|
||||
// Keep the dock widgets in case of shutdown so they can be restored by
|
||||
// OBS on startup
|
||||
if (!OBSIsShuttingDown()) {
|
||||
RemoveDock();
|
||||
}
|
||||
}
|
||||
|
||||
void MacroDockSettings::Save(obs_data_t *obj, bool saveForCopy) const
|
||||
{
|
||||
OBSDataAutoRelease dockSettings = obs_data_create();
|
||||
obs_data_set_bool(dockSettings, "register", _registerDock);
|
||||
obs_data_set_bool(dockSettings, "standaloneDock", _standaloneDock);
|
||||
obs_data_set_string(dockSettings, "dockWindow", _dockWindow.c_str());
|
||||
obs_data_set_bool(dockSettings, "hasRunButton", _hasRunButton);
|
||||
obs_data_set_bool(dockSettings, "hasPauseButton", _hasPauseButton);
|
||||
obs_data_set_bool(dockSettings, "hasStatusLabel", _hasStatusLabel);
|
||||
obs_data_set_bool(dockSettings, "highlightIfConditionsTrue",
|
||||
_highlight);
|
||||
_runButtonText.Save(dockSettings, "runButtonText");
|
||||
_pauseButtonText.Save(dockSettings, "pauseButtonText");
|
||||
_unpauseButtonText.Save(dockSettings, "unpauseButtonText");
|
||||
_conditionsTrueStatusText.Save(dockSettings,
|
||||
"conditionsTrueStatusText");
|
||||
_conditionsFalseStatusText.Save(dockSettings,
|
||||
"conditionsFalseStatusText");
|
||||
if (saveForCopy) {
|
||||
auto uuid = GenerateId();
|
||||
obs_data_set_string(dockSettings, "dockId", uuid.c_str());
|
||||
|
||||
} else {
|
||||
obs_data_set_string(dockSettings, "dockId", _id.c_str());
|
||||
}
|
||||
obs_data_set_int(dockSettings, "version", 1);
|
||||
obs_data_set_obj(obj, "dockSettings", dockSettings);
|
||||
}
|
||||
|
||||
void MacroDockSettings::Load(obs_data_t *obj)
|
||||
{
|
||||
OBSDataAutoRelease dockSettings = obs_data_get_obj(obj, "dockSettings");
|
||||
if (!dockSettings) {
|
||||
// TODO: Remove this fallback
|
||||
_hasRunButton = obs_data_get_bool(obj, "dockHasRunButton");
|
||||
_hasPauseButton = obs_data_get_bool(obj, "dockHasPauseButton");
|
||||
_registerDock = obs_data_get_bool(obj, "registerDock");
|
||||
ResetDockIfEnabled();
|
||||
return;
|
||||
}
|
||||
|
||||
_macroName = _macro->Name();
|
||||
if (!obs_data_has_user_value(dockSettings, "version")) {
|
||||
assert(_macro);
|
||||
_id = std::string("ADVSS-") + _macroName;
|
||||
} else {
|
||||
_id = obs_data_get_string(dockSettings, "dockId");
|
||||
}
|
||||
|
||||
_registerDock = obs_data_get_bool(dockSettings, "register");
|
||||
|
||||
// TODO: remove these default settings in a future version
|
||||
obs_data_set_default_bool(dockSettings, "standaloneDock", true);
|
||||
obs_data_set_default_string(dockSettings, "dockWindow", "Dock");
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "runButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.run"));
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "pauseButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.pause"));
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "unpauseButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.unpause"));
|
||||
_standaloneDock = obs_data_get_bool(dockSettings, "standaloneDock");
|
||||
_dockWindow = obs_data_get_string(dockSettings, "dockWindow");
|
||||
_runButtonText.Load(dockSettings, "runButtonText");
|
||||
_pauseButtonText.Load(dockSettings, "pauseButtonText");
|
||||
_unpauseButtonText.Load(dockSettings, "unpauseButtonText");
|
||||
_conditionsTrueStatusText.Load(dockSettings,
|
||||
"conditionsTrueStatusText");
|
||||
_conditionsFalseStatusText.Load(dockSettings,
|
||||
"conditionsFalseStatusText");
|
||||
if (_registerDock) {
|
||||
_hasRunButton = obs_data_get_bool(dockSettings, "hasRunButton");
|
||||
_hasPauseButton =
|
||||
obs_data_get_bool(dockSettings, "hasPauseButton");
|
||||
_hasStatusLabel =
|
||||
obs_data_get_bool(dockSettings, "hasStatusLabel");
|
||||
_highlight = obs_data_get_bool(dockSettings,
|
||||
"highlightIfConditionsTrue");
|
||||
}
|
||||
|
||||
ResetDockIfEnabled();
|
||||
}
|
||||
|
||||
void MacroDockSettings::EnableDock(bool enable)
|
||||
{
|
||||
// Only apply "on change" to avoid recreation of the dock widget
|
||||
if (_registerDock == enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveDock();
|
||||
|
||||
if (!enable) {
|
||||
_registerDock = enable;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(_macro);
|
||||
_macroName = _macro->Name();
|
||||
_dock = new MacroDock(GetWeakMacroByName(_macroName.c_str()),
|
||||
_runButtonText, _pauseButtonText,
|
||||
_unpauseButtonText, _conditionsTrueStatusText,
|
||||
_conditionsFalseStatusText, _highlight);
|
||||
|
||||
if (!_standaloneDock) {
|
||||
auto window = GetDockWindowByName(_dockWindow);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
window->AddMacroDock(_dock, QString::fromStdString(_macroName));
|
||||
_registerDock = enable;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obs_frontend_add_dock_by_id(_id.c_str(), _macroName.c_str(),
|
||||
_dock)) {
|
||||
blog(LOG_INFO, "failed to add macro dock for macro %s",
|
||||
_macroName.c_str());
|
||||
_dock->deleteLater();
|
||||
_dock = nullptr;
|
||||
_registerDock = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_registerDock = enable;
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetIsStandaloneDock(bool value)
|
||||
{
|
||||
if (_standaloneDock == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveDock();
|
||||
_standaloneDock = value;
|
||||
ResetDockIfEnabled();
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetDockWindowName(const std::string &name)
|
||||
{
|
||||
if (_dockWindow == name) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveDock();
|
||||
_dockWindow = name;
|
||||
ResetDockIfEnabled();
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetHasRunButton(bool value)
|
||||
{
|
||||
_hasRunButton = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->ShowRunButton(value);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetHasPauseButton(bool value)
|
||||
{
|
||||
_hasPauseButton = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->ShowPauseButton(value);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetHasStatusLabel(bool value)
|
||||
{
|
||||
_hasStatusLabel = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->ShowStatusLabel(value);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetHighlightEnable(bool value)
|
||||
{
|
||||
_highlight = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->EnableHighlight(value);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetRunButtonText(const std::string &text)
|
||||
{
|
||||
_runButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetRunButtonText(text);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetPauseButtonText(const std::string &text)
|
||||
{
|
||||
_pauseButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetPauseButtonText(text);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetUnpauseButtonText(const std::string &text)
|
||||
{
|
||||
_unpauseButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetUnpauseButtonText(text);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetConditionsTrueStatusText(const std::string &text)
|
||||
{
|
||||
_conditionsTrueStatusText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetConditionsTrueText(text);
|
||||
}
|
||||
|
||||
StringVariable MacroDockSettings::ConditionsTrueStatusText() const
|
||||
{
|
||||
return _conditionsTrueStatusText;
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetConditionsFalseStatusText(const std::string &text)
|
||||
{
|
||||
_conditionsFalseStatusText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetConditionsFalseText(text);
|
||||
}
|
||||
|
||||
StringVariable MacroDockSettings::ConditionsFalseStatusText() const
|
||||
{
|
||||
return _conditionsFalseStatusText;
|
||||
}
|
||||
|
||||
void MacroDockSettings::HandleMacroNameChange()
|
||||
{
|
||||
const auto newName = _macro->Name();
|
||||
|
||||
if (!_standaloneDock) {
|
||||
auto window = GetDockWindowByName(_dockWindow);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
window->RenameMacro(_macroName, newName);
|
||||
_macroName = newName;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_macroName != newName) {
|
||||
RemoveDock();
|
||||
_id = GenerateId();
|
||||
_macroName = newName;
|
||||
}
|
||||
|
||||
ResetDockIfEnabled();
|
||||
}
|
||||
|
||||
void MacroDockSettings::ResetDockIfEnabled()
|
||||
{
|
||||
if (_registerDock) {
|
||||
_registerDock = false;
|
||||
EnableDock(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroDockSettings::RemoveDock()
|
||||
{
|
||||
if (_standaloneDock) {
|
||||
obs_frontend_remove_dock(_id.c_str());
|
||||
_dock = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
auto window = GetDockWindowByName(_dockWindow);
|
||||
if (window) {
|
||||
window->RemoveMacroDock(_dock);
|
||||
}
|
||||
|
||||
if (_dock) {
|
||||
_dock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string MacroDockSettings::GenerateId()
|
||||
{
|
||||
#if LIBOBS_API_VER > MAKE_SEMANTIC_VERSION(30, 0, 0)
|
||||
auto uuid = os_generate_uuid();
|
||||
auto id = std::string("advss-macro-dock-") + std::string(uuid);
|
||||
bfree(uuid);
|
||||
return id;
|
||||
|
||||
#else
|
||||
static std::atomic_int16_t idCounter = 0;
|
||||
return std::to_string(++idCounter);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
76
lib/macro/macro-dock-settings.hpp
Normal file
76
lib/macro/macro-dock-settings.hpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "variable-string.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
class Macro;
|
||||
class MacroDock;
|
||||
|
||||
class MacroDockSettings {
|
||||
public:
|
||||
MacroDockSettings(Macro *macro);
|
||||
~MacroDockSettings();
|
||||
|
||||
void Save(obs_data_t *obj, bool saveForCopy) const;
|
||||
void Load(obs_data_t *obj);
|
||||
|
||||
void EnableDock(bool);
|
||||
bool DockEnabled() const { return _registerDock; }
|
||||
|
||||
bool IsStandaloneDock() const { return _standaloneDock; }
|
||||
void SetIsStandaloneDock(bool value);
|
||||
std::string DockWindowName() const { return _dockWindow; }
|
||||
void SetDockWindowName(const std::string &name);
|
||||
|
||||
void SetHasRunButton(bool value);
|
||||
bool HasRunButton() const { return _hasRunButton; }
|
||||
void SetHasPauseButton(bool value);
|
||||
bool HasPauseButton() const { return _hasPauseButton; }
|
||||
void SetHasStatusLabel(bool value);
|
||||
bool HasStatusLabel() const { return _hasStatusLabel; }
|
||||
void SetHighlightEnable(bool value);
|
||||
bool HighlightEnabled() const { return _highlight; }
|
||||
StringVariable RunButtonText() const { return _runButtonText; }
|
||||
void SetRunButtonText(const std::string &text);
|
||||
StringVariable PauseButtonText() const { return _pauseButtonText; }
|
||||
void SetPauseButtonText(const std::string &text);
|
||||
StringVariable UnpauseButtonText() const { return _unpauseButtonText; }
|
||||
void SetUnpauseButtonText(const std::string &text);
|
||||
void SetConditionsTrueStatusText(const std::string &text);
|
||||
StringVariable ConditionsTrueStatusText() const;
|
||||
void SetConditionsFalseStatusText(const std::string &text);
|
||||
StringVariable ConditionsFalseStatusText() const;
|
||||
|
||||
void HandleMacroNameChange();
|
||||
|
||||
private:
|
||||
void ResetDockIfEnabled();
|
||||
void RemoveDock();
|
||||
static std::string GenerateId();
|
||||
|
||||
bool _registerDock = false;
|
||||
bool _standaloneDock = true;
|
||||
std::string _dockWindow = "Dock";
|
||||
bool _hasRunButton = true;
|
||||
bool _hasPauseButton = true;
|
||||
bool _hasStatusLabel = false;
|
||||
bool _highlight = false;
|
||||
StringVariable _runButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.run");
|
||||
StringVariable _pauseButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.pause");
|
||||
StringVariable _unpauseButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.unpause");
|
||||
StringVariable _conditionsTrueStatusText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.true");
|
||||
StringVariable _conditionsFalseStatusText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.false");
|
||||
std::string _id = GenerateId();
|
||||
std::string _macroName = "";
|
||||
|
||||
Macro *_macro = nullptr;
|
||||
MacroDock *_dock = nullptr;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
170
lib/macro/macro-dock-window.cpp
Normal file
170
lib/macro/macro-dock-window.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
#include "macro-dock-window.hpp"
|
||||
#include "log-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QLayout>
|
||||
#include <mutex>
|
||||
|
||||
namespace advss {
|
||||
|
||||
static std::unordered_map<std::string, MacroDockWindow *> windows;
|
||||
static std::unordered_map<std::string, QByteArray> windowGeometries;
|
||||
static std::mutex mutex;
|
||||
|
||||
static void saveDocks(obs_data_t *obj)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
OBSDataArrayAutoRelease array = obs_data_array_create();
|
||||
for (const auto &[name, window] : windows) {
|
||||
OBSDataAutoRelease dockData = obs_data_create();
|
||||
obs_data_set_string(dockData, "name", name.c_str());
|
||||
obs_data_set_string(dockData, "geometry",
|
||||
window->GetWindow()
|
||||
->saveState()
|
||||
.toBase64()
|
||||
.toStdString()
|
||||
.c_str());
|
||||
obs_data_array_push_back(array, dockData);
|
||||
}
|
||||
obs_data_set_array(data, "docks", array);
|
||||
obs_data_set_obj(obj, "dockWindows", data);
|
||||
}
|
||||
|
||||
static void restoreDockGeometry()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
for (const auto &[name, dock] : windows) {
|
||||
const auto it = windowGeometries.find(name);
|
||||
if (it == windowGeometries.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dock->GetWindow()->restoreState(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
static void loadDocks(obs_data_t *obj)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
windowGeometries.clear();
|
||||
OBSDataAutoRelease data = obs_data_get_obj(obj, "dockWindows");
|
||||
OBSDataArrayAutoRelease array = obs_data_get_array(data, "docks");
|
||||
auto size = obs_data_array_count(array);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
OBSDataAutoRelease dockData = obs_data_array_item(array, i);
|
||||
const auto name = obs_data_get_string(dockData, "name");
|
||||
const auto geometry = QByteArray::fromBase64(
|
||||
obs_data_get_string(dockData, "geometry"));
|
||||
windowGeometries[name] = geometry;
|
||||
}
|
||||
AddPostLoadStep(restoreDockGeometry);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static bool _ = []() {
|
||||
AddPluginInitStep([]() {
|
||||
AddSaveStep(saveDocks);
|
||||
AddLoadStep(loadDocks);
|
||||
});
|
||||
return true;
|
||||
}();
|
||||
|
||||
MacroDockWindow::MacroDockWindow(const std::string &name)
|
||||
: QFrame(),
|
||||
_name(name),
|
||||
_window(new QMainWindow())
|
||||
{
|
||||
setFrameShape(QFrame::StyledPanel);
|
||||
setFrameShadow(QFrame::Sunken);
|
||||
_window->setDockNestingEnabled(true);
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->addWidget(_window);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
QWidget *MacroDockWindow::AddMacroDock(QWidget *widget, const QString &title)
|
||||
{
|
||||
auto dock = new QDockWidget();
|
||||
dock->setWindowTitle(title);
|
||||
dock->setWidget(widget);
|
||||
dock->setVisible(true);
|
||||
dock->setFeatures(QDockWidget::DockWidgetMovable);
|
||||
dock->setObjectName(title);
|
||||
_window->addDockWidget(Qt::RightDockWidgetArea, dock);
|
||||
return dock;
|
||||
}
|
||||
|
||||
void MacroDockWindow::RenameMacro(const std::string &oldName,
|
||||
const std::string &newName)
|
||||
{
|
||||
auto docks = _window->findChildren<QDockWidget *>();
|
||||
for (const auto dock : docks) {
|
||||
if (dock->windowTitle() == QString::fromStdString(oldName)) {
|
||||
dock->setWindowTitle(QString::fromStdString(newName));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MacroDockWindow::RemoveMacroDock(QWidget *widget)
|
||||
{
|
||||
bool removedDock = false;
|
||||
auto docks = _window->findChildren<QDockWidget *>();
|
||||
for (const auto dock : docks) {
|
||||
if (dock->widget() == widget) {
|
||||
_window->removeDockWidget(dock);
|
||||
dock->deleteLater();
|
||||
removedDock = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (OBSIsShuttingDown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool shouldRemoveDockWindow = docks.isEmpty() ||
|
||||
(removedDock && docks.count() == 1);
|
||||
if (!shouldRemoveDockWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
auto it = windows.find(_name);
|
||||
if (it != windows.end()) {
|
||||
windows.erase(it);
|
||||
}
|
||||
|
||||
const auto id = "advss-dock-window-" + _name;
|
||||
obs_frontend_remove_dock(id.c_str());
|
||||
}
|
||||
|
||||
QMainWindow *MacroDockWindow::GetWindow() const
|
||||
{
|
||||
return _window;
|
||||
}
|
||||
|
||||
MacroDockWindow *GetDockWindowByName(const std::string &name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
auto it = windows.find(name);
|
||||
if (it != windows.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto window = new MacroDockWindow(name);
|
||||
const auto id = "advss-dock-window-" + name;
|
||||
if (!obs_frontend_add_dock_by_id(id.c_str(), name.c_str(), window)) {
|
||||
blog(LOG_INFO, "failed to add macro dock window '%s'",
|
||||
id.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
windows[name] = window;
|
||||
return window;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
29
lib/macro/macro-dock-window.hpp
Normal file
29
lib/macro/macro-dock-window.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include <QFrame>
|
||||
#include <QMainWindow>
|
||||
#include <QWidget>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MacroDockWindow : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroDockWindow(const std::string &name);
|
||||
QWidget *AddMacroDock(QWidget *, const QString &title);
|
||||
void RenameMacro(const std::string &oldName,
|
||||
const std::string &newName);
|
||||
void RemoveMacroDock(QWidget *);
|
||||
QMainWindow *GetWindow() const;
|
||||
|
||||
private:
|
||||
std::string _name;
|
||||
QMainWindow *_window;
|
||||
};
|
||||
|
||||
MacroDockWindow *GetDockWindowByName(const std::string &name);
|
||||
|
||||
} // namespace advss
|
||||
@@ -30,9 +30,10 @@ MacroDock::MacroDock(std::weak_ptr<Macro> m,
|
||||
|
||||
auto macro = _macro.lock();
|
||||
if (macro) {
|
||||
_run->setVisible(macro->DockHasRunButton());
|
||||
_pauseToggle->setVisible(macro->DockHasPauseButton());
|
||||
_statusText->setVisible(macro->DockHasStatusLabel());
|
||||
const auto &settings = macro->GetDockSettings();
|
||||
_run->setVisible(settings.HasRunButton());
|
||||
_pauseToggle->setVisible(settings.HasPauseButton());
|
||||
_statusText->setVisible(settings.HasStatusLabel());
|
||||
}
|
||||
|
||||
QWidget::connect(_run, SIGNAL(clicked()), this, SLOT(RunClicked()));
|
||||
|
||||
1842
lib/macro/macro-edit.cpp
Normal file
1842
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;
|
||||
|
||||
/*******************************************************************************
|
||||
* Advanced Scene Switcher window
|
||||
*******************************************************************************/
|
||||
class MacroEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroEdit(QWidget *parent, QStringList helpMsg = {});
|
||||
void SetMacro(const std::shared_ptr<Macro> &);
|
||||
std::shared_ptr<Macro> GetMacro() const;
|
||||
void ClearSegmentWidgetCacheFor(Macro *) const;
|
||||
void SetControlsDisabled(bool disable) const;
|
||||
void HighlightAction(int idx, QColor color = QColor(Qt::green)) const;
|
||||
void HighlightElseAction(int idx,
|
||||
QColor color = QColor(Qt::green)) const;
|
||||
void HighlightCondition(int idx,
|
||||
QColor color = QColor(Qt::green)) const;
|
||||
void ResetConditionHighlights();
|
||||
void ResetActionHighlights();
|
||||
void SetActionData(Macro &m) const;
|
||||
void SetElseActionData(Macro &m) const;
|
||||
void SetConditionData(Macro &m) const;
|
||||
void SwapActions(Macro *m, int pos1, int pos2);
|
||||
void SwapElseActions(Macro *m, int pos1, int pos2);
|
||||
void SwapConditions(Macro *m, int pos1, int pos2);
|
||||
void CopyMacroSegment();
|
||||
void PasteMacroSegment();
|
||||
bool IsEmpty() const;
|
||||
void ShowAllMacroSections();
|
||||
|
||||
private slots:
|
||||
void on_conditionAdd_clicked();
|
||||
void on_conditionRemove_clicked();
|
||||
void on_conditionTop_clicked();
|
||||
void on_conditionUp_clicked();
|
||||
void on_conditionDown_clicked();
|
||||
void on_conditionBottom_clicked();
|
||||
void on_actionAdd_clicked();
|
||||
void on_actionRemove_clicked();
|
||||
void on_actionTop_clicked();
|
||||
void on_actionUp_clicked();
|
||||
void on_actionDown_clicked();
|
||||
void on_actionBottom_clicked();
|
||||
void on_toggleElseActions_clicked() const;
|
||||
void on_elseActionAdd_clicked();
|
||||
void on_elseActionRemove_clicked();
|
||||
void on_elseActionTop_clicked();
|
||||
void on_elseActionUp_clicked();
|
||||
void on_elseActionDown_clicked();
|
||||
void on_elseActionBottom_clicked();
|
||||
void UpMacroSegmentHotkey();
|
||||
void DownMacroSegmentHotkey();
|
||||
void DeleteMacroSegmentHotkey();
|
||||
void ShowMacroActionsContextMenu(const QPoint &);
|
||||
void ShowMacroElseActionsContextMenu(const QPoint &);
|
||||
void ShowMacroConditionsContextMenu(const QPoint &);
|
||||
void ExpandAllActions() const;
|
||||
void ExpandAllElseActions() const;
|
||||
void ExpandAllConditions() const;
|
||||
void CollapseAllActions() const;
|
||||
void CollapseAllElseActions() const;
|
||||
void CollapseAllConditions() const;
|
||||
void MinimizeActions() const;
|
||||
void MaximizeActions() const;
|
||||
void MinimizeElseActions() const;
|
||||
void MaximizeElseActions() const;
|
||||
void MinimizeConditions() const;
|
||||
void MaximizeConditions() const;
|
||||
void SetElseActionsStateToHidden() const;
|
||||
void SetElseActionsStateToVisible() const;
|
||||
void MacroActionSelectionChanged(int idx);
|
||||
void MacroActionReorder(int to, int target);
|
||||
void AddMacroAction(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data);
|
||||
void AddMacroAction(int idx);
|
||||
void RemoveMacroAction(int idx);
|
||||
void MoveMacroActionUp(int idx);
|
||||
void MoveMacroActionDown(int idx);
|
||||
void MacroElseActionSelectionChanged(int idx);
|
||||
void MacroElseActionReorder(int to, int target);
|
||||
void AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data);
|
||||
void AddMacroElseAction(int idx);
|
||||
void RemoveMacroElseAction(int idx);
|
||||
void MoveMacroElseActionUp(int idx);
|
||||
void MoveMacroElseActionDown(int idx);
|
||||
void MacroConditionSelectionChanged(int idx);
|
||||
void MacroConditionReorder(int to, int target);
|
||||
void AddMacroCondition(int idx);
|
||||
void AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
||||
obs_data_t *data, Logic::Type logic);
|
||||
void RemoveMacroCondition(int idx);
|
||||
void MoveMacroConditionUp(int idx);
|
||||
void MoveMacroConditionDown(int idx);
|
||||
void HighlightControls() const;
|
||||
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void MacroSegmentOrderChanged();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
private:
|
||||
enum class MacroSection { CONDITIONS, ACTIONS, ELSE_ACTIONS };
|
||||
|
||||
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroElseActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
|
||||
void SetupMacroSegmentSelection(MacroSection type, int idx);
|
||||
void
|
||||
SetupContextMenu(const QPoint &pos,
|
||||
const std::function<void(MacroEdit *, int)> &remove,
|
||||
const std::function<void(MacroEdit *)> &expand,
|
||||
const std::function<void(MacroEdit *)> &collapse,
|
||||
const std::function<void(MacroEdit *)> &maximize,
|
||||
const std::function<void(MacroEdit *)> &minimize,
|
||||
MacroSegmentList *list);
|
||||
void RunSegmentHighlightChecks();
|
||||
bool ElseSectionIsVisible() const;
|
||||
|
||||
MacroSection lastInteracted = MacroSection::CONDITIONS;
|
||||
int currentConditionIdx = -1;
|
||||
int currentActionIdx = -1;
|
||||
int currentElseActionIdx = -1;
|
||||
|
||||
std::shared_ptr<Macro> _currentMacro;
|
||||
|
||||
std::unique_ptr<Ui_MacroEdit> ui;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -78,36 +78,36 @@ bool MacroSwitchedScene()
|
||||
return macroSceneSwitched;
|
||||
}
|
||||
|
||||
std::string GetMacroName(Macro *macro)
|
||||
std::string GetMacroName(const Macro *macro)
|
||||
{
|
||||
return macro ? macro->Name() : "";
|
||||
}
|
||||
|
||||
std::chrono::high_resolution_clock::time_point
|
||||
LastMacroConditionCheckTime(Macro *macro)
|
||||
LastMacroConditionCheckTime(const Macro *macro)
|
||||
{
|
||||
return macro ? macro->LastConditionCheckTime()
|
||||
: std::chrono::high_resolution_clock::time_point{};
|
||||
}
|
||||
|
||||
bool MacroIsStopped(Macro *macro)
|
||||
bool MacroIsStopped(const Macro *macro)
|
||||
{
|
||||
return macro ? macro->GetStop() : true;
|
||||
}
|
||||
|
||||
bool MacroIsPaused(Macro *macro)
|
||||
bool MacroIsPaused(const Macro *macro)
|
||||
{
|
||||
return macro ? macro->Paused() : true;
|
||||
}
|
||||
|
||||
bool MacroWasPausedSince(
|
||||
Macro *macro,
|
||||
const Macro *macro,
|
||||
const std::chrono::high_resolution_clock::time_point &time)
|
||||
{
|
||||
return macro ? macro->WasPausedSince(time) : false;
|
||||
}
|
||||
|
||||
bool MacroWasCheckedSinceLastStart(Macro *macro)
|
||||
bool MacroWasCheckedSinceLastStart(const Macro *macro)
|
||||
{
|
||||
if (!macro) {
|
||||
return false;
|
||||
@@ -144,7 +144,7 @@ void ResetMacroRunCount(Macro *macro)
|
||||
macro->ResetRunCount();
|
||||
}
|
||||
|
||||
bool IsValidMacroSegmentIndex(Macro *m, const int idx, bool isCondition)
|
||||
bool IsValidMacroSegmentIndex(const Macro *m, const int idx, bool isCondition)
|
||||
{
|
||||
if (!m || idx < 0) {
|
||||
return false;
|
||||
|
||||
@@ -41,17 +41,17 @@ EXPORT std::atomic_int &GetShutdownConditionCount();
|
||||
EXPORT void SetMacroSwitchedScene(bool value);
|
||||
EXPORT bool MacroSwitchedScene();
|
||||
|
||||
EXPORT std::string GetMacroName(Macro *);
|
||||
EXPORT std::string GetMacroName(const Macro *);
|
||||
|
||||
EXPORT std::chrono::high_resolution_clock::time_point
|
||||
LastMacroConditionCheckTime(Macro *);
|
||||
LastMacroConditionCheckTime(const Macro *);
|
||||
|
||||
EXPORT bool MacroIsStopped(Macro *);
|
||||
EXPORT bool MacroIsPaused(Macro *);
|
||||
EXPORT bool MacroIsStopped(const Macro *);
|
||||
EXPORT bool MacroIsPaused(const Macro *);
|
||||
EXPORT bool
|
||||
MacroWasPausedSince(Macro *,
|
||||
MacroWasPausedSince(const Macro *,
|
||||
const std::chrono::high_resolution_clock::time_point &);
|
||||
EXPORT bool MacroWasCheckedSinceLastStart(Macro *);
|
||||
EXPORT bool MacroWasCheckedSinceLastStart(const Macro *);
|
||||
|
||||
EXPORT void AddMacroHelperThread(Macro *, std::thread &&);
|
||||
|
||||
@@ -68,6 +68,6 @@ EXPORT void InvalidateMacroTempVarValues();
|
||||
EXPORT void ResetMacroConditionTimers(Macro *);
|
||||
EXPORT void ResetMacroRunCount(Macro *);
|
||||
|
||||
bool IsValidMacroSegmentIndex(Macro *m, const int idx, bool isCondition);
|
||||
bool IsValidMacroSegmentIndex(const Macro *m, const int idx, bool isCondition);
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "macro-list.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-selection.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
|
||||
@@ -10,11 +11,11 @@ MacroList::MacroList(QWidget *parent, bool allowDuplicates, bool reorder)
|
||||
: ListEditor(parent, reorder),
|
||||
_allowDuplicates(allowDuplicates)
|
||||
{
|
||||
QWidget::connect(window(),
|
||||
SIGNAL(MacroRenamed(const QString &, const QString &)),
|
||||
this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Rename(const QString &, const QString &)), this,
|
||||
SLOT(MacroRename(const QString &, const QString &)));
|
||||
QWidget::connect(window(), SIGNAL(MacroRemoved(const QString &)), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Remove(const QString &)), this,
|
||||
SLOT(MacroRemove(const QString &)));
|
||||
UpdateListSize();
|
||||
}
|
||||
|
||||
@@ -11,10 +11,14 @@ namespace advss {
|
||||
MacroRunButton::MacroRunButton(QWidget *parent) : QPushButton(parent)
|
||||
{
|
||||
installEventFilter(this);
|
||||
auto parentWindow = window();
|
||||
if (parentWindow) {
|
||||
parentWindow->installEventFilter(this);
|
||||
}
|
||||
|
||||
// GetSettingsWindow() might still return null while this constructor is called
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
auto parentWindow = GetSettingsWindow();
|
||||
if (parentWindow) {
|
||||
parentWindow->installEventFilter(this);
|
||||
}
|
||||
});
|
||||
|
||||
setToolTip(obs_module_text("AdvSceneSwitcher.macroTab.run.tooltip"));
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ struct MacroSegmentCopyInfo {
|
||||
};
|
||||
static MacroSegmentCopyInfo copyInfo;
|
||||
|
||||
void AdvSceneSwitcher::CopyMacroSegment()
|
||||
void MacroEdit::CopyMacroSegment()
|
||||
{
|
||||
copyInfo.segment.reset();
|
||||
copyInfo.type = MacroSegmentCopyInfo::Type::NONE;
|
||||
@@ -23,7 +23,7 @@ void AdvSceneSwitcher::CopyMacroSegment()
|
||||
return;
|
||||
}
|
||||
|
||||
auto macro = GetSelectedMacro();
|
||||
auto macro = _currentMacro;
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
@@ -43,13 +43,13 @@ void AdvSceneSwitcher::CopyMacroSegment()
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::PasteMacroSegment()
|
||||
void MacroEdit::PasteMacroSegment()
|
||||
{
|
||||
if (copyInfo.type == MacroSegmentCopyInfo::Type::NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto macro = GetSelectedMacro();
|
||||
auto macro = _currentMacro;
|
||||
if (!macro || !copyInfo.segment) {
|
||||
return;
|
||||
}
|
||||
@@ -113,14 +113,14 @@ void SetCopySegmentTargetActionType(bool setToElseAction)
|
||||
}
|
||||
}
|
||||
|
||||
void SetupSegmentCopyPasteShortcutHandlers(AdvSceneSwitcher *window)
|
||||
void SetupSegmentCopyPasteShortcutHandlers(MacroEdit *edit)
|
||||
{
|
||||
auto copyShortcut = new QShortcut(QKeySequence("Ctrl+C"), window);
|
||||
QWidget::connect(copyShortcut, &QShortcut::activated, window,
|
||||
&AdvSceneSwitcher::CopyMacroSegment);
|
||||
auto pasteShortcut = new QShortcut(QKeySequence("Ctrl+V"), window);
|
||||
QWidget::connect(pasteShortcut, &QShortcut::activated, window,
|
||||
&AdvSceneSwitcher::PasteMacroSegment);
|
||||
auto copyShortcut = new QShortcut(QKeySequence("Ctrl+C"), edit);
|
||||
QWidget::connect(copyShortcut, &QShortcut::activated, edit,
|
||||
&MacroEdit::CopyMacroSegment);
|
||||
auto pasteShortcut = new QShortcut(QKeySequence("Ctrl+V"), edit);
|
||||
QWidget::connect(pasteShortcut, &QShortcut::activated, edit,
|
||||
&MacroEdit::PasteMacroSegment);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
namespace advss {
|
||||
|
||||
class AdvSceneSwitcher;
|
||||
class MacroEdit;
|
||||
|
||||
bool MacroSegmentIsInClipboard();
|
||||
bool MacroActionIsInClipboard();
|
||||
void SetCopySegmentTargetActionType(bool setToElseAction);
|
||||
void SetupSegmentCopyPasteShortcutHandlers(AdvSceneSwitcher *window);
|
||||
void SetupSegmentCopyPasteShortcutHandlers(MacroEdit *edit);
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -13,36 +13,62 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
bool MacroSegmentList::_useCache = true;
|
||||
|
||||
MacroSegmentList::MacroSegmentList(QWidget *parent)
|
||||
: QScrollArea(parent),
|
||||
_stackedWidget(new QStackedWidget(this)),
|
||||
_layout(new QVBoxLayout),
|
||||
_contentLayout(new QVBoxLayout),
|
||||
_helpMsg(new QLabel)
|
||||
_helpMsg(new QLabel(this))
|
||||
{
|
||||
_helpMsg->setWordWrap(true);
|
||||
_helpMsg->setAlignment(Qt::AlignCenter);
|
||||
auto helpWidget = new QWidget(this);
|
||||
auto helpLayout = new QVBoxLayout(helpWidget);
|
||||
helpLayout->addWidget(_helpMsg);
|
||||
helpLayout->setAlignment(Qt::AlignCenter);
|
||||
|
||||
auto contentWidget = new QWidget(this);
|
||||
contentWidget->setLayout(_contentLayout);
|
||||
_contentLayout->setSpacing(0);
|
||||
auto helperLayout = new QGridLayout();
|
||||
helperLayout->addWidget(_helpMsg, 0, 0,
|
||||
Qt::AlignHCenter | Qt::AlignVCenter);
|
||||
helperLayout->addLayout(_contentLayout, 0, 0);
|
||||
helperLayout->setSizeConstraint(QLayout::SetMinAndMaxSize);
|
||||
_layout->addLayout(helperLayout, 10);
|
||||
_layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding,
|
||||
QSizePolicy::Expanding));
|
||||
auto wrapper = new QWidget;
|
||||
wrapper->setLayout(_layout);
|
||||
setWidget(wrapper);
|
||||
|
||||
auto contentWrapper = new QWidget(this);
|
||||
auto wrapperLayout = new QVBoxLayout(contentWrapper);
|
||||
wrapperLayout->setContentsMargins(0, 0, 0, 0);
|
||||
wrapperLayout->addWidget(contentWidget);
|
||||
// Move macro segments to the top of the list
|
||||
wrapperLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding,
|
||||
QSizePolicy::Expanding));
|
||||
|
||||
_stackedWidget->addWidget(helpWidget);
|
||||
_stackedWidget->addWidget(contentWrapper);
|
||||
|
||||
setWidget(_stackedWidget);
|
||||
setWidgetResizable(true);
|
||||
setAcceptDrops(true);
|
||||
|
||||
SetHelpMsgVisible(true);
|
||||
|
||||
connect(verticalScrollBar(), &QScrollBar::valueChanged, this,
|
||||
[this]() { SetupVisibleMacroSegmentWidgets(); });
|
||||
}
|
||||
|
||||
static void clearWidgetVector(const std::vector<QWidget *> &widgets)
|
||||
{
|
||||
for (auto widget : widgets) {
|
||||
widget->deleteLater();
|
||||
}
|
||||
};
|
||||
|
||||
MacroSegmentList::~MacroSegmentList()
|
||||
{
|
||||
if (_autoScrollThread.joinable()) {
|
||||
_autoScroll = false;
|
||||
_autoScrollThread.join();
|
||||
}
|
||||
|
||||
ClearWidgetCache();
|
||||
}
|
||||
|
||||
static bool posIsInScrollbar(const QScrollBar *scrollbar, const QPoint &pos)
|
||||
@@ -53,7 +79,7 @@ static bool posIsInScrollbar(const QScrollBar *scrollbar, const QPoint &pos)
|
||||
if (!scrollbar->isVisible()) {
|
||||
return false;
|
||||
}
|
||||
const auto geo = scrollbar->geometry();
|
||||
const auto &geo = scrollbar->geometry();
|
||||
const auto globalGeo = QRect(scrollbar->mapToGlobal(geo.topLeft()),
|
||||
scrollbar->mapToGlobal(geo.bottomRight()));
|
||||
return globalGeo.contains(pos);
|
||||
@@ -93,31 +119,102 @@ void MacroSegmentList::SetHelpMsg(const QString &msg) const
|
||||
_helpMsg->setText(msg);
|
||||
}
|
||||
|
||||
void MacroSegmentList::SetHelpMsgVisible(bool visible) const
|
||||
void MacroSegmentList::SetHelpMsgVisible(bool visible)
|
||||
{
|
||||
_helpMsg->setVisible(visible);
|
||||
_stackedWidget->setCurrentIndex(visible ? 0 : 1);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroSegmentList::Insert(int idx, MacroSegmentEdit *widget)
|
||||
void MacroSegmentList::Insert(int idx, QWidget *widget)
|
||||
{
|
||||
widget->installEventFilter(this);
|
||||
_contentLayout->insertWidget(idx, widget);
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
SetHelpMsgVisible(false);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroSegmentList::Add(QWidget *widget)
|
||||
{
|
||||
widget->installEventFilter(this);
|
||||
_contentLayout->addWidget(widget);
|
||||
Insert(_contentLayout->count(), widget);
|
||||
}
|
||||
|
||||
void MacroSegmentList::Remove(int idx) const
|
||||
void MacroSegmentList::Remove(int idx)
|
||||
{
|
||||
DeleteLayoutItemWidget(_contentLayout->takeAt(idx));
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
if (IsEmpty()) {
|
||||
SetHelpMsgVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSegmentList::Clear(int idx) const
|
||||
void MacroSegmentList::Clear(int idx)
|
||||
{
|
||||
ClearLayout(_contentLayout, idx);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
SetHelpMsgVisible(true);
|
||||
}
|
||||
|
||||
void MacroSegmentList::SetCachingEnabled(bool enable)
|
||||
{
|
||||
_useCache = enable;
|
||||
}
|
||||
|
||||
void MacroSegmentList::CacheCurrentWidgetsFor(const Macro *macro)
|
||||
{
|
||||
if (!_useCache) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<QWidget *> result;
|
||||
int idx = 0;
|
||||
QLayoutItem *item;
|
||||
while ((item = _contentLayout->takeAt(idx))) {
|
||||
if (!item || !item->widget()) {
|
||||
continue;
|
||||
}
|
||||
auto widget = item->widget();
|
||||
widget->hide();
|
||||
result.emplace_back(widget);
|
||||
}
|
||||
|
||||
_widgetCache[macro] = result;
|
||||
}
|
||||
|
||||
bool MacroSegmentList::PopulateWidgetsFromCache(const Macro *macro)
|
||||
{
|
||||
if (!_useCache) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = _widgetCache.find(macro);
|
||||
if (it == _widgetCache.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto widget : it->second) {
|
||||
_contentLayout->addWidget(widget);
|
||||
widget->show();
|
||||
}
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroSegmentList::ClearWidgetsFromCacheFor(const Macro *macro)
|
||||
{
|
||||
auto it = _widgetCache.find(macro);
|
||||
if (it == _widgetCache.end()) {
|
||||
return;
|
||||
}
|
||||
clearWidgetVector(it->second);
|
||||
_widgetCache.erase(it);
|
||||
}
|
||||
|
||||
void MacroSegmentList::Highlight(int idx, QColor color)
|
||||
@@ -265,6 +362,13 @@ void MacroSegmentList::HideLastDropLine()
|
||||
_dropLineIdx = -1;
|
||||
}
|
||||
|
||||
void MacroSegmentList::ClearWidgetCache()
|
||||
{
|
||||
for (const auto &[_, widgets] : _widgetCache) {
|
||||
clearWidgetVector(widgets);
|
||||
}
|
||||
}
|
||||
|
||||
static bool isInUpperHalfOf(const QPoint &pos, const QRect &rect)
|
||||
{
|
||||
return QRect(rect.topLeft(),
|
||||
@@ -322,6 +426,55 @@ QRect MacroSegmentList::GetContentItemRectWithPadding(int idx) const
|
||||
return rect;
|
||||
}
|
||||
|
||||
void MacroSegmentList::SetVisibilityCheckEnable(bool enable)
|
||||
{
|
||||
_checkVisibility = enable;
|
||||
|
||||
if (_checkVisibility) {
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool MacroSegmentList::IsEmpty() const
|
||||
{
|
||||
return _contentLayout->count() == 0;
|
||||
}
|
||||
|
||||
QSize MacroSegmentList::minimumSizeHint() const
|
||||
{
|
||||
return _stackedWidget->currentWidget()->minimumSizeHint();
|
||||
}
|
||||
|
||||
QSize MacroSegmentList::sizeHint() const
|
||||
{
|
||||
const auto contentSize = _stackedWidget->currentWidget()->sizeHint();
|
||||
const auto hint =
|
||||
QSize(width(), contentSize.height() + 2 * frameWidth());
|
||||
return hint;
|
||||
}
|
||||
|
||||
void MacroSegmentList::SetupVisibleMacroSegmentWidgets()
|
||||
{
|
||||
if (!_checkVisibility) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto viewportRect = viewport()->rect();
|
||||
|
||||
for (auto segment : widget()->findChildren<MacroSegmentEdit *>()) {
|
||||
const auto pos = segment->mapTo(viewport(), QPoint(0, 0));
|
||||
const QRect rect(pos, segment->size());
|
||||
if (!viewportRect.intersects(rect)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
segment->SetupWidgets();
|
||||
}
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
int MacroSegmentList::GetSegmentIndexFromPos(const QPoint &pos) const
|
||||
{
|
||||
int idx = -1;
|
||||
@@ -455,4 +608,10 @@ void MacroSegmentList::dropEvent(QDropEvent *event)
|
||||
_dragPosition = -1;
|
||||
}
|
||||
|
||||
void MacroSegmentList::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QScrollArea::resizeEvent(event);
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,56 +1,80 @@
|
||||
#pragma once
|
||||
#include "macro-segment.hpp"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QScrollArea>
|
||||
#include <QVBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <thread>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QScrollArea>
|
||||
#include <QStackedWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class Macro;
|
||||
|
||||
class MacroSegmentList : public QScrollArea {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroSegmentList(QWidget *parent = nullptr);
|
||||
virtual ~MacroSegmentList();
|
||||
~MacroSegmentList();
|
||||
|
||||
void SetHelpMsg(const QString &msg) const;
|
||||
void SetHelpMsgVisible(bool visible) const;
|
||||
void SetHelpMsgVisible(bool visible);
|
||||
|
||||
MacroSegmentEdit *WidgetAt(int idx) const;
|
||||
MacroSegmentEdit *WidgetAt(const QPoint &) const;
|
||||
|
||||
int IndexAt(const QPoint &) const;
|
||||
void Insert(int idx, MacroSegmentEdit *widget);
|
||||
void Insert(int idx, QWidget *widget);
|
||||
void Add(QWidget *widget);
|
||||
void Remove(int idx) const;
|
||||
void Clear(int idx = 0) const; // Clear all elements >= idx
|
||||
void Remove(int idx);
|
||||
void Clear(int idx = 0); // Clear all elements >= idx
|
||||
bool IsEmpty() const;
|
||||
|
||||
static void SetCachingEnabled(bool enable);
|
||||
void CacheCurrentWidgetsFor(const Macro *);
|
||||
bool PopulateWidgetsFromCache(const Macro *);
|
||||
void ClearWidgetsFromCacheFor(const Macro *);
|
||||
void SetVisibilityCheckEnable(bool enable);
|
||||
|
||||
void Highlight(int idx, QColor color = QColor(Qt::green));
|
||||
|
||||
void SetCollapsed(bool) const;
|
||||
void SetSelection(int idx) const;
|
||||
QVBoxLayout *ContentLayout() const { return _contentLayout; }
|
||||
|
||||
QSize minimumSizeHint() const override;
|
||||
QSize sizeHint() const override;
|
||||
|
||||
signals:
|
||||
void SelectionChanged(int idx);
|
||||
void Reorder(int source, int target);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *object, QEvent *event);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
void mouseReleaseEvent(QMouseEvent *event);
|
||||
void dragLeaveEvent(QDragLeaveEvent *event);
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
void dragMoveEvent(QDragMoveEvent *event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
bool eventFilter(QObject *object, QEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void dragLeaveEvent(QDragLeaveEvent *event) override;
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
void SetupVisibleMacroSegmentWidgets();
|
||||
void ClearWidgetCache();
|
||||
|
||||
int GetSegmentIndexFromPos(const QPoint &) const;
|
||||
bool IsInListArea(const QPoint &) const;
|
||||
QRect GetContentItemRectWithPadding(int idx) const;
|
||||
|
||||
int GetDragIndex(const QPoint &) const;
|
||||
int GetDropIndex(const QPoint &) const;
|
||||
void CheckScroll() const;
|
||||
void CheckDropLine(const QPoint &);
|
||||
bool IsInListArea(const QPoint &) const;
|
||||
QRect GetContentItemRectWithPadding(int idx) const;
|
||||
void HideLastDropLine();
|
||||
|
||||
int _dragPosition = -1;
|
||||
@@ -59,9 +83,15 @@ private:
|
||||
std::thread _autoScrollThread;
|
||||
std::atomic_bool _autoScroll{false};
|
||||
|
||||
QStackedWidget *_stackedWidget;
|
||||
QVBoxLayout *_layout;
|
||||
QVBoxLayout *_contentLayout;
|
||||
QLabel *_helpMsg;
|
||||
|
||||
bool _checkVisibility = true;
|
||||
|
||||
static bool _useCache;
|
||||
std::unordered_map<const Macro *, std::vector<QWidget *>> _widgetCache;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-segment.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
@@ -31,7 +32,8 @@ MacroSegmentSelection::MacroSegmentSelection(QWidget *parent, Type type,
|
||||
_index,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(IndexChanged(const NumberVariable<int> &)));
|
||||
QWidget::connect(window(), SIGNAL(MacroSegmentOrderChanged()), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(SegmentOrderChanged()), this,
|
||||
SLOT(MacroSegmentOrderChanged()));
|
||||
|
||||
auto layout = new QHBoxLayout;
|
||||
|
||||
74
lib/macro/macro-segment-unknown.hpp
Normal file
74
lib/macro/macro-segment-unknown.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
#include "macro-action.hpp"
|
||||
#include "macro-condition.hpp"
|
||||
|
||||
#include <obs.hpp>
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
namespace advss {
|
||||
|
||||
// Retains the settings and ID of the macro segment even if they can't be
|
||||
// interpreted correctly right now.
|
||||
//
|
||||
// As soon as a version of the plugin supporting the original ID is running it
|
||||
// will take over again
|
||||
template<typename T> class MacroSegmentUnknown : public T {
|
||||
public:
|
||||
MacroSegmentUnknown(Macro *macro, const std::string &originalId);
|
||||
bool CheckCondition() { return false; }
|
||||
std::shared_ptr<MacroAction> Copy() const;
|
||||
bool PerformAction() { return true; };
|
||||
bool Save(obs_data_t *data) const;
|
||||
bool Load(obs_data_t *data);
|
||||
std::string GetId() const { return "unknown"; }
|
||||
|
||||
private:
|
||||
std::string _id;
|
||||
OBSData _settings;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline MacroSegmentUnknown<T>::MacroSegmentUnknown(
|
||||
Macro *macro, const std::string &originalId)
|
||||
: T(macro),
|
||||
_id(originalId),
|
||||
_settings(obs_data_create())
|
||||
{
|
||||
obs_data_release(_settings);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline std::shared_ptr<MacroAction> MacroSegmentUnknown<T>::Copy() const
|
||||
{
|
||||
if constexpr (std::is_same_v<T, MacroAction>) {
|
||||
return std::make_shared<MacroSegmentUnknown<T>>(
|
||||
MacroAction::GetMacro(), _id);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool MacroSegmentUnknown<T>::Save(obs_data_t *data) const
|
||||
{
|
||||
T::Save(data);
|
||||
obs_data_apply(data, _settings);
|
||||
obs_data_set_string(_settings, "id", _id.c_str());
|
||||
return true;
|
||||
};
|
||||
|
||||
template<typename T> inline bool MacroSegmentUnknown<T>::Load(obs_data_t *data)
|
||||
{
|
||||
T::Load(data);
|
||||
obs_data_apply(_settings, data);
|
||||
return true;
|
||||
};
|
||||
|
||||
inline QWidget *CreateUnknownSegmentWidget(bool isAction)
|
||||
{
|
||||
return new QLabel(obs_module_text(
|
||||
isAction ? "AdvSceneSwitcher.action.unknown"
|
||||
: "AdvSceneSwitcher.condition.unknown"));
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
@@ -107,7 +107,7 @@ void MacroSegment::SetupTempVars()
|
||||
void MacroSegment::ClearAvailableTempvars()
|
||||
{
|
||||
_tempVariables.clear();
|
||||
NotifyUIAboutTempVarChange();
|
||||
NotifyUIAboutTempVarChange(this);
|
||||
}
|
||||
|
||||
static std::shared_ptr<MacroSegment>
|
||||
@@ -149,7 +149,7 @@ void MacroSegment::AddTempvar(const std::string &id, const std::string &name,
|
||||
|
||||
TempVariable var(id, name, description, sharedSegment);
|
||||
_tempVariables.emplace_back(std::move(var));
|
||||
NotifyUIAboutTempVarChange();
|
||||
NotifyUIAboutTempVarChange(this);
|
||||
}
|
||||
|
||||
void MacroSegment::SetTempVarValue(const std::string &id,
|
||||
@@ -256,23 +256,6 @@ MacroSegmentEdit::MacroSegmentEdit(QWidget *parent)
|
||||
|
||||
QWidget::connect(_section, &Section::Collapsed, this,
|
||||
&MacroSegmentEdit::Collapsed);
|
||||
// Macro signals
|
||||
QWidget::connect(parent, SIGNAL(MacroAdded(const QString &)), this,
|
||||
SIGNAL(MacroAdded(const QString &)));
|
||||
QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this,
|
||||
SIGNAL(MacroRemoved(const QString &)));
|
||||
QWidget::connect(
|
||||
parent, SIGNAL(MacroRenamed(const QString &, const QString &)),
|
||||
this, SIGNAL(MacroRenamed(const QString &, const QString &)));
|
||||
// Scene group signals
|
||||
QWidget::connect(parent, SIGNAL(SceneGroupAdded(const QString &)), this,
|
||||
SIGNAL(SceneGroupAdded(const QString &)));
|
||||
QWidget::connect(parent, SIGNAL(SceneGroupRemoved(const QString &)),
|
||||
this, SIGNAL(SceneGroupRemoved(const QString &)));
|
||||
QWidget::connect(
|
||||
parent,
|
||||
SIGNAL(SceneGroupRenamed(const QString &, const QString)), this,
|
||||
SIGNAL(SceneGroupRenamed(const QString &, const QString)));
|
||||
|
||||
auto frameLayout = new QGridLayout;
|
||||
frameLayout->setContentsMargins(0, 0, 0, 0);
|
||||
@@ -324,7 +307,7 @@ void MacroSegmentEdit::HeaderInfoChanged(const QString &text)
|
||||
_headerInfo->setText(text);
|
||||
}
|
||||
|
||||
void MacroSegmentEdit::Collapsed(bool collapsed)
|
||||
void MacroSegmentEdit::Collapsed(bool collapsed) const
|
||||
{
|
||||
if (Data()) {
|
||||
Data()->SetCollapsed(collapsed);
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace advss {
|
||||
|
||||
class Macro;
|
||||
|
||||
class EXPORT MacroSegment {
|
||||
class EXPORT MacroSegment : public Lockable {
|
||||
public:
|
||||
MacroSegment(Macro *m, bool supportsVariableValue);
|
||||
virtual ~MacroSegment() = default;
|
||||
@@ -48,7 +48,7 @@ protected:
|
||||
friend void IncrementVariableRef(MacroSegment *);
|
||||
friend void DecrementVariableRef(MacroSegment *);
|
||||
void SetVariableValue(const std::string &value);
|
||||
bool IsReferencedInVars() { return _variableRefs != 0; }
|
||||
bool IsReferencedInVars() const { return _variableRefs != 0; }
|
||||
|
||||
virtual void SetupTempVars();
|
||||
void AddTempvar(const std::string &id, const std::string &name,
|
||||
@@ -106,19 +106,13 @@ public:
|
||||
void SetCollapsed(bool collapsed);
|
||||
void SetSelected(bool);
|
||||
virtual std::shared_ptr<MacroSegment> Data() const = 0;
|
||||
virtual void SetupWidgets(bool basicSetup = false) = 0;
|
||||
|
||||
public slots:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected slots:
|
||||
void Collapsed(bool);
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void SceneGroupAdded(const QString &name);
|
||||
void SceneGroupRemoved(const QString &name);
|
||||
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
||||
void Collapsed(bool) const;
|
||||
|
||||
protected:
|
||||
void SetDisableEffect(bool);
|
||||
@@ -130,6 +124,7 @@ protected:
|
||||
QLabel *_headerInfo;
|
||||
QWidget *_frame;
|
||||
QVBoxLayout *_contentLayout;
|
||||
bool _allWidgetsAreSetup = false;
|
||||
|
||||
private:
|
||||
enum class DropLineState {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
@@ -20,15 +21,14 @@ MacroSelection::MacroSelection(QWidget *parent)
|
||||
addItem(QString::fromStdString(m->Name()));
|
||||
}
|
||||
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroAdded(const QString &)), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Add(const QString &)), this,
|
||||
SLOT(MacroAdd(const QString &)));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroRemoved(const QString &)), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Remove(const QString &)), this,
|
||||
SLOT(MacroRemove(const QString &)));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroRenamed(const QString &, const QString &)),
|
||||
this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Rename(const QString &, const QString &)), this,
|
||||
SLOT(MacroRename(const QString &, const QString &)));
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ void MacroSelection::SetCurrentMacro(const MacroRef ¯o)
|
||||
|
||||
void MacroSelection::HideSelectedMacro()
|
||||
{
|
||||
auto ssWindow = static_cast<AdvSceneSwitcher *>(window());
|
||||
auto ssWindow = static_cast<AdvSceneSwitcher *>(GetSettingsWindow());
|
||||
if (!ssWindow) {
|
||||
return;
|
||||
}
|
||||
@@ -76,12 +76,16 @@ void MacroSelection::ShowAllMacros()
|
||||
|
||||
void MacroSelection::MacroRemove(const QString &name)
|
||||
{
|
||||
const bool currentSelectionWasRemoved = name == currentText();
|
||||
|
||||
int idx = findText(name);
|
||||
if (idx == -1) {
|
||||
return;
|
||||
}
|
||||
removeItem(idx);
|
||||
setCurrentIndex(-1);
|
||||
if (currentSelectionWasRemoved) {
|
||||
setCurrentIndex(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSelection::MacroRename(const QString &oldName, const QString &newName)
|
||||
|
||||
@@ -19,6 +19,8 @@ void GlobalMacroSettings::Save(obs_data_t *obj) const
|
||||
obs_data_set_bool(data, "highlightExecuted", _highlightExecuted);
|
||||
obs_data_set_bool(data, "highlightConditions", _highlightConditions);
|
||||
obs_data_set_bool(data, "highlightActions", _highlightActions);
|
||||
obs_data_set_bool(data, "newMacroCheckInParallel",
|
||||
_newMacroCheckInParallel);
|
||||
obs_data_set_bool(data, "newMacroRegisterHotkey",
|
||||
_newMacroRegisterHotkeys);
|
||||
obs_data_set_bool(data, "newMacroUseShortCircuitEvaluation",
|
||||
@@ -41,6 +43,8 @@ void GlobalMacroSettings::Load(obs_data_t *obj)
|
||||
_highlightExecuted = obs_data_get_bool(data, "highlightExecuted");
|
||||
_highlightConditions = obs_data_get_bool(data, "highlightConditions");
|
||||
_highlightActions = obs_data_get_bool(data, "highlightActions");
|
||||
_newMacroCheckInParallel =
|
||||
obs_data_get_bool(data, "newMacroCheckInParallel");
|
||||
_newMacroRegisterHotkeys =
|
||||
obs_data_get_bool(data, "newMacroRegisterHotkey");
|
||||
_newMacroUseShortCircuitEvaluation =
|
||||
@@ -62,12 +66,16 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
"AdvSceneSwitcher.macroTab.highlightTrueConditions"))),
|
||||
_highlightActions(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.highlightPerformedActions"))),
|
||||
_newMacroCheckInParallel(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.newMacroCheckInParallel"))),
|
||||
_newMacroRegisterHotkeys(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.newMacroRegisterHotkey"))),
|
||||
_newMacroUseShortCircuitEvaluation(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.newMacroUseShortCircuitEvaluation"))),
|
||||
_saveSettingsOnMacroChange(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.saveSettingsOnMacroChange"))),
|
||||
_currentCheckInParallel(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentCheckInParallel"))),
|
||||
_currentMacroRegisterHotkeys(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentRegisterHotkeys"))),
|
||||
_currentUseShortCircuitEvaluation(new QCheckBox(obs_module_text(
|
||||
@@ -86,6 +94,9 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
_currentInputs(new MacroInputSelection()),
|
||||
_currentMacroRegisterDock(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentRegisterDock"))),
|
||||
_currentMacroIsStandaloneDock(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentIsStandaloneDock"))),
|
||||
_currentMacroDockWindowName(new QLineEdit(this)),
|
||||
_currentMacroDockAddRunButton(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentDockAddRunButton"))),
|
||||
_currentMacroDockAddPauseButton(new QCheckBox(obs_module_text(
|
||||
@@ -107,6 +118,11 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
setWindowModality(Qt::WindowModality::WindowModal);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
_newMacroCheckInParallel->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.checkInParallel.tooltip"));
|
||||
_currentCheckInParallel->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.checkInParallel.tooltip"));
|
||||
|
||||
_newMacroUseShortCircuitEvaluation->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.shortCircuit.tooltip"));
|
||||
_saveSettingsOnMacroChange->setToolTip(obs_module_text(
|
||||
@@ -146,6 +162,8 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
obs_module_text("AdvSceneSwitcher.macroTab.generalSettings"));
|
||||
auto generalLayout = new QVBoxLayout;
|
||||
generalLayout->addWidget(_saveSettingsOnMacroChange);
|
||||
generalLayout->addWidget(_currentCheckInParallel);
|
||||
generalLayout->addWidget(_newMacroCheckInParallel);
|
||||
generalLayout->addWidget(_currentSkipOnStartup);
|
||||
generalLayout->addWidget(_currentStopActionsIfNotDone);
|
||||
generalLayout->addWidget(_currentUseShortCircuitEvaluation);
|
||||
@@ -183,6 +201,15 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
int row = 0;
|
||||
_dockLayout->addWidget(_currentMacroRegisterDock, row, 1, 1, 2);
|
||||
row++;
|
||||
_dockLayout->addWidget(_currentMacroIsStandaloneDock, row, 1, 1, 2);
|
||||
row++;
|
||||
_dockLayout->addWidget(
|
||||
new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentDockWindowName")),
|
||||
row, 1);
|
||||
_dockLayout->addWidget(_currentMacroDockWindowName, row, 2);
|
||||
_dockWindowNameRow = row;
|
||||
row++;
|
||||
_dockLayout->addWidget(_currentMacroDockAddRunButton, row, 1, 1, 2);
|
||||
row++;
|
||||
_dockLayout->addWidget(
|
||||
@@ -237,6 +264,8 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
|
||||
connect(_currentMacroRegisterDock, &QCheckBox::stateChanged, this,
|
||||
&MacroSettingsDialog::DockEnableChanged);
|
||||
connect(_currentMacroIsStandaloneDock, &QCheckBox::stateChanged, this,
|
||||
&MacroSettingsDialog::IsStandaloneDockChanged);
|
||||
connect(_currentMacroDockAddRunButton, &QCheckBox::stateChanged, this,
|
||||
&MacroSettingsDialog::RunButtonEnableChanged);
|
||||
connect(_currentMacroDockAddPauseButton, &QCheckBox::stateChanged, this,
|
||||
@@ -273,6 +302,7 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
_highlightExecutedMacros->setChecked(settings._highlightExecuted);
|
||||
_highlightConditions->setChecked(settings._highlightConditions);
|
||||
_highlightActions->setChecked(settings._highlightActions);
|
||||
_newMacroCheckInParallel->setChecked(settings._newMacroCheckInParallel);
|
||||
_newMacroRegisterHotkeys->setChecked(settings._newMacroRegisterHotkeys);
|
||||
_newMacroUseShortCircuitEvaluation->setChecked(
|
||||
settings._newMacroUseShortCircuitEvaluation);
|
||||
@@ -280,20 +310,23 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
settings._saveSettingsOnMacroChange);
|
||||
|
||||
if (!macro || macro->IsGroup()) {
|
||||
hotkeyOptions->hide();
|
||||
|
||||
// General group
|
||||
_currentSkipOnStartup->hide();
|
||||
_currentStopActionsIfNotDone->hide();
|
||||
_currentUseShortCircuitEvaluation->hide();
|
||||
_currentCheckInParallel->hide();
|
||||
SetLayoutVisible(customConditionIntervalLayout, false);
|
||||
SetLayoutVisible(pauseStateSaveBehavorLayout, false);
|
||||
|
||||
// Hotkey group
|
||||
_currentMacroRegisterHotkeys->hide();
|
||||
|
||||
inputOptions->hide();
|
||||
_dockOptions->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
_currentCheckInParallel->setChecked(macro->CheckInParallel());
|
||||
_currentMacroRegisterHotkeys->setChecked(macro->PauseHotkeysEnabled());
|
||||
_currentUseShortCircuitEvaluation->setChecked(
|
||||
macro->ShortCircuitEvaluationEnabled());
|
||||
@@ -310,55 +343,37 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
_currentSkipOnStartup->setChecked(macro->SkipExecOnStart());
|
||||
_currentStopActionsIfNotDone->setChecked(macro->StopActionsIfNotDone());
|
||||
_currentInputs->SetInputs(macro->GetInputVariables());
|
||||
const bool dockEnabled = macro->DockEnabled();
|
||||
const auto &dockSettings = macro->GetDockSettings();
|
||||
const bool dockEnabled = dockSettings.DockEnabled();
|
||||
_currentMacroRegisterDock->setChecked(dockEnabled);
|
||||
_currentMacroDockAddRunButton->setChecked(macro->DockHasRunButton());
|
||||
_currentMacroIsStandaloneDock->setChecked(
|
||||
dockSettings.IsStandaloneDock());
|
||||
_currentMacroDockWindowName->setText(
|
||||
QString::fromStdString(dockSettings.DockWindowName()));
|
||||
_currentMacroDockAddRunButton->setChecked(dockSettings.HasRunButton());
|
||||
_currentMacroDockAddPauseButton->setChecked(
|
||||
macro->DockHasPauseButton());
|
||||
dockSettings.HasPauseButton());
|
||||
_currentMacroDockAddStatusLabel->setChecked(
|
||||
macro->DockHasStatusLabel());
|
||||
dockSettings.HasStatusLabel());
|
||||
_currentMacroDockHighlightIfConditionsTrue->setChecked(
|
||||
macro->DockHighlightEnabled());
|
||||
_runButtonText->setText(macro->RunButtonText());
|
||||
_pauseButtonText->setText(macro->PauseButtonText());
|
||||
_unpauseButtonText->setText(macro->UnpauseButtonText());
|
||||
_conditionsTrueStatusText->setText(macro->ConditionsTrueStatusText());
|
||||
_conditionsFalseStatusText->setText(macro->ConditionsFalseStatusText());
|
||||
dockSettings.HighlightEnabled());
|
||||
_runButtonText->setText(dockSettings.RunButtonText());
|
||||
_pauseButtonText->setText(dockSettings.PauseButtonText());
|
||||
_unpauseButtonText->setText(dockSettings.UnpauseButtonText());
|
||||
_conditionsTrueStatusText->setText(
|
||||
dockSettings.ConditionsTrueStatusText());
|
||||
_conditionsFalseStatusText->setText(
|
||||
dockSettings.ConditionsFalseStatusText());
|
||||
|
||||
_currentMacroDockAddRunButton->setVisible(dockEnabled);
|
||||
_currentMacroDockAddPauseButton->setVisible(dockEnabled);
|
||||
_currentMacroDockAddStatusLabel->setVisible(dockEnabled);
|
||||
_currentMacroDockHighlightIfConditionsTrue->setVisible(dockEnabled);
|
||||
SetGridLayoutRowVisible(_dockLayout, _runButtonTextRow,
|
||||
dockEnabled && macro->DockHasRunButton());
|
||||
SetGridLayoutRowVisible(_dockLayout, _pauseButtonTextRow,
|
||||
dockEnabled && macro->DockHasPauseButton());
|
||||
SetGridLayoutRowVisible(_dockLayout, _unpauseButtonTextRow,
|
||||
dockEnabled && macro->DockHasPauseButton());
|
||||
SetGridLayoutRowVisible(_dockLayout, _conditionsTrueTextRow,
|
||||
dockEnabled && macro->DockHasStatusLabel());
|
||||
SetGridLayoutRowVisible(_dockLayout, _conditionsFalseTextRow,
|
||||
dockEnabled && macro->DockHasStatusLabel());
|
||||
DockEnableChanged(dockEnabled);
|
||||
MinimizeSizeOfColumn(_dockLayout, 0);
|
||||
Resize();
|
||||
|
||||
// Try to set sensible initial size for the dialog window
|
||||
QSize contentSize = contentWidget->sizeHint();
|
||||
resize(contentSize.width() + layout->contentsMargins().left() +
|
||||
layout->contentsMargins().right() +
|
||||
dialogLayout->contentsMargins().left() +
|
||||
dialogLayout->contentsMargins().right() +
|
||||
scrollArea->verticalScrollBar()->sizeHint().width() + 20,
|
||||
contentSize.height() + dialogLayout->spacing() +
|
||||
buttonbox->sizeHint().height() +
|
||||
dialogLayout->contentsMargins().top() +
|
||||
dialogLayout->contentsMargins().bottom() +
|
||||
scrollArea->horizontalScrollBar()->sizeHint().height() +
|
||||
20);
|
||||
Resize();
|
||||
}
|
||||
|
||||
void MacroSettingsDialog::DockEnableChanged(int enabled)
|
||||
{
|
||||
_currentMacroIsStandaloneDock->setVisible(enabled);
|
||||
_currentMacroDockAddRunButton->setVisible(enabled);
|
||||
_currentMacroDockAddPauseButton->setVisible(enabled);
|
||||
_currentMacroDockAddStatusLabel->setVisible(enabled);
|
||||
@@ -382,6 +397,12 @@ void MacroSettingsDialog::DockEnableChanged(int enabled)
|
||||
Resize();
|
||||
}
|
||||
|
||||
void MacroSettingsDialog::IsStandaloneDockChanged(int enabled)
|
||||
{
|
||||
SetGridLayoutRowVisible(_dockLayout, _dockWindowNameRow, !enabled);
|
||||
Resize();
|
||||
}
|
||||
|
||||
void MacroSettingsDialog::RunButtonEnableChanged(int enabled)
|
||||
{
|
||||
SetGridLayoutRowVisible(_dockLayout, _runButtonTextRow, enabled);
|
||||
@@ -431,6 +452,8 @@ bool MacroSettingsDialog::AskForSettings(QWidget *parent,
|
||||
userInput._highlightConditions =
|
||||
dialog._highlightConditions->isChecked();
|
||||
userInput._highlightActions = dialog._highlightActions->isChecked();
|
||||
userInput._newMacroCheckInParallel =
|
||||
dialog._newMacroCheckInParallel->isChecked();
|
||||
userInput._newMacroRegisterHotkeys =
|
||||
dialog._newMacroRegisterHotkeys->isChecked();
|
||||
userInput._newMacroUseShortCircuitEvaluation =
|
||||
@@ -441,6 +464,7 @@ bool MacroSettingsDialog::AskForSettings(QWidget *parent,
|
||||
return true;
|
||||
}
|
||||
|
||||
macro->SetCheckInParallel(dialog._currentCheckInParallel->isChecked());
|
||||
macro->EnablePauseHotkeys(
|
||||
dialog._currentMacroRegisterHotkeys->isChecked());
|
||||
macro->SetShortCircuitEvaluation(
|
||||
@@ -456,23 +480,30 @@ bool MacroSettingsDialog::AskForSettings(QWidget *parent,
|
||||
macro->SetSkipExecOnStart(dialog._currentSkipOnStartup->isChecked());
|
||||
macro->SetStopActionsIfNotDone(
|
||||
dialog._currentStopActionsIfNotDone->isChecked());
|
||||
macro->EnableDock(dialog._currentMacroRegisterDock->isChecked());
|
||||
macro->SetDockHasRunButton(
|
||||
|
||||
auto &dockSettings = macro->GetDockSettings();
|
||||
dockSettings.EnableDock(dialog._currentMacroRegisterDock->isChecked());
|
||||
dockSettings.SetIsStandaloneDock(
|
||||
dialog._currentMacroIsStandaloneDock->isChecked());
|
||||
dockSettings.SetDockWindowName(
|
||||
dialog._currentMacroDockWindowName->text().toStdString());
|
||||
dockSettings.SetHasRunButton(
|
||||
dialog._currentMacroDockAddRunButton->isChecked());
|
||||
macro->SetDockHasPauseButton(
|
||||
dockSettings.SetHasPauseButton(
|
||||
dialog._currentMacroDockAddPauseButton->isChecked());
|
||||
macro->SetDockHasStatusLabel(
|
||||
dockSettings.SetHasStatusLabel(
|
||||
dialog._currentMacroDockAddStatusLabel->isChecked());
|
||||
macro->SetHighlightEnable(
|
||||
dockSettings.SetHighlightEnable(
|
||||
dialog._currentMacroDockHighlightIfConditionsTrue->isChecked());
|
||||
macro->SetRunButtonText(dialog._runButtonText->text().toStdString());
|
||||
macro->SetPauseButtonText(
|
||||
dockSettings.SetRunButtonText(
|
||||
dialog._runButtonText->text().toStdString());
|
||||
dockSettings.SetPauseButtonText(
|
||||
dialog._pauseButtonText->text().toStdString());
|
||||
macro->SetUnpauseButtonText(
|
||||
dockSettings.SetUnpauseButtonText(
|
||||
dialog._unpauseButtonText->text().toStdString());
|
||||
macro->SetConditionsTrueStatusText(
|
||||
dockSettings.SetConditionsTrueStatusText(
|
||||
dialog._conditionsTrueStatusText->text().toStdString());
|
||||
macro->SetConditionsFalseStatusText(
|
||||
dockSettings.SetConditionsFalseStatusText(
|
||||
dialog._conditionsFalseStatusText->text().toStdString());
|
||||
macro->SetInputVariables(dialog._currentInputs->GetInputs());
|
||||
return true;
|
||||
|
||||
@@ -20,9 +20,10 @@ public:
|
||||
void Save(obs_data_t *obj) const;
|
||||
void Load(obs_data_t *obj);
|
||||
|
||||
bool _highlightExecuted = false;
|
||||
bool _highlightConditions = false;
|
||||
bool _highlightActions = false;
|
||||
bool _highlightExecuted = true;
|
||||
bool _highlightConditions = true;
|
||||
bool _highlightActions = true;
|
||||
bool _newMacroCheckInParallel = false;
|
||||
bool _newMacroRegisterHotkeys = true;
|
||||
bool _newMacroUseShortCircuitEvaluation = false;
|
||||
bool _saveSettingsOnMacroChange = true;
|
||||
@@ -40,6 +41,7 @@ public:
|
||||
Macro *macro);
|
||||
private slots:
|
||||
void DockEnableChanged(int);
|
||||
void IsStandaloneDockChanged(int);
|
||||
void RunButtonEnableChanged(int);
|
||||
void PauseButtonEnableChanged(int);
|
||||
void StatusLabelEnableChanged(int);
|
||||
@@ -52,10 +54,12 @@ private:
|
||||
QCheckBox *_highlightExecutedMacros;
|
||||
QCheckBox *_highlightConditions;
|
||||
QCheckBox *_highlightActions;
|
||||
QCheckBox *_newMacroCheckInParallel;
|
||||
QCheckBox *_newMacroRegisterHotkeys;
|
||||
QCheckBox *_newMacroUseShortCircuitEvaluation;
|
||||
QCheckBox *_saveSettingsOnMacroChange;
|
||||
// Current macro specific settings
|
||||
QCheckBox *_currentCheckInParallel;
|
||||
QCheckBox *_currentMacroRegisterHotkeys;
|
||||
QCheckBox *_currentUseShortCircuitEvaluation;
|
||||
QCheckBox *_currentUseCustomConditionCheckInterval;
|
||||
@@ -66,6 +70,8 @@ private:
|
||||
QCheckBox *_currentStopActionsIfNotDone;
|
||||
MacroInputSelection *_currentInputs;
|
||||
QCheckBox *_currentMacroRegisterDock;
|
||||
QCheckBox *_currentMacroIsStandaloneDock;
|
||||
QLineEdit *_currentMacroDockWindowName;
|
||||
QCheckBox *_currentMacroDockAddRunButton;
|
||||
QCheckBox *_currentMacroDockAddPauseButton;
|
||||
QCheckBox *_currentMacroDockAddStatusLabel;
|
||||
@@ -78,6 +84,7 @@ private:
|
||||
QGroupBox *_dockOptions;
|
||||
QGridLayout *_dockLayout;
|
||||
|
||||
int _dockWindowNameRow = -1;
|
||||
int _runButtonTextRow = -1;
|
||||
int _pauseButtonTextRow = -1;
|
||||
int _unpauseButtonTextRow = -1;
|
||||
|
||||
13
lib/macro/macro-signals.cpp
Normal file
13
lib/macro/macro-signals.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "macro-signals.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
MacroSignalManager::MacroSignalManager(QObject *parent) : QObject(parent) {}
|
||||
|
||||
MacroSignalManager *MacroSignalManager::Instance()
|
||||
{
|
||||
static MacroSignalManager manager;
|
||||
return &manager;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
26
lib/macro/macro-signals.hpp
Normal file
26
lib/macro/macro-signals.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
#pragma once
|
||||
#include "export-symbol-helper.hpp"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class ADVSS_EXPORT MacroSignalManager : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static MacroSignalManager *Instance();
|
||||
|
||||
signals:
|
||||
void Rename(const QString &, const QString &);
|
||||
void Add(const QString &);
|
||||
void Remove(const QString &);
|
||||
void SegmentOrderChanged();
|
||||
void HighlightChanged(bool value);
|
||||
|
||||
private:
|
||||
MacroSignalManager(QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
#include "macro-tree.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "path-helpers.hpp"
|
||||
#include "sync-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
@@ -79,10 +80,10 @@ MacroTreeItem::MacroTreeItem(MacroTree *tree, std::shared_ptr<Macro> macroItem,
|
||||
_macro->SetPaused(!val);
|
||||
};
|
||||
connect(_running, &QAbstractButton::clicked, setRunning);
|
||||
connect(_tree->window(), SIGNAL(HighlightMacrosChanged(bool)), this,
|
||||
SLOT(EnableHighlight(bool)));
|
||||
connect(_tree->window(),
|
||||
SIGNAL(MacroRenamed(const QString &, const QString &)), this,
|
||||
connect(MacroSignalManager::Instance(), SIGNAL(HighlightChanged(bool)),
|
||||
this, SLOT(EnableHighlight(bool)));
|
||||
connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Rename(const QString &, const QString &)), this,
|
||||
SLOT(MacroRenamed(const QString &, const QString &)));
|
||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(HighlightIfExecuted()));
|
||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(UpdatePaused()));
|
||||
@@ -414,6 +415,20 @@ void MacroTreeModel::Add(std::shared_ptr<Macro> item)
|
||||
QItemSelectionModel::Select);
|
||||
}
|
||||
|
||||
void MacroTreeModel::MoveToBeginningOfGroup(std::shared_ptr<Macro> item,
|
||||
std::shared_ptr<Macro> group)
|
||||
{
|
||||
auto it = std::find(_macros.begin(), _macros.end(), item);
|
||||
assert(it != _macros.end());
|
||||
std::shared_ptr<Macro> tmp = *it;
|
||||
_macros.erase(it);
|
||||
it = std::find(_macros.begin(), _macros.end(), group);
|
||||
assert(it != _macros.end());
|
||||
_macros.insert(std::next(it), tmp);
|
||||
|
||||
Reset(_macros);
|
||||
}
|
||||
|
||||
void MacroTreeModel::Remove(std::shared_ptr<Macro> item)
|
||||
{
|
||||
auto lock = LockContext();
|
||||
@@ -789,6 +804,13 @@ void MacroTree::Add(std::shared_ptr<Macro> item,
|
||||
assert(GetModel()->IsInValidState());
|
||||
}
|
||||
|
||||
void MacroTree::AddToGroup(std::shared_ptr<Macro> item,
|
||||
std::shared_ptr<Macro> group) const
|
||||
{
|
||||
GetModel()->Add(item);
|
||||
GetModel()->MoveToBeginningOfGroup(item, group);
|
||||
}
|
||||
|
||||
std::shared_ptr<Macro> MacroTree::GetCurrentMacro() const
|
||||
{
|
||||
return GetModel()->GetCurrentMacro();
|
||||
@@ -1160,6 +1182,28 @@ bool MacroTree::SelectionEmpty() const
|
||||
return selectedIndexes().empty();
|
||||
}
|
||||
|
||||
bool MacroTree::GroupsExist() const
|
||||
{
|
||||
for (const auto ¯o : GetMacros()) {
|
||||
if (macro->IsGroup()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MacroTree::ExpandGroup(std::shared_ptr<Macro> item) const
|
||||
{
|
||||
auto *mtm = GetModel();
|
||||
mtm->ExpandGroup(item);
|
||||
}
|
||||
|
||||
void MacroTree::CollapseGroup(std::shared_ptr<Macro> item) const
|
||||
{
|
||||
auto *mtm = GetModel();
|
||||
mtm->CollapseGroup(item);
|
||||
}
|
||||
|
||||
void MacroTree::MoveItemBefore(const std::shared_ptr<Macro> &item,
|
||||
const std::shared_ptr<Macro> &after) const
|
||||
{
|
||||
@@ -1260,6 +1304,26 @@ void MacroTree::UngroupSelectedGroups()
|
||||
assert(GetModel()->IsInValidState());
|
||||
}
|
||||
|
||||
void MacroTree::ExpandAll()
|
||||
{
|
||||
for (const auto ¯o : GetMacros()) {
|
||||
if (!macro->IsGroup()) {
|
||||
continue;
|
||||
}
|
||||
ExpandGroup(macro);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroTree::CollapseAll()
|
||||
{
|
||||
for (const auto ¯o : GetMacros()) {
|
||||
if (!macro->IsGroup()) {
|
||||
continue;
|
||||
}
|
||||
CollapseGroup(macro);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroTree::SelectionChangedHelper(const QItemSelection &,
|
||||
const QItemSelection &)
|
||||
{
|
||||
@@ -1301,10 +1365,10 @@ QSize MacroTreeDelegate::sizeHint(const QStyleOptionViewItem &option,
|
||||
QWidget *item = tree->indexWidget(index);
|
||||
|
||||
if (!item) {
|
||||
return (QSize(0, 0));
|
||||
return QStyledItemDelegate::sizeHint(option, index);
|
||||
}
|
||||
|
||||
return (QSize(option.widget->minimumWidth(), item->height()));
|
||||
return QSize(item->sizeHint());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -91,6 +91,8 @@ private:
|
||||
void MoveItemAfter(const std::shared_ptr<Macro> &item,
|
||||
const std::shared_ptr<Macro> &after);
|
||||
void Add(std::shared_ptr<Macro> item);
|
||||
void MoveToBeginningOfGroup(std::shared_ptr<Macro> item,
|
||||
std::shared_ptr<Macro>);
|
||||
void Remove(std::shared_ptr<Macro> item);
|
||||
std::shared_ptr<Macro> Neighbor(const std::shared_ptr<Macro> &m,
|
||||
bool above) const;
|
||||
@@ -126,6 +128,8 @@ public:
|
||||
void Reset(std::deque<std::shared_ptr<Macro>> &, bool highlight);
|
||||
void Add(std::shared_ptr<Macro> item,
|
||||
std::shared_ptr<Macro> after = {}) const;
|
||||
void AddToGroup(std::shared_ptr<Macro> item,
|
||||
std::shared_ptr<Macro> group) const;
|
||||
void Remove(std::shared_ptr<Macro> item) const;
|
||||
void Up(std::shared_ptr<Macro> item) const;
|
||||
void Down(std::shared_ptr<Macro> item) const;
|
||||
@@ -135,10 +139,15 @@ public:
|
||||
bool GroupedItemsSelected() const;
|
||||
bool SingleItemSelected() const;
|
||||
bool SelectionEmpty() const;
|
||||
bool GroupsExist() const;
|
||||
void ExpandGroup(std::shared_ptr<Macro> item) const;
|
||||
void CollapseGroup(std::shared_ptr<Macro> item) const;
|
||||
|
||||
public slots:
|
||||
void GroupSelectedItems();
|
||||
void UngroupSelectedGroups();
|
||||
void ExpandAll();
|
||||
void CollapseAll();
|
||||
void SelectionChangedHelper(const QItemSelection &,
|
||||
const QItemSelection &);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "macro.hpp"
|
||||
#include "macro-action-factory.hpp"
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "macro-dock.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-settings.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "splitter-helpers.hpp"
|
||||
#include "sync-helpers.hpp"
|
||||
@@ -14,77 +14,26 @@
|
||||
#include <QAction>
|
||||
#include <QMainWindow>
|
||||
#include <unordered_map>
|
||||
#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 {
|
||||
|
||||
static std::deque<std::shared_ptr<Macro>> macros;
|
||||
|
||||
Macro::Macro(const std::string &name, const bool addHotkey,
|
||||
const bool shortCircuitEvaluation)
|
||||
Macro::Macro(const std::string &name) : _dockSettings(this)
|
||||
{
|
||||
SetName(name);
|
||||
if (addHotkey) {
|
||||
}
|
||||
|
||||
Macro::Macro(const std::string &name, const GlobalMacroSettings &settings)
|
||||
: Macro(name)
|
||||
{
|
||||
if (settings._newMacroRegisterHotkeys) {
|
||||
SetupHotkeys();
|
||||
}
|
||||
_registerHotkeys = addHotkey;
|
||||
_useShortCircuitEvaluation = shortCircuitEvaluation;
|
||||
_registerHotkeys = settings._newMacroRegisterHotkeys;
|
||||
_checkInParallel = settings._newMacroCheckInParallel;
|
||||
_useShortCircuitEvaluation =
|
||||
settings._newMacroUseShortCircuitEvaluation;
|
||||
}
|
||||
|
||||
Macro::~Macro()
|
||||
@@ -92,19 +41,14 @@ Macro::~Macro()
|
||||
_die = true;
|
||||
Stop();
|
||||
ClearHotkeys();
|
||||
|
||||
// Keep the dock widgets in case of shutdown so they can be restored by
|
||||
// OBS on startup
|
||||
if (!OBSIsShuttingDown()) {
|
||||
RemoveDock();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Macro>
|
||||
Macro::CreateGroup(const std::string &name,
|
||||
std::vector<std::shared_ptr<Macro>> &children)
|
||||
{
|
||||
auto group = std::make_shared<Macro>(name, false);
|
||||
auto group = std::make_shared<Macro>(name);
|
||||
group->_registerHotkeys = false;
|
||||
for (auto &c : children) {
|
||||
c->SetParent(group);
|
||||
}
|
||||
@@ -165,7 +109,10 @@ static bool checkCondition(const std::shared_ptr<MacroCondition> &condition)
|
||||
static constexpr auto perfLogThreshold = 300ms;
|
||||
|
||||
const auto startTime = std::chrono::high_resolution_clock::now();
|
||||
const bool conditionMatched = condition->CheckCondition();
|
||||
bool conditionMatched = false;
|
||||
condition->WithLock([&condition, &conditionMatched]() {
|
||||
conditionMatched = condition->CheckCondition();
|
||||
});
|
||||
const auto endTime = std::chrono::high_resolution_clock::now();
|
||||
const auto timeSpent = endTime - startTime;
|
||||
|
||||
@@ -244,19 +191,52 @@ bool Macro::CheckConditions(bool ignorePause)
|
||||
return false;
|
||||
}
|
||||
|
||||
_stop = false;
|
||||
_matched = false;
|
||||
for (auto &condition : _conditions) {
|
||||
if (!condition) {
|
||||
continue;
|
||||
}
|
||||
const auto checkConditionsTask =
|
||||
[this,
|
||||
ignorePause](const std::deque<std::shared_ptr<MacroCondition>>
|
||||
&conditions) {
|
||||
for (auto &condition : conditions) {
|
||||
if (!condition) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_paused && !ignorePause) {
|
||||
vblog(LOG_INFO, "Macro %s is paused", _name.c_str());
|
||||
if (_paused && !ignorePause) {
|
||||
vblog(LOG_INFO, "Macro %s is paused",
|
||||
_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
_matched = CheckConditionHelper(condition);
|
||||
}
|
||||
return _matched;
|
||||
};
|
||||
|
||||
if (CheckInParallel()) {
|
||||
if (!_conditionCheckFuture.valid()) {
|
||||
_stop = false;
|
||||
_matched = false;
|
||||
_conditionCheckFuture = std::async(
|
||||
std::launch::async,
|
||||
[this, checkConditionsTask]() {
|
||||
// Copy to avoid settings modifications
|
||||
// causing issues
|
||||
const auto conditionsCopy = _conditions;
|
||||
checkConditionsTask(conditionsCopy);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
_matched = CheckConditionHelper(condition);
|
||||
if (_conditionCheckFuture.wait_for(std::chrono::seconds(0)) !=
|
||||
std::future_status::ready) {
|
||||
vblog(LOG_INFO,
|
||||
"Macro %s still waiting for condition check result",
|
||||
_name.c_str());
|
||||
return false;
|
||||
}
|
||||
_conditionCheckFuture.get();
|
||||
} else {
|
||||
_stop = false;
|
||||
_matched = false;
|
||||
_matched = checkConditionsTask(_conditions);
|
||||
}
|
||||
|
||||
vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched);
|
||||
@@ -273,7 +253,9 @@ bool Macro::CheckConditions(bool ignorePause)
|
||||
|
||||
bool Macro::PerformActions(bool match, bool forceParallel, bool ignorePause)
|
||||
{
|
||||
if (!_done) {
|
||||
if (_actionRunFuture.valid() &&
|
||||
_actionRunFuture.wait_for(std::chrono::seconds(0)) !=
|
||||
std::future_status::ready) {
|
||||
vblog(LOG_INFO, "Macro %s already running", _name.c_str());
|
||||
|
||||
if (!_stopActionsIfNotDone) {
|
||||
@@ -291,14 +273,15 @@ bool Macro::PerformActions(bool match, bool forceParallel, bool ignorePause)
|
||||
: std::bind(&Macro::RunElseActions, this,
|
||||
std::placeholders::_1);
|
||||
_stop = false;
|
||||
_done = false;
|
||||
bool ret = true;
|
||||
if (_runInParallel || forceParallel) {
|
||||
if (_backgroundThread.joinable()) {
|
||||
_backgroundThread.join();
|
||||
if (_actionRunFuture.valid()) {
|
||||
_actionRunFuture.get();
|
||||
}
|
||||
_backgroundThread = std::thread(
|
||||
[this, runFunc, ignorePause] { runFunc(ignorePause); });
|
||||
_actionRunFuture = std::async(std::launch::async,
|
||||
[this, runFunc, ignorePause] {
|
||||
runFunc(ignorePause);
|
||||
});
|
||||
} else {
|
||||
ret = runFunc(ignorePause);
|
||||
}
|
||||
@@ -336,6 +319,13 @@ bool Macro::ConditionsShouldBeChecked() const
|
||||
|
||||
bool Macro::ShouldRunActions() const
|
||||
{
|
||||
if (CheckInParallel() && _conditionCheckFuture.valid()) {
|
||||
vblog(LOG_INFO,
|
||||
"%s not ready to perform actions as condition check is still running",
|
||||
_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool hasActionsToExecute =
|
||||
!_paused && (_matched || _elseActions.size() > 0) &&
|
||||
(!_performActionsOnChange || _conditionSateChanged);
|
||||
@@ -358,15 +348,9 @@ bool Macro::ShouldRunActions() const
|
||||
|
||||
void Macro::SetName(const std::string &name)
|
||||
{
|
||||
const bool nameChanged = _name == name;
|
||||
_name = name;
|
||||
|
||||
SetHotkeysDesc();
|
||||
|
||||
if (nameChanged) {
|
||||
_dockId = GenerateDockId();
|
||||
}
|
||||
EnableDock(_registerDock);
|
||||
_dockSettings.HandleMacroNameChange();
|
||||
}
|
||||
|
||||
void Macro::ResetTimers()
|
||||
@@ -393,9 +377,12 @@ bool Macro::RunActionsHelper(
|
||||
}
|
||||
if (action->Enabled()) {
|
||||
action->LogAction();
|
||||
bool actionResult = false;
|
||||
action->WithLock([&action, &actionResult]() {
|
||||
actionResult = action->PerformAction();
|
||||
});
|
||||
actionsExecutedSuccessfully =
|
||||
actionsExecutedSuccessfully &&
|
||||
action->PerformAction();
|
||||
actionsExecutedSuccessfully && actionResult;
|
||||
} else {
|
||||
vblog(LOG_INFO, "skipping disabled action %s",
|
||||
action->GetId().c_str());
|
||||
@@ -408,7 +395,6 @@ bool Macro::RunActionsHelper(
|
||||
action->EnableHighlight();
|
||||
}
|
||||
}
|
||||
_done = true;
|
||||
return actionsExecutedSuccessfully;
|
||||
}
|
||||
|
||||
@@ -508,9 +494,35 @@ void Macro::Stop()
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
if (_backgroundThread.joinable()) {
|
||||
_backgroundThread.join();
|
||||
if (_actionRunFuture.valid()) {
|
||||
_actionRunFuture.get();
|
||||
}
|
||||
if (_conditionCheckFuture.valid()) {
|
||||
_conditionCheckFuture.get();
|
||||
}
|
||||
}
|
||||
|
||||
void Macro::SetCheckInParallel(bool parallel)
|
||||
{
|
||||
_checkInParallel = parallel;
|
||||
_conditionCheckFuture = {};
|
||||
}
|
||||
|
||||
bool Macro::ParallelTasksCompleted() const
|
||||
{
|
||||
// A parallel action run might be triggered by RunInParallel() or the
|
||||
// "Run Macro" button, so checking just for RunInParallel() will not
|
||||
// suffice
|
||||
if (!CheckInParallel() && !_actionRunFuture.valid()) {
|
||||
return true;
|
||||
}
|
||||
if (_actionRunFuture.valid()) {
|
||||
return false;
|
||||
}
|
||||
if (CheckInParallel() && _conditionCheckFuture.valid()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
MacroInputVariables Macro::GetInputVariables() const
|
||||
@@ -523,7 +535,7 @@ void Macro::SetInputVariables(const MacroInputVariables &inputVariables)
|
||||
_inputVariables = inputVariables;
|
||||
}
|
||||
|
||||
std::vector<TempVariable> Macro::GetTempVars(MacroSegment *filter) const
|
||||
std::vector<TempVariable> Macro::GetTempVars(const MacroSegment *filter) const
|
||||
{
|
||||
std::vector<TempVariable> res;
|
||||
|
||||
@@ -551,7 +563,7 @@ std::vector<TempVariable> Macro::GetTempVars(MacroSegment *filter) const
|
||||
return ptr.get() == segment;
|
||||
}) != _conditions.end();
|
||||
};
|
||||
auto isAction = [this](MacroSegment *segment) -> bool {
|
||||
auto isAction = [this](const MacroSegment *segment) -> bool {
|
||||
return std::find_if(_actions.begin(), _actions.end(),
|
||||
[segment](
|
||||
const std::shared_ptr<MacroSegment>
|
||||
@@ -559,7 +571,7 @@ std::vector<TempVariable> Macro::GetTempVars(MacroSegment *filter) const
|
||||
return ptr.get() == segment;
|
||||
}) != _actions.end();
|
||||
};
|
||||
auto isElseAction = [this](MacroSegment *segment) -> bool {
|
||||
auto isElseAction = [this](const MacroSegment *segment) -> bool {
|
||||
return std::find_if(_elseActions.begin(), _elseActions.end(),
|
||||
[segment](
|
||||
const std::shared_ptr<MacroSegment>
|
||||
@@ -648,16 +660,31 @@ std::deque<std::shared_ptr<MacroCondition>> &Macro::Conditions()
|
||||
return _conditions;
|
||||
}
|
||||
|
||||
const std::deque<std::shared_ptr<MacroCondition>> &Macro::Conditions() const
|
||||
{
|
||||
return _conditions;
|
||||
}
|
||||
|
||||
std::deque<std::shared_ptr<MacroAction>> &Macro::Actions()
|
||||
{
|
||||
return _actions;
|
||||
}
|
||||
|
||||
const std::deque<std::shared_ptr<MacroAction>> &Macro::Actions() const
|
||||
{
|
||||
return _actions;
|
||||
}
|
||||
|
||||
std::deque<std::shared_ptr<MacroAction>> &Macro::ElseActions()
|
||||
{
|
||||
return _elseActions;
|
||||
}
|
||||
|
||||
const std::deque<std::shared_ptr<MacroAction>> &Macro::ElseActions() const
|
||||
{
|
||||
return _elseActions;
|
||||
}
|
||||
|
||||
static void updateIndicesHelper(std::deque<std::shared_ptr<MacroSegment>> &list)
|
||||
{
|
||||
int idx = 0;
|
||||
@@ -712,6 +739,7 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const
|
||||
static_cast<int>(_pauseSaveBehavior));
|
||||
obs_data_set_bool(obj, "pause", _paused);
|
||||
obs_data_set_bool(obj, "parallel", _runInParallel);
|
||||
obs_data_set_bool(obj, "checkConditionsInParallel", _checkInParallel);
|
||||
obs_data_set_bool(obj, "onChange", _performActionsOnChange);
|
||||
obs_data_set_bool(obj, "skipExecOnStart", _skipExecOnStart);
|
||||
obs_data_set_bool(obj, "stopActionsIfNotDone", _stopActionsIfNotDone);
|
||||
@@ -721,7 +749,7 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const
|
||||
_useCustomConditionCheckInterval);
|
||||
_customConditionCheckInterval.Save(obj, "customConditionCheckInterval");
|
||||
|
||||
SaveDockSettings(obj, saveForCopy);
|
||||
_dockSettings.Save(obj, saveForCopy);
|
||||
|
||||
SaveSplitterPos(_actionConditionSplitterPosition, obj,
|
||||
"macroActionConditionSplitterPosition");
|
||||
@@ -797,6 +825,7 @@ bool Macro::Load(obs_data_t *obj)
|
||||
break;
|
||||
}
|
||||
_runInParallel = obs_data_get_bool(obj, "parallel");
|
||||
_checkInParallel = obs_data_get_bool(obj, "checkConditionsInParallel");
|
||||
_performActionsOnChange = obs_data_get_bool(obj, "onChange");
|
||||
_skipExecOnStart = obs_data_get_bool(obj, "skipExecOnStart");
|
||||
_stopActionsIfNotDone = obs_data_get_bool(obj, "stopActionsIfNotDone");
|
||||
@@ -806,7 +835,7 @@ bool Macro::Load(obs_data_t *obj)
|
||||
obs_data_get_bool(obj, "useCustomConditionCheckInterval");
|
||||
_customConditionCheckInterval.Load(obj, "customConditionCheckInterval");
|
||||
|
||||
LoadDockSettings(obj);
|
||||
_dockSettings.Load(obj);
|
||||
|
||||
LoadSplitterPos(_actionConditionSplitterPosition, obj,
|
||||
"macroActionConditionSplitterPosition");
|
||||
@@ -840,9 +869,12 @@ bool Macro::Load(obs_data_t *obj)
|
||||
auto newEntry = MacroConditionFactory::Create(id, this);
|
||||
if (newEntry) {
|
||||
_conditions.emplace_back(newEntry);
|
||||
auto c = _conditions.back().get();
|
||||
c->Load(arrayObj);
|
||||
c->ValidateLogicSelection(root, Name().c_str());
|
||||
auto condition = _conditions.back().get();
|
||||
condition->WithLock([&]() {
|
||||
condition->Load(arrayObj);
|
||||
condition->ValidateLogicSelection(
|
||||
root, Name().c_str());
|
||||
});
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"discarding condition entry with unknown id (%s) for macro %s",
|
||||
@@ -855,12 +887,15 @@ bool Macro::Load(obs_data_t *obj)
|
||||
OBSDataArrayAutoRelease actions = obs_data_get_array(obj, "actions");
|
||||
count = obs_data_array_count(actions);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
OBSDataAutoRelease array_obj = obs_data_array_item(actions, i);
|
||||
std::string id = obs_data_get_string(array_obj, "id");
|
||||
OBSDataAutoRelease arrayObj = obs_data_array_item(actions, i);
|
||||
std::string id = obs_data_get_string(arrayObj, "id");
|
||||
auto newEntry = MacroActionFactory::Create(id, this);
|
||||
if (newEntry) {
|
||||
_actions.emplace_back(newEntry);
|
||||
_actions.back()->Load(array_obj);
|
||||
auto action = _actions.back().get();
|
||||
action->WithLock([action, &arrayObj]() {
|
||||
action->Load(arrayObj);
|
||||
});
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"discarding action entry with unknown id (%s) for macro %s",
|
||||
@@ -873,13 +908,16 @@ bool Macro::Load(obs_data_t *obj)
|
||||
obs_data_get_array(obj, "elseActions");
|
||||
count = obs_data_array_count(elseActions);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
OBSDataAutoRelease array_obj =
|
||||
OBSDataAutoRelease arrayObj =
|
||||
obs_data_array_item(elseActions, i);
|
||||
std::string id = obs_data_get_string(array_obj, "id");
|
||||
std::string id = obs_data_get_string(arrayObj, "id");
|
||||
auto newEntry = MacroActionFactory::Create(id, this);
|
||||
if (newEntry) {
|
||||
_elseActions.emplace_back(newEntry);
|
||||
_elseActions.back()->Load(array_obj);
|
||||
auto action = _elseActions.back().get();
|
||||
action->WithLock([action, &arrayObj]() {
|
||||
action->Load(arrayObj);
|
||||
});
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"discarding elseAction entry with unknown id (%s) for macro %s",
|
||||
@@ -896,13 +934,13 @@ bool Macro::Load(obs_data_t *obj)
|
||||
bool Macro::PostLoad()
|
||||
{
|
||||
for (auto &c : _conditions) {
|
||||
c->PostLoad();
|
||||
c->WithLock([c]() { c->PostLoad(); });
|
||||
}
|
||||
for (auto &a : _actions) {
|
||||
a->PostLoad();
|
||||
a->WithLock([a]() { a->PostLoad(); });
|
||||
}
|
||||
for (auto &a : _elseActions) {
|
||||
a->PostLoad();
|
||||
a->WithLock([a]() { a->PostLoad(); });
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -987,224 +1025,6 @@ bool Macro::PauseHotkeysEnabled() const
|
||||
return _registerHotkeys;
|
||||
}
|
||||
|
||||
void Macro::SaveDockSettings(obs_data_t *obj, bool saveForCopy) const
|
||||
{
|
||||
auto dockSettings = obs_data_create();
|
||||
obs_data_set_bool(dockSettings, "register", _registerDock);
|
||||
obs_data_set_bool(dockSettings, "hasRunButton", _dockHasRunButton);
|
||||
obs_data_set_bool(dockSettings, "hasPauseButton", _dockHasPauseButton);
|
||||
obs_data_set_bool(dockSettings, "hasStatusLabel", _dockHasStatusLabel);
|
||||
obs_data_set_bool(dockSettings, "highlightIfConditionsTrue",
|
||||
_dockHighlight);
|
||||
_runButtonText.Save(dockSettings, "runButtonText");
|
||||
_pauseButtonText.Save(dockSettings, "pauseButtonText");
|
||||
_unpauseButtonText.Save(dockSettings, "unpauseButtonText");
|
||||
_conditionsTrueStatusText.Save(dockSettings,
|
||||
"conditionsTrueStatusText");
|
||||
_conditionsFalseStatusText.Save(dockSettings,
|
||||
"conditionsFalseStatusText");
|
||||
if (saveForCopy) {
|
||||
auto uuid = GenerateDockId();
|
||||
obs_data_set_string(dockSettings, "dockId", uuid.c_str());
|
||||
|
||||
} else {
|
||||
obs_data_set_string(dockSettings, "dockId", _dockId.c_str());
|
||||
}
|
||||
obs_data_set_int(dockSettings, "version", 1);
|
||||
obs_data_set_obj(obj, "dockSettings", dockSettings);
|
||||
obs_data_release(dockSettings);
|
||||
}
|
||||
|
||||
void Macro::LoadDockSettings(obs_data_t *obj)
|
||||
{
|
||||
auto dockSettings = obs_data_get_obj(obj, "dockSettings");
|
||||
if (!dockSettings) {
|
||||
// TODO: Remove this fallback
|
||||
_dockHasRunButton = obs_data_get_bool(obj, "dockHasRunButton");
|
||||
_dockHasPauseButton =
|
||||
obs_data_get_bool(obj, "dockHasPauseButton");
|
||||
EnableDock(obs_data_get_bool(obj, "registerDock"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obs_data_has_user_value(dockSettings, "version")) {
|
||||
_dockId = std::string("ADVSS-") + _name;
|
||||
} else {
|
||||
_dockId = obs_data_get_string(dockSettings, "dockId");
|
||||
}
|
||||
|
||||
const bool dockEnabled = obs_data_get_bool(dockSettings, "register");
|
||||
|
||||
// TODO: remove these default settings in a future version
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "runButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.run"));
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "pauseButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.pause"));
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "unpauseButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.unpause"));
|
||||
_runButtonText.Load(dockSettings, "runButtonText");
|
||||
_pauseButtonText.Load(dockSettings, "pauseButtonText");
|
||||
_unpauseButtonText.Load(dockSettings, "unpauseButtonText");
|
||||
_conditionsTrueStatusText.Load(dockSettings,
|
||||
"conditionsTrueStatusText");
|
||||
_conditionsFalseStatusText.Load(dockSettings,
|
||||
"conditionsFalseStatusText");
|
||||
if (dockEnabled) {
|
||||
_dockHasRunButton =
|
||||
obs_data_get_bool(dockSettings, "hasRunButton");
|
||||
_dockHasPauseButton =
|
||||
obs_data_get_bool(dockSettings, "hasPauseButton");
|
||||
_dockHasStatusLabel =
|
||||
obs_data_get_bool(dockSettings, "hasStatusLabel");
|
||||
_dockHighlight = obs_data_get_bool(dockSettings,
|
||||
"highlightIfConditionsTrue");
|
||||
}
|
||||
EnableDock(dockEnabled);
|
||||
obs_data_release(dockSettings);
|
||||
}
|
||||
|
||||
void Macro::EnableDock(bool value)
|
||||
{
|
||||
// Reset dock regardless
|
||||
RemoveDock();
|
||||
|
||||
if (!value) {
|
||||
_registerDock = value;
|
||||
return;
|
||||
}
|
||||
|
||||
_dock = new MacroDock(GetWeakMacroByName(_name.c_str()), _runButtonText,
|
||||
_pauseButtonText, _unpauseButtonText,
|
||||
_conditionsTrueStatusText,
|
||||
_conditionsFalseStatusText, _dockHighlight);
|
||||
|
||||
if (!obs_frontend_add_dock_by_id(_dockId.c_str(), _name.c_str(),
|
||||
_dock)) {
|
||||
blog(LOG_INFO, "failed to add macro dock for macro %s",
|
||||
_name.c_str());
|
||||
_dock->deleteLater();
|
||||
_dock = nullptr;
|
||||
_registerDock = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_registerDock = value;
|
||||
}
|
||||
|
||||
void Macro::SetDockHasRunButton(bool value)
|
||||
{
|
||||
_dockHasRunButton = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->ShowRunButton(value);
|
||||
}
|
||||
|
||||
void Macro::SetDockHasPauseButton(bool value)
|
||||
{
|
||||
_dockHasPauseButton = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->ShowPauseButton(value);
|
||||
}
|
||||
|
||||
void Macro::SetDockHasStatusLabel(bool value)
|
||||
{
|
||||
_dockHasStatusLabel = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->ShowStatusLabel(value);
|
||||
}
|
||||
|
||||
void Macro::SetHighlightEnable(bool value)
|
||||
{
|
||||
_dockHighlight = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->EnableHighlight(value);
|
||||
}
|
||||
|
||||
void Macro::SetRunButtonText(const std::string &text)
|
||||
{
|
||||
_runButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetRunButtonText(text);
|
||||
}
|
||||
|
||||
void Macro::SetPauseButtonText(const std::string &text)
|
||||
{
|
||||
_pauseButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetPauseButtonText(text);
|
||||
}
|
||||
|
||||
void Macro::SetUnpauseButtonText(const std::string &text)
|
||||
{
|
||||
_unpauseButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetUnpauseButtonText(text);
|
||||
}
|
||||
|
||||
void Macro::SetConditionsTrueStatusText(const std::string &text)
|
||||
{
|
||||
_conditionsTrueStatusText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetConditionsTrueText(text);
|
||||
}
|
||||
|
||||
StringVariable Macro::ConditionsTrueStatusText() const
|
||||
{
|
||||
return _conditionsTrueStatusText;
|
||||
}
|
||||
|
||||
void Macro::SetConditionsFalseStatusText(const std::string &text)
|
||||
{
|
||||
_conditionsFalseStatusText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetConditionsFalseText(text);
|
||||
}
|
||||
|
||||
StringVariable Macro::ConditionsFalseStatusText() const
|
||||
{
|
||||
return _conditionsFalseStatusText;
|
||||
}
|
||||
|
||||
void Macro::RemoveDock()
|
||||
{
|
||||
obs_frontend_remove_dock(_dockId.c_str());
|
||||
_dock = nullptr;
|
||||
}
|
||||
|
||||
std::string Macro::GenerateDockId()
|
||||
{
|
||||
#if LIBOBS_API_VER > MAKE_SEMANTIC_VERSION(30, 0, 0)
|
||||
auto uuid = os_generate_uuid();
|
||||
auto id = std::string("advss-macro-dock-") + std::string(uuid);
|
||||
bfree(uuid);
|
||||
return id;
|
||||
|
||||
#else
|
||||
static std::atomic_int16_t idCounter = 0;
|
||||
return std::to_string(++idCounter);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void pauseCB(void *data, obs_hotkey_id, obs_hotkey_t *, bool pressed)
|
||||
{
|
||||
if (pressed) {
|
||||
@@ -1468,6 +1288,14 @@ std::weak_ptr<Macro> GetWeakMacroByName(const char *name)
|
||||
void InvalidateMacroTempVarValues()
|
||||
{
|
||||
for (const auto &m : macros) {
|
||||
// Do not invalidate the temp vars set during condition checks
|
||||
// or action executions running in parallel to the "main" macro
|
||||
// loop, as otherwise access to the information stored in those
|
||||
// variables might get lost while those checks or actions are
|
||||
// still ongoing.
|
||||
if (!m->ParallelTasksCompleted()) {
|
||||
continue;
|
||||
}
|
||||
m->InvalidateTempVarValues();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
#pragma once
|
||||
#include "macro-action.hpp"
|
||||
#include "macro-condition.hpp"
|
||||
#include "macro-dock-settings.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-input.hpp"
|
||||
#include "macro-ref.hpp"
|
||||
#include "variable-string.hpp"
|
||||
#include "temp-variable.hpp"
|
||||
|
||||
#include <future>
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <string>
|
||||
@@ -19,7 +21,7 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MacroDock;
|
||||
class GlobalMacroSettings;
|
||||
|
||||
class Macro {
|
||||
using TimePoint = std::chrono::high_resolution_clock::time_point;
|
||||
@@ -27,8 +29,8 @@ class Macro {
|
||||
public:
|
||||
enum class PauseStateSaveBehavior { PERSIST, PAUSE, UNPAUSE };
|
||||
|
||||
Macro(const std::string &name = "", const bool addHotkey = false,
|
||||
const bool shortCircuitEvaluation = false);
|
||||
Macro(const std::string &name = "");
|
||||
Macro(const std::string &name, const GlobalMacroSettings &settings);
|
||||
~Macro();
|
||||
|
||||
std::string Name() const { return _name; }
|
||||
@@ -77,21 +79,27 @@ public:
|
||||
void AddHelperThread(std::thread &&);
|
||||
void SetRunInParallel(bool parallel) { _runInParallel = parallel; }
|
||||
bool RunInParallel() const { return _runInParallel; }
|
||||
bool CheckInParallel() const { return _checkInParallel; }
|
||||
void SetCheckInParallel(bool parallel);
|
||||
bool ParallelTasksCompleted() const;
|
||||
|
||||
// Input variables
|
||||
MacroInputVariables GetInputVariables() const;
|
||||
void SetInputVariables(const MacroInputVariables &);
|
||||
|
||||
// Temporary variable helpers
|
||||
std::vector<TempVariable> GetTempVars(MacroSegment *filter) const;
|
||||
std::vector<TempVariable> GetTempVars(const MacroSegment *filter) const;
|
||||
std::optional<const TempVariable>
|
||||
GetTempVar(const MacroSegment *, const std::string &id) const;
|
||||
void InvalidateTempVarValues() const;
|
||||
|
||||
// Macro segments
|
||||
std::deque<std::shared_ptr<MacroCondition>> &Conditions();
|
||||
const std::deque<std::shared_ptr<MacroCondition>> &Conditions() const;
|
||||
std::deque<std::shared_ptr<MacroAction>> &Actions();
|
||||
const std::deque<std::shared_ptr<MacroAction>> &Actions() const;
|
||||
std::deque<std::shared_ptr<MacroAction>> &ElseActions();
|
||||
const std::deque<std::shared_ptr<MacroAction>> &ElseActions() const;
|
||||
void UpdateActionIndices();
|
||||
void UpdateElseActionIndices();
|
||||
void UpdateConditionIndices();
|
||||
@@ -139,26 +147,7 @@ public:
|
||||
bool PauseHotkeysEnabled() const;
|
||||
|
||||
// Docks
|
||||
void EnableDock(bool);
|
||||
bool DockEnabled() const { return _registerDock; }
|
||||
void SetDockHasRunButton(bool value);
|
||||
bool DockHasRunButton() const { return _dockHasRunButton; }
|
||||
void SetDockHasPauseButton(bool value);
|
||||
bool DockHasPauseButton() const { return _dockHasPauseButton; }
|
||||
void SetDockHasStatusLabel(bool value);
|
||||
bool DockHasStatusLabel() const { return _dockHasStatusLabel; }
|
||||
void SetHighlightEnable(bool value);
|
||||
bool DockHighlightEnabled() const { return _dockHighlight; }
|
||||
StringVariable RunButtonText() const { return _runButtonText; }
|
||||
void SetRunButtonText(const std::string &text);
|
||||
StringVariable PauseButtonText() const { return _pauseButtonText; }
|
||||
void SetPauseButtonText(const std::string &text);
|
||||
StringVariable UnpauseButtonText() const { return _unpauseButtonText; }
|
||||
void SetUnpauseButtonText(const std::string &text);
|
||||
void SetConditionsTrueStatusText(const std::string &text);
|
||||
StringVariable ConditionsTrueStatusText() const;
|
||||
void SetConditionsFalseStatusText(const std::string &text);
|
||||
StringVariable ConditionsFalseStatusText() const;
|
||||
MacroDockSettings &GetDockSettings() { return _dockSettings; }
|
||||
|
||||
private:
|
||||
void SetupHotkeys();
|
||||
@@ -174,19 +163,13 @@ private:
|
||||
bool RunActions(bool ignorePause);
|
||||
bool RunElseActions(bool ignorePause);
|
||||
|
||||
void SaveDockSettings(obs_data_t *obj, bool saveForCopy) const;
|
||||
void LoadDockSettings(obs_data_t *obj);
|
||||
void RemoveDock();
|
||||
static std::string GenerateDockId();
|
||||
|
||||
std::string _name = "";
|
||||
bool _die = false;
|
||||
bool _stop = false;
|
||||
bool _done = true;
|
||||
std::future<void> _actionRunFuture;
|
||||
TimePoint _lastCheckTime{};
|
||||
TimePoint _lastUnpauseTime{};
|
||||
TimePoint _lastExecutionTime{};
|
||||
std::thread _backgroundThread;
|
||||
std::vector<std::thread> _helperThreads;
|
||||
|
||||
std::deque<std::shared_ptr<MacroCondition>> _conditions;
|
||||
@@ -204,7 +187,9 @@ private:
|
||||
bool _conditionSateChanged = false;
|
||||
|
||||
bool _runInParallel = false;
|
||||
bool _checkInParallel = false;
|
||||
bool _matched = false;
|
||||
std::future<void> _conditionCheckFuture;
|
||||
bool _lastMatched = false;
|
||||
bool _performActionsOnChange = true;
|
||||
bool _skipExecOnStart = false;
|
||||
@@ -227,23 +212,7 @@ private:
|
||||
QList<int> _actionConditionSplitterPosition;
|
||||
QList<int> _elseActionSplitterPosition;
|
||||
|
||||
bool _registerDock = false;
|
||||
bool _dockHasRunButton = true;
|
||||
bool _dockHasPauseButton = true;
|
||||
bool _dockHasStatusLabel = false;
|
||||
bool _dockHighlight = false;
|
||||
StringVariable _runButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.run");
|
||||
StringVariable _pauseButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.pause");
|
||||
StringVariable _unpauseButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.unpause");
|
||||
StringVariable _conditionsTrueStatusText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.true");
|
||||
StringVariable _conditionsFalseStatusText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.false");
|
||||
MacroDock *_dock = nullptr;
|
||||
std::string _dockId = GenerateDockId();
|
||||
MacroDockSettings _dockSettings;
|
||||
};
|
||||
|
||||
void LoadMacros(obs_data_t *obj);
|
||||
|
||||
@@ -44,11 +44,6 @@ void SwitcherData::Prune()
|
||||
}
|
||||
}
|
||||
|
||||
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) {
|
||||
switchIfNotMatching = NoMatchBehavior::NO_SWITCH;
|
||||
nonMatchingScene = nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < randomSwitches.size(); i++) {
|
||||
RandomSwitch &s = randomSwitches[i];
|
||||
if (!s.valid()) {
|
||||
@@ -168,31 +163,6 @@ void SwitcherData::SaveVersion(obs_data_t *obj,
|
||||
obs_data_set_string(obj, "version", currentVersion.c_str());
|
||||
}
|
||||
|
||||
void SwitcherData::RunPostLoadSteps()
|
||||
{
|
||||
for (const auto &func : postLoadSteps) {
|
||||
func();
|
||||
}
|
||||
postLoadSteps.clear();
|
||||
}
|
||||
|
||||
void SwitcherData::AddSaveStep(std::function<void(obs_data_t *)> function)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
saveSteps.emplace_back(function);
|
||||
}
|
||||
|
||||
void SwitcherData::AddLoadStep(std::function<void(obs_data_t *)> function)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
loadSteps.emplace_back(function);
|
||||
}
|
||||
|
||||
void SwitcherData::AddPostLoadStep(std::function<void()> function)
|
||||
{
|
||||
postLoadSteps.emplace_back(function);
|
||||
}
|
||||
|
||||
static void startHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
|
||||
{
|
||||
if (pressed) {
|
||||
@@ -255,6 +225,16 @@ static void removeMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
}
|
||||
}
|
||||
|
||||
static void addNewMacroHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
|
||||
bool pressed)
|
||||
{
|
||||
if (pressed && SettingsWindowIsOpened()) {
|
||||
QMetaObject::invokeMethod(GetSettingsWindow(),
|
||||
"on_macroAdd_clicked",
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
static void registerHotkeys()
|
||||
{
|
||||
switcher->startHotkey = obs_hotkey_register_frontend(
|
||||
@@ -270,19 +250,21 @@ static void registerHotkeys()
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey"),
|
||||
startStopToggleHotkeyFunc, NULL);
|
||||
switcher->newMacroHotkey = obs_hotkey_register_frontend(
|
||||
"newMacroSwitcherHotkey",
|
||||
obs_module_text("AdvSceneSwitcher.hotkey.macro.new"),
|
||||
addNewMacroHotkeyFunc, NULL);
|
||||
switcher->upMacroSegment = obs_hotkey_register_frontend(
|
||||
"upMacroSegmentSwitcherHotkey",
|
||||
obs_module_text("AdvSceneSwitcher.hotkey.upMacroSegmentHotkey"),
|
||||
obs_module_text("AdvSceneSwitcher.hotkey.macro.segment.up"),
|
||||
upMacroSegmentHotkeyFunc, NULL);
|
||||
switcher->downMacroSegment = obs_hotkey_register_frontend(
|
||||
"downMacroSegmentSwitcherHotkey",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.hotkey.downMacroSegmentHotkey"),
|
||||
obs_module_text("AdvSceneSwitcher.hotkey.macro.segment.down"),
|
||||
downMacroSegmentHotkeyFunc, NULL);
|
||||
switcher->removeMacroSegment = obs_hotkey_register_frontend(
|
||||
"removeMacroSegmentSwitcherHotkey",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey"),
|
||||
obs_module_text("AdvSceneSwitcher.hotkey.macro.segment.remove"),
|
||||
removeMacroSegmentHotkeyFunc, NULL);
|
||||
|
||||
switcher->hotkeysRegistered = true;
|
||||
@@ -300,6 +282,7 @@ void SwitcherData::SaveHotkeys(obs_data_t *obj)
|
||||
saveHotkey(obj, startHotkey, "startHotkey");
|
||||
saveHotkey(obj, stopHotkey, "stopHotkey");
|
||||
saveHotkey(obj, toggleHotkey, "toggleHotkey");
|
||||
saveHotkey(obj, newMacroHotkey, "newMacroHotkey");
|
||||
saveHotkey(obj, upMacroSegment, "upMacroSegmentHotkey");
|
||||
saveHotkey(obj, downMacroSegment, "downMacroSegmentHotkey");
|
||||
saveHotkey(obj, removeMacroSegment, "removeMacroSegmentHotkey");
|
||||
@@ -312,14 +295,31 @@ static void loadHotkey(obs_data_t *obj, obs_hotkey_id id, const char *name)
|
||||
obs_data_array_release(a);
|
||||
}
|
||||
|
||||
static void setDefaultHotkeyBinding(obs_data_t *data, const char *name,
|
||||
const char *value)
|
||||
{
|
||||
OBSDataAutoRelease hotkeyData = obs_data_create_from_json(value);
|
||||
OBSDataArrayAutoRelease hotkeyArray = obs_data_array_create();
|
||||
obs_data_array_push_back(hotkeyArray, hotkeyData);
|
||||
obs_data_set_default_array(data, name, hotkeyArray);
|
||||
}
|
||||
|
||||
void SwitcherData::LoadHotkeys(obs_data_t *obj)
|
||||
{
|
||||
if (!hotkeysRegistered) {
|
||||
registerHotkeys();
|
||||
}
|
||||
|
||||
setDefaultHotkeyBinding(obj, "newMacroHotkey",
|
||||
"{"
|
||||
"\"control\": true,"
|
||||
"\"key\": \"OBS_KEY_N\""
|
||||
"}");
|
||||
|
||||
loadHotkey(obj, startHotkey, "startHotkey");
|
||||
loadHotkey(obj, stopHotkey, "stopHotkey");
|
||||
loadHotkey(obj, toggleHotkey, "toggleHotkey");
|
||||
loadHotkey(obj, newMacroHotkey, "newMacroHotkey");
|
||||
loadHotkey(obj, upMacroSegment, "upMacroSegmentHotkey");
|
||||
loadHotkey(obj, downMacroSegment, "downMacroSegmentHotkey");
|
||||
loadHotkey(obj, removeMacroSegment, "removeMacroSegmentHotkey");
|
||||
|
||||
@@ -14,10 +14,12 @@
|
||||
#include "switch-sequence.hpp"
|
||||
#include "switch-video.hpp"
|
||||
|
||||
#include "macro-settings.hpp"
|
||||
#include "duration-control.hpp"
|
||||
#include "priority-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "priority-helper.hpp"
|
||||
#include "regex-config.hpp"
|
||||
#include "scene-selection.hpp"
|
||||
#include "variable-string.hpp"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <vector>
|
||||
@@ -57,15 +59,12 @@ public:
|
||||
bool AnySceneTransitionStarted();
|
||||
|
||||
void SetPreconditions();
|
||||
void AddSaveStep(std::function<void(obs_data_t *)>);
|
||||
void AddLoadStep(std::function<void(obs_data_t *)>);
|
||||
void AddPostLoadStep(std::function<void()>);
|
||||
void RunPostLoadSteps();
|
||||
bool CheckForMatch(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||
int &linger, bool &setPreviousSceneAsMatch,
|
||||
bool ¯oMatch);
|
||||
void CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition, int &sleep);
|
||||
void CheckAutoStart();
|
||||
|
||||
/* --- Start of saving / loading section --- */
|
||||
|
||||
@@ -95,13 +94,9 @@ public:
|
||||
bool stop = false;
|
||||
std::condition_variable cv;
|
||||
|
||||
std::vector<std::function<void(obs_data_t *)>> saveSteps;
|
||||
std::vector<std::function<void(obs_data_t *)>> loadSteps;
|
||||
std::vector<std::function<void()>> postLoadSteps;
|
||||
|
||||
bool firstBoot = true;
|
||||
bool transitionActive = false;
|
||||
bool sceneColletionStop = false;
|
||||
bool sceneCollectionStop = false;
|
||||
bool obsIsShuttingDown = false;
|
||||
bool firstInterval = true;
|
||||
bool firstIntervalAfterStop = true;
|
||||
@@ -114,7 +109,7 @@ public:
|
||||
/* --- Start of General tab section --- */
|
||||
|
||||
int interval = default_interval;
|
||||
OBSWeakSource nonMatchingScene;
|
||||
SceneSelection nonMatchingScene;
|
||||
NoMatchBehavior switchIfNotMatching = NoMatchBehavior::NO_SWITCH;
|
||||
Duration noMatchDelay;
|
||||
enum class StartupBehavior { PERSIST = 0, START = 1, STOP = 2 };
|
||||
@@ -126,15 +121,16 @@ public:
|
||||
RECORINDG_OR_STREAMING
|
||||
};
|
||||
AutoStart autoStartEvent = AutoStart::NEVER;
|
||||
bool useAutoStartScene = false;
|
||||
SceneSelection autoStartScene;
|
||||
StringVariable autoStartSceneName;
|
||||
RegexConfig autoStartSceneRegex;
|
||||
bool enableCooldown = false;
|
||||
Duration cooldown;
|
||||
bool showSystemTrayNotifications = false;
|
||||
bool transitionOverrideOverride = false;
|
||||
bool adjustActiveTransitionType = true;
|
||||
|
||||
enum class LogLevel { DEFAULT, LOG_MACRO, LOG_ACTION, VERBOSE };
|
||||
LogLevel logLevel = LogLevel::DEFAULT;
|
||||
|
||||
/* --- End of General tab section --- */
|
||||
|
||||
std::string lastTitle;
|
||||
@@ -152,6 +148,7 @@ public:
|
||||
obs_hotkey_id startHotkey = OBS_INVALID_HOTKEY_ID;
|
||||
obs_hotkey_id stopHotkey = OBS_INVALID_HOTKEY_ID;
|
||||
obs_hotkey_id toggleHotkey = OBS_INVALID_HOTKEY_ID;
|
||||
obs_hotkey_id newMacroHotkey = OBS_INVALID_HOTKEY_ID;
|
||||
obs_hotkey_id upMacroSegment = OBS_INVALID_HOTKEY_ID;
|
||||
obs_hotkey_id downMacroSegment = OBS_INVALID_HOTKEY_ID;
|
||||
obs_hotkey_id removeMacroSegment = OBS_INVALID_HOTKEY_ID;
|
||||
@@ -166,6 +163,7 @@ public:
|
||||
bool warnPluginLoadFailure = true;
|
||||
bool disableHints = false;
|
||||
bool disableFilterComboboxFilter = false;
|
||||
bool disableMacroWidgetCache = false;
|
||||
bool hideLegacyTabs = true;
|
||||
bool saveWindowGeo = false;
|
||||
QPoint windowPos = {};
|
||||
|
||||
296
lib/utils/canvas-helpers.cpp
Normal file
296
lib/utils/canvas-helpers.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
#include "canvas-helpers.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "scene-group.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "selection-helpers.hpp"
|
||||
#include "source-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "variable.hpp"
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
#include <QLayout>
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
Q_DECLARE_METATYPE(advss::OBSWeakCanvas);
|
||||
#else
|
||||
Q_DECLARE_METATYPE(OBSWeakCanvas);
|
||||
#endif
|
||||
|
||||
namespace advss {
|
||||
|
||||
void CanvasSelection::Populate()
|
||||
{
|
||||
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
static const auto enumCanvases = [](void *listPtr,
|
||||
obs_canvas_t *canvas) -> bool {
|
||||
auto list = static_cast<FilterComboBox *>(listPtr);
|
||||
OBSWeakCanvas weakCanvas = obs_canvas_get_weak_canvas(canvas);
|
||||
obs_weak_canvas_release(weakCanvas);
|
||||
QVariant variant;
|
||||
variant.setValue(weakCanvas);
|
||||
list->addItem(obs_canvas_get_name(canvas), variant);
|
||||
return true;
|
||||
};
|
||||
obs_enum_canvases(enumCanvases, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
CanvasSelection::CanvasSelection(QWidget *parent)
|
||||
: FilterComboBox(parent,
|
||||
obs_module_text("AdvSceneSwitcher.selectScene"))
|
||||
{
|
||||
setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
|
||||
Populate();
|
||||
|
||||
connect(this, &FilterComboBox::currentIndexChanged, this,
|
||||
[this]() { emit CanvasChanged(GetCanvas()); });
|
||||
}
|
||||
|
||||
void CanvasSelection::SetCanvas(const OBSWeakCanvas &canvas)
|
||||
{
|
||||
QVariant variant;
|
||||
variant.setValue(canvas);
|
||||
setCurrentIndex(findData(variant));
|
||||
}
|
||||
|
||||
OBSWeakCanvas CanvasSelection::GetCanvas()
|
||||
{
|
||||
return itemData(currentIndex()).value<OBSWeakCanvas>();
|
||||
}
|
||||
|
||||
int GetCanvasCount()
|
||||
{
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
return 1;
|
||||
#else
|
||||
static const auto enumCanvases = [](void *countPtr,
|
||||
obs_canvas_t *canvas) -> bool {
|
||||
auto count = static_cast<int *>(countPtr);
|
||||
(*count)++;
|
||||
return true;
|
||||
};
|
||||
int count = 0;
|
||||
obs_enum_canvases(enumCanvases, &count);
|
||||
return count;
|
||||
#endif
|
||||
}
|
||||
|
||||
OBSWeakCanvas GetWeakCanvasByName(const char *name)
|
||||
{
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
return OBSWeakCanvas();
|
||||
#else
|
||||
struct Data {
|
||||
OBSWeakCanvas canvas;
|
||||
const std::string name;
|
||||
};
|
||||
|
||||
static const auto enumCanvases = [](void *dataPtr,
|
||||
obs_canvas_t *canvas) -> bool {
|
||||
auto data = static_cast<Data *>(dataPtr);
|
||||
if (data->name != obs_canvas_get_name(canvas)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
data->canvas = obs_canvas_get_weak_canvas(canvas);
|
||||
obs_weak_canvas_release(data->canvas);
|
||||
return false;
|
||||
};
|
||||
Data data{nullptr, name};
|
||||
obs_enum_canvases(enumCanvases, &data);
|
||||
return data.canvas;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string GetWeakCanvasName(const OBSWeakCanvas &weakCanvas)
|
||||
{
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
return "Main";
|
||||
#else
|
||||
OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas);
|
||||
return canvas ? obs_canvas_get_name(canvas) : "";
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsMainCanvas(obs_weak_canvas_t *weakCanvas)
|
||||
{
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
return true;
|
||||
#else
|
||||
if (!weakCanvas) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas);
|
||||
OBSCanvasAutoRelease main = obs_get_main_canvas();
|
||||
return canvas == main;
|
||||
#endif
|
||||
}
|
||||
|
||||
OBSWeakSource GetActiveCanvasScene(const OBSWeakCanvas &weakCanvas)
|
||||
{
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
OBSCanvasAutoRelease canvas;
|
||||
#else
|
||||
if (!weakCanvas) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas);
|
||||
if (!canvas) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const auto enumCanvasScenes = [](void *scenePtr,
|
||||
obs_source_t *source) -> bool {
|
||||
auto scene = static_cast<OBSWeakSource *>(scenePtr);
|
||||
if (!obs_source_active(source)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*scene = obs_source_get_weak_source(source);
|
||||
obs_weak_source_release(*scene);
|
||||
return false;
|
||||
};
|
||||
|
||||
OBSWeakSource scene;
|
||||
obs_canvas_enum_scenes(canvas, enumCanvasScenes, &scene);
|
||||
return scene;
|
||||
}
|
||||
|
||||
OBSWeakSource GetSceneAtIndex(const OBSWeakCanvas &weakCanvas, int idx)
|
||||
{
|
||||
if (idx < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
OBSCanvas canvas;
|
||||
#else
|
||||
if (!weakCanvas) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OBSCanvas canvas = OBSGetStrongRef(weakCanvas);
|
||||
if (!canvas) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Data {
|
||||
const int idx;
|
||||
int currentIdx;
|
||||
OBSSource scene;
|
||||
};
|
||||
|
||||
static const auto enumCanvasScenes = [](void *dataPtr,
|
||||
obs_source_t *source) -> bool {
|
||||
auto data = static_cast<Data *>(dataPtr);
|
||||
if (data->idx != data->currentIdx) {
|
||||
data->currentIdx++;
|
||||
return true;
|
||||
}
|
||||
|
||||
data->scene = source;
|
||||
return false;
|
||||
};
|
||||
|
||||
Data data{idx, 0, nullptr};
|
||||
obs_canvas_enum_scenes(canvas, enumCanvasScenes, &data);
|
||||
|
||||
return OBSGetWeakRef(data.scene);
|
||||
}
|
||||
|
||||
int GetIndexOfScene(const OBSWeakCanvas &weakCanvas, const OBSWeakSource &scene)
|
||||
{
|
||||
if (!scene) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
OBSCanvas canvas;
|
||||
#else
|
||||
if (!weakCanvas) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
OBSCanvas canvas = OBSGetStrongRef(weakCanvas);
|
||||
if (!canvas) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Data {
|
||||
int idx;
|
||||
OBSSource scene;
|
||||
};
|
||||
|
||||
static const auto enumCanvasScenes = [](void *dataPtr,
|
||||
obs_source_t *source) -> bool {
|
||||
auto data = static_cast<Data *>(dataPtr);
|
||||
if (source == data->scene) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data->idx++;
|
||||
return true;
|
||||
};
|
||||
|
||||
Data data{0, OBSGetStrongRef(scene)};
|
||||
obs_canvas_enum_scenes(canvas, enumCanvasScenes, &data);
|
||||
|
||||
return data.idx;
|
||||
}
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
|
||||
obs_canvas_t *obs_canvas_get_ref(obs_canvas_t *)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void obs_canvas_release(obs_canvas_t *) {}
|
||||
|
||||
void obs_weak_canvas_addref(obs_weak_canvas_t *) {}
|
||||
|
||||
void obs_weak_canvas_release(obs_weak_canvas_t *) {}
|
||||
|
||||
OBSCanvas OBSGetStrongRef(obs_weak_object_t *weak)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
obs_weak_canvas_t *obs_canvas_get_weak_canvas(obs_canvas_t *)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
obs_canvas_t *obs_weak_canvas_get_canvas(obs_weak_canvas_t *)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void obs_canvas_enum_scenes(obs_canvas_t *,
|
||||
bool (*enum_proc)(void *, obs_source_t *),
|
||||
void *param)
|
||||
{
|
||||
obs_enum_scenes(enum_proc, param);
|
||||
}
|
||||
|
||||
OBSCanvas OBSGetStrongRef(obs_weak_canvas_t *)
|
||||
{
|
||||
return OBSCanvas();
|
||||
}
|
||||
|
||||
obs_canvas_t *obs_get_main_canvas()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace advss
|
||||
61
lib/utils/canvas-helpers.hpp
Normal file
61
lib/utils/canvas-helpers.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include "filter-combo-box.hpp"
|
||||
|
||||
#include <obs.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
class EXPORT obs_canvas_t {};
|
||||
class EXPORT obs_weak_canvas_t {};
|
||||
|
||||
EXPORT obs_canvas_t *obs_canvas_get_ref(obs_canvas_t *);
|
||||
EXPORT void obs_canvas_release(obs_canvas_t *);
|
||||
EXPORT void obs_weak_canvas_addref(obs_weak_canvas_t *);
|
||||
EXPORT void obs_weak_canvas_release(obs_weak_canvas_t *);
|
||||
|
||||
using OBSCanvas =
|
||||
OBSSafeRef<obs_canvas_t *, obs_canvas_get_ref, obs_canvas_release>;
|
||||
using OBSWeakCanvas = OBSRef<obs_weak_canvas_t *, obs_weak_canvas_addref,
|
||||
obs_weak_canvas_release>;
|
||||
using OBSCanvasAutoRelease =
|
||||
OBSRefAutoRelease<obs_canvas_t *, obs_canvas_release>;
|
||||
using OBSWeakCanvasAutoRelease =
|
||||
OBSRefAutoRelease<obs_weak_canvas_t *, obs_weak_canvas_release>;
|
||||
|
||||
EXPORT obs_weak_canvas_t *obs_canvas_get_weak_canvas(obs_canvas_t *);
|
||||
EXPORT obs_canvas_t *obs_weak_canvas_get_canvas(obs_weak_canvas_t *);
|
||||
EXPORT void obs_canvas_enum_scenes(obs_canvas_t *,
|
||||
bool (*enum_proc)(void *, obs_source_t *),
|
||||
void *param);
|
||||
EXPORT OBSCanvas OBSGetStrongRef(obs_weak_canvas_t *);
|
||||
EXPORT OBSWeakCanvas OBSGetWeakRef(obs_canvas_t *);
|
||||
EXPORT obs_canvas_t *obs_get_main_canvas();
|
||||
|
||||
#endif
|
||||
|
||||
EXPORT int GetCanvasCount();
|
||||
EXPORT OBSWeakCanvas GetWeakCanvasByName(const char *name);
|
||||
EXPORT std::string GetWeakCanvasName(const OBSWeakCanvas &canvas);
|
||||
EXPORT bool IsMainCanvas(obs_weak_canvas_t *canvas);
|
||||
EXPORT OBSWeakSource GetActiveCanvasScene(const OBSWeakCanvas &canvas);
|
||||
EXPORT OBSWeakSource GetSceneAtIndex(const OBSWeakCanvas &weakCanvas, int idx);
|
||||
EXPORT int GetIndexOfScene(const OBSWeakCanvas &weakCanvas,
|
||||
const OBSWeakSource &scene);
|
||||
|
||||
class CanvasSelection : public FilterComboBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EXPORT CanvasSelection(QWidget *parent);
|
||||
EXPORT void SetCanvas(const OBSWeakCanvas &);
|
||||
EXPORT OBSWeakCanvas GetCanvas();
|
||||
|
||||
signals:
|
||||
void CanvasChanged(const OBSWeakCanvas &);
|
||||
|
||||
private:
|
||||
void Populate();
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
class SliderIgnoreScroll : public QSlider {
|
||||
class ADVSS_EXPORT SliderIgnoreScroll : public QSlider {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
@@ -9,15 +9,14 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
class DurationSelection : public QWidget {
|
||||
class ADVSS_EXPORT DurationSelection : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
EXPORT DurationSelection(QWidget *parent = nullptr,
|
||||
bool showUnitSelection = true,
|
||||
double minValue = 0.0);
|
||||
EXPORT void SetDuration(const Duration &);
|
||||
DurationSelection(QWidget *parent = nullptr,
|
||||
bool showUnitSelection = true, double minValue = 0.0);
|
||||
void SetDuration(const Duration &);
|
||||
Duration GetDuration() const { return _current; }
|
||||
EXPORT QDoubleSpinBox *SpinBox() { return _duration->SpinBox(); }
|
||||
QDoubleSpinBox *SpinBox() { return _duration->SpinBox(); }
|
||||
|
||||
private slots:
|
||||
void _DurationChanged(const NumberVariable<double> &value);
|
||||
|
||||
@@ -62,6 +62,11 @@ void FilterComboBox::SetFilterBehaviourEnabled(bool value)
|
||||
FilterComboBox::_filteringEnabled = value;
|
||||
}
|
||||
|
||||
void FilterComboBox::SetAllowUnmatchedSelection(bool allow)
|
||||
{
|
||||
_allowUnmatchedSelection = allow;
|
||||
}
|
||||
|
||||
void FilterComboBox::setCurrentText(const QString &text)
|
||||
{
|
||||
if (_filteringEnabled) {
|
||||
@@ -79,10 +84,25 @@ void FilterComboBox::setItemText(int index, const QString &text)
|
||||
}
|
||||
}
|
||||
|
||||
QSize FilterComboBox::sizeHint() const
|
||||
{
|
||||
QSize size = QComboBox::sizeHint();
|
||||
|
||||
if (!_filteringEnabled) {
|
||||
return QComboBox::sizeHint();
|
||||
}
|
||||
|
||||
QFontMetrics fm(font());
|
||||
int extra = fm.horizontalAdvance("X") * 2; // Add padding
|
||||
size.setWidth(size.width() + extra);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void FilterComboBox::focusOutEvent(QFocusEvent *event)
|
||||
{
|
||||
// Reset on invalid selection
|
||||
if (findText(currentText()) == -1) {
|
||||
if (!_allowUnmatchedSelection && findText(currentText()) == -1) {
|
||||
setCurrentIndex(-1);
|
||||
Emit(-1, "");
|
||||
}
|
||||
@@ -91,7 +111,7 @@ void FilterComboBox::focusOutEvent(QFocusEvent *event)
|
||||
_lastCompleterHighlightRow = -1;
|
||||
}
|
||||
|
||||
static int findXthOccurance(QComboBox *list, int count, const QString &value)
|
||||
static int findXthOccurrence(QComboBox *list, int count, const QString &value)
|
||||
{
|
||||
if (value.isEmpty() || count < 1) {
|
||||
return -1;
|
||||
@@ -116,7 +136,7 @@ void FilterComboBox::CompleterHighlightChanged(const QModelIndex &index)
|
||||
{
|
||||
_lastCompleterHighlightRow = index.row();
|
||||
const auto text = currentText();
|
||||
int idx = findXthOccurance(this, _lastCompleterHighlightRow, text);
|
||||
int idx = findXthOccurrence(this, _lastCompleterHighlightRow, text);
|
||||
if (idx == -1) {
|
||||
return;
|
||||
}
|
||||
@@ -128,7 +148,7 @@ void FilterComboBox::TextChanged(const QString &text)
|
||||
auto c = completer();
|
||||
const bool completerActive = c->completionCount() > 0;
|
||||
int count = completerActive ? _lastCompleterHighlightRow + 1 : 1;
|
||||
int idx = findXthOccurance(this, count, text);
|
||||
int idx = findXthOccurrence(this, count, text);
|
||||
if (idx == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -13,10 +13,13 @@ public:
|
||||
FilterComboBox(QWidget *parent = nullptr,
|
||||
const QString &placehodler = "");
|
||||
static void SetFilterBehaviourEnabled(bool);
|
||||
void SetAllowUnmatchedSelection(bool allow);
|
||||
|
||||
void setCurrentText(const QString &text);
|
||||
void setItemText(int index, const QString &text);
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
protected:
|
||||
void focusOutEvent(QFocusEvent *event) override;
|
||||
|
||||
@@ -27,6 +30,7 @@ private slots:
|
||||
private:
|
||||
void Emit(int index, const QString &text);
|
||||
|
||||
bool _allowUnmatchedSelection = false;
|
||||
int _lastEmittedIndex = -1;
|
||||
QString _lastEmittedText;
|
||||
|
||||
|
||||
102
lib/utils/json-helpers.cpp
Normal file
102
lib/utils/json-helpers.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "json-helpers.hpp"
|
||||
|
||||
#ifdef JSONPATH_SUPPORT
|
||||
#include <jsoncons/json.hpp>
|
||||
#include <jsoncons_ext/jsonpath/jsonpath.hpp>
|
||||
#endif
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <QJsonDocument>
|
||||
|
||||
namespace advss {
|
||||
|
||||
QString FormatJsonString(std::string s)
|
||||
{
|
||||
return FormatJsonString(QString::fromStdString(s));
|
||||
}
|
||||
|
||||
QString FormatJsonString(QString json)
|
||||
{
|
||||
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
|
||||
if (doc.isNull()) {
|
||||
return "";
|
||||
}
|
||||
return QString::fromUtf8(doc.toJson(QJsonDocument::Indented));
|
||||
}
|
||||
|
||||
bool MatchJson(const std::string &json1, const std::string &json2,
|
||||
const RegexConfig ®ex)
|
||||
{
|
||||
auto j1 = FormatJsonString(json1).toStdString();
|
||||
auto j2 = FormatJsonString(json2).toStdString();
|
||||
|
||||
if (j1.empty()) {
|
||||
j1 = json1;
|
||||
}
|
||||
if (j2.empty()) {
|
||||
j2 = json2;
|
||||
}
|
||||
|
||||
if (regex.Enabled()) {
|
||||
return regex.Matches(j1, j2);
|
||||
}
|
||||
return j1 == j2;
|
||||
}
|
||||
|
||||
std::optional<std::string> GetJsonField(const std::string &jsonStr,
|
||||
const std::string &fieldToExtract)
|
||||
{
|
||||
try {
|
||||
nlohmann::json json = nlohmann::json::parse(jsonStr);
|
||||
auto it = json.find(fieldToExtract);
|
||||
if (it == json.end()) {
|
||||
return {};
|
||||
}
|
||||
if (it->is_string()) {
|
||||
return it->get<std::string>();
|
||||
}
|
||||
return it->dump();
|
||||
} catch (const nlohmann::json::exception &) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<std::string> QueryJson(const std::string &jsonStr,
|
||||
const std::string &query)
|
||||
{
|
||||
#ifdef JSONPATH_SUPPORT
|
||||
try {
|
||||
auto json = jsoncons::json::parse(jsonStr);
|
||||
auto result = jsoncons::jsonpath::json_query(json, query);
|
||||
return result.as_string();
|
||||
} catch (const jsoncons::json_exception &) {
|
||||
return {};
|
||||
} catch (const jsoncons::json_errc &) {
|
||||
return {};
|
||||
}
|
||||
#else
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
std::optional<std::string> AccessJsonArrayIndex(const std::string &jsonStr,
|
||||
const int index)
|
||||
{
|
||||
try {
|
||||
nlohmann::json json = nlohmann::json::parse(jsonStr);
|
||||
if (!json.is_array() || index >= (int)json.size() ||
|
||||
index < 0) {
|
||||
return {};
|
||||
}
|
||||
auto result = json.at(index);
|
||||
if (result.is_string()) {
|
||||
return result.get<std::string>();
|
||||
}
|
||||
return result.dump();
|
||||
} catch (const nlohmann::json::exception &) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
21
lib/utils/json-helpers.hpp
Normal file
21
lib/utils/json-helpers.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include "export-symbol-helper.hpp"
|
||||
#include "regex-config.hpp"
|
||||
|
||||
#include <QString>
|
||||
#include <string>
|
||||
|
||||
namespace advss {
|
||||
|
||||
EXPORT QString FormatJsonString(std::string);
|
||||
EXPORT QString FormatJsonString(QString);
|
||||
EXPORT bool MatchJson(const std::string &json1, const std::string &json2,
|
||||
const RegexConfig ®ex);
|
||||
EXPORT std::optional<std::string> GetJsonField(const std::string &json,
|
||||
const std::string &id);
|
||||
EXPORT std::optional<std::string> QueryJson(const std::string &json,
|
||||
const std::string &query);
|
||||
EXPORT std::optional<std::string> AccessJsonArrayIndex(const std::string &json,
|
||||
const int index);
|
||||
|
||||
} // namespace advss
|
||||
@@ -12,6 +12,7 @@ class ADVSS_EXPORT ListEditor : public QWidget {
|
||||
|
||||
public:
|
||||
ListEditor(QWidget *parent = nullptr, bool reorder = true);
|
||||
int count() const { return _list->count(); };
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *);
|
||||
|
||||
@@ -1,26 +1,97 @@
|
||||
#include "log-helper.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <obs-data.h>
|
||||
#include <QComboBox>
|
||||
#include <string>
|
||||
|
||||
namespace advss {
|
||||
|
||||
static LogLevel logLevel = LogLevel::DEFAULT;
|
||||
|
||||
bool VerboseLoggingEnabled()
|
||||
{
|
||||
return GetSwitcher() &&
|
||||
GetSwitcher()->logLevel == SwitcherData::LogLevel::VERBOSE;
|
||||
return logLevel == LogLevel::VERBOSE;
|
||||
}
|
||||
|
||||
bool ActionLoggingEnabled()
|
||||
{
|
||||
return GetSwitcher() &&
|
||||
(GetSwitcher()->logLevel == SwitcherData::LogLevel::LOG_ACTION ||
|
||||
VerboseLoggingEnabled());
|
||||
return logLevel == LogLevel::LOG_ACTION || VerboseLoggingEnabled();
|
||||
}
|
||||
|
||||
bool MacroLoggingEnabled()
|
||||
{
|
||||
return GetSwitcher() &&
|
||||
(GetSwitcher()->logLevel == SwitcherData::LogLevel::LOG_MACRO ||
|
||||
ActionLoggingEnabled());
|
||||
return logLevel == LogLevel::LOG_MACRO || ActionLoggingEnabled();
|
||||
}
|
||||
|
||||
bool LoggingEnabled()
|
||||
{
|
||||
return logLevel != LogLevel::DISABLE;
|
||||
}
|
||||
|
||||
void SetLogLevel(LogLevel newLogLevel)
|
||||
{
|
||||
logLevel = newLogLevel;
|
||||
}
|
||||
|
||||
LogLevel GetLogLevel()
|
||||
{
|
||||
return logLevel;
|
||||
}
|
||||
|
||||
void SaveLogLevel(void *data)
|
||||
{
|
||||
auto obj = static_cast<obs_data_t *>(data);
|
||||
obs_data_set_int(obj, "logLevel", static_cast<int>(logLevel));
|
||||
obs_data_set_int(obj, "logLevelVersion", 1);
|
||||
}
|
||||
|
||||
void LoadLogLevel(void *data)
|
||||
{
|
||||
auto obj = static_cast<obs_data_t *>(data);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PopulateLogLevelSelection(void *sel)
|
||||
{
|
||||
auto selection = static_cast<QComboBox *>(sel);
|
||||
static const std::map<LogLevel, std::string> logLevels = {
|
||||
{LogLevel::DISABLE,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.logLevel.disable"},
|
||||
{LogLevel::DEFAULT,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default"},
|
||||
{LogLevel::LOG_MACRO,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logMacro"},
|
||||
{LogLevel::LOG_ACTION,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction"},
|
||||
{LogLevel::VERBOSE,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose"},
|
||||
};
|
||||
|
||||
selection->clear();
|
||||
for (const auto &[value, name] : logLevels) {
|
||||
selection->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -12,7 +12,13 @@ namespace advss {
|
||||
#else
|
||||
|
||||
// Print log with "[adv-ss] " prefix
|
||||
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
|
||||
#define blog(level, msg, ...) \
|
||||
do { \
|
||||
if (LoggingEnabled()) { \
|
||||
blog(level, "[adv-ss] " msg, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// Print log with "[adv-ss] " if log level is set to "verbose"
|
||||
#define vblog(level, msg, ...) \
|
||||
do { \
|
||||
@@ -43,5 +49,15 @@ EXPORT bool VerboseLoggingEnabled();
|
||||
EXPORT bool ActionLoggingEnabled();
|
||||
// Returns true if log level is set to "macro", "action" or "verbose"
|
||||
EXPORT bool MacroLoggingEnabled();
|
||||
// Returns true if logging is enabled and false otherwise
|
||||
EXPORT bool LoggingEnabled();
|
||||
|
||||
enum class LogLevel { DISABLE = -1, DEFAULT, LOG_MACRO, LOG_ACTION, VERBOSE };
|
||||
|
||||
void SetLogLevel(LogLevel);
|
||||
LogLevel GetLogLevel();
|
||||
void SaveLogLevel(void *data);
|
||||
void LoadLogLevel(void *data);
|
||||
void PopulateLogLevelSelection(void *);
|
||||
|
||||
} // 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