mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 04:36:21 -05:00
Compare commits
156 Commits
1.28.0-bet
...
1.30.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93703c80bc | ||
|
|
d7951a7179 | ||
|
|
d42a3b584a | ||
|
|
becd1bd02a | ||
|
|
30422aecf3 | ||
|
|
c567e6ef7f | ||
|
|
1ca61f3ed4 | ||
|
|
1affe9dce3 | ||
|
|
406e3c1855 | ||
|
|
c05dd40c4c | ||
|
|
9a86ecac42 | ||
|
|
721a786e79 | ||
|
|
32d29875ed | ||
|
|
0e5f56b562 | ||
|
|
5490fabf92 | ||
|
|
5e3ab19940 | ||
|
|
1c94a1ab44 | ||
|
|
34baa56134 | ||
|
|
5ce4171773 | ||
|
|
c281c6db83 | ||
|
|
c43439ee64 | ||
|
|
a84731b8fe | ||
|
|
61fbff5821 | ||
|
|
1381654fed | ||
|
|
9805601c07 | ||
|
|
fcf57ee031 | ||
|
|
ba3e87a761 | ||
|
|
3dd3f576c3 | ||
|
|
7403a18e96 | ||
|
|
56494480ba | ||
|
|
cdc5d16e95 | ||
|
|
27aed79305 | ||
|
|
7ec95e33eb | ||
|
|
98260b25a1 | ||
|
|
45b37de9f7 | ||
|
|
027a3e9074 | ||
|
|
cab50e0922 | ||
|
|
88514e209d | ||
|
|
4ed7f13b72 | ||
|
|
0fb11ac274 | ||
|
|
942933290a | ||
|
|
f13beaead2 | ||
|
|
13dba6527d | ||
|
|
b78a6510a9 | ||
|
|
6c22f438b6 | ||
|
|
347abe6c84 | ||
|
|
230863adda | ||
|
|
f59478fac7 | ||
|
|
8adac79cd8 | ||
|
|
ea93c44db7 | ||
|
|
9e20b341d8 | ||
|
|
232cbb06f6 | ||
|
|
e9d57a0f4a | ||
|
|
9633a61a65 | ||
|
|
0643b250e1 | ||
|
|
b52738881f | ||
|
|
470d5ba3d7 | ||
|
|
8326e72047 | ||
|
|
12ab4d8cf9 | ||
|
|
295ec9eb81 | ||
|
|
4c5dbd4b7c | ||
|
|
5568f92ad0 | ||
|
|
7c4c0056ce | ||
|
|
d2b4b1cc07 | ||
|
|
a3ca22d238 | ||
|
|
c73542a3cc | ||
|
|
70bbc7cdac | ||
|
|
d892298995 | ||
|
|
0fe31432be | ||
|
|
aaa0113ccb | ||
|
|
b908954b46 | ||
|
|
b0eede8a85 | ||
|
|
aa87911b71 | ||
|
|
1b05019acc | ||
|
|
78a5a2629d | ||
|
|
634270a978 | ||
|
|
78ba22e1e4 | ||
|
|
aba5737a60 | ||
|
|
4315f7f621 | ||
|
|
53c535962f | ||
|
|
1e718b78c7 | ||
|
|
b1d2156228 | ||
|
|
9c3c953c6b | ||
|
|
ae74f68db7 | ||
|
|
213f1bba36 | ||
|
|
5a2cb0bd68 | ||
|
|
23b461828b | ||
|
|
9944a1b03b | ||
|
|
eaad4d1bbd | ||
|
|
17d9b73b9a | ||
|
|
d6185a6099 | ||
|
|
41c06b9edb | ||
|
|
d8807077da | ||
|
|
34e125f82d | ||
|
|
d670b6d07e | ||
|
|
7b0f985f18 | ||
|
|
212be923f6 | ||
|
|
88fcb57e9f | ||
|
|
9b609c118f | ||
|
|
37c398d37a | ||
|
|
a51b7f6b13 | ||
|
|
808fd84b83 | ||
|
|
57bcea15f5 | ||
|
|
4e51b56b9b | ||
|
|
ef5cf41d34 | ||
|
|
911e79ea6a | ||
|
|
d586177de0 | ||
|
|
202c36646c | ||
|
|
ab5102f5ca | ||
|
|
e612fb99f6 | ||
|
|
691e77a69a | ||
|
|
930118c61f | ||
|
|
1e05f2f2ce | ||
|
|
ae25b4d023 | ||
|
|
af055a12a1 | ||
|
|
7de28eedd3 | ||
|
|
8dfe81f522 | ||
|
|
a1d8ae291d | ||
|
|
eb6989527d | ||
|
|
2986a5dd96 | ||
|
|
816ee9b244 | ||
|
|
51b53bf948 | ||
|
|
2c5121ee94 | ||
|
|
6a58684854 | ||
|
|
0b622fdbed | ||
|
|
3bce8e075f | ||
|
|
f598d84ea1 | ||
|
|
d7a244e80e | ||
|
|
408002e96a | ||
|
|
50da3d3210 | ||
|
|
9e13067769 | ||
|
|
821e768e76 | ||
|
|
4d2179448b | ||
|
|
40d9002470 | ||
|
|
7f1e310ca6 | ||
|
|
66d02f4683 | ||
|
|
0aae1b9978 | ||
|
|
db50822b05 | ||
|
|
63a545b293 | ||
|
|
bc0497d2c9 | ||
|
|
37226a3a4c | ||
|
|
9f15fbe47c | ||
|
|
0ee6feb529 | ||
|
|
3b82b55090 | ||
|
|
071c3309c2 | ||
|
|
ee7ee7a846 | ||
|
|
d10300bd4b | ||
|
|
e262672876 | ||
|
|
392e775c7b | ||
|
|
f641c20564 | ||
|
|
39327be88e | ||
|
|
ed0963799c | ||
|
|
f9e73a2b8f | ||
|
|
dfaa704b71 | ||
|
|
d54edddde4 | ||
|
|
37cc289204 |
@@ -6,15 +6,6 @@
|
||||
"autosort": true
|
||||
},
|
||||
"additional_commands": {
|
||||
"find_qt": {
|
||||
"flags": [],
|
||||
"kwargs": {
|
||||
"COMPONENTS": "+",
|
||||
"COMPONENTS_WIN": "+",
|
||||
"COMPONENTS_MACOS": "+",
|
||||
"COMPONENTS_LINUX": "+"
|
||||
}
|
||||
},
|
||||
"set_target_properties_obs": {
|
||||
"pargs": 1,
|
||||
"flags": [],
|
||||
|
||||
1
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
1
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -20,6 +20,7 @@ body:
|
||||
- macOS 13
|
||||
- macOS 12
|
||||
- macOS 11
|
||||
- Ubuntu 24.04
|
||||
- Ubuntu 23.10
|
||||
- Ubuntu 22.04
|
||||
- Other
|
||||
|
||||
6
.github/scripts/.Aptfile
vendored
6
.github/scripts/.Aptfile
vendored
@@ -9,5 +9,7 @@ package 'libxtst-dev'
|
||||
package 'libxss-dev'
|
||||
package 'libopencv-dev'
|
||||
package 'libtesseract-dev'
|
||||
package 'libprocps-dev'
|
||||
package 'libusb-1.0-0-dev'
|
||||
package 'libproc2-dev'
|
||||
package 'libusb-1.0-0-dev'
|
||||
package 'libpaho-mqttpp-dev'
|
||||
package 'libpaho-mqtt-dev'
|
||||
34
.github/scripts/.build-deps.zsh
vendored
34
.github/scripts/.build-deps.zsh
vendored
@@ -478,14 +478,36 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
unset MACOSX_DEPLOYMENT_TARGET
|
||||
|
||||
popd
|
||||
|
||||
local mqtt_dir="${project_root}/deps/paho.mqtt.cpp"
|
||||
local mqtt_build_dir="${mqtt_dir}/build_${target##*-}"
|
||||
|
||||
local -a mqtt_cmake_args=(
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
|
||||
-DCMAKE_PREFIX_PATH="${advss_dep_path};${_plugin_deps}"
|
||||
-DCMAKE_INSTALL_PREFIX="${advss_dep_path}"
|
||||
-DPAHO_BUILD_SHARED=OFF
|
||||
-DPAHO_BUILD_STATIC=ON
|
||||
-DPAHO_WITH_MQTT_C=ON
|
||||
-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)
|
||||
# Hacky workaround to support libproc2 with Ubuntu 22 build environment
|
||||
local lsb_version=$(lsb_release -r | cut -f 2 || true)
|
||||
if [[ "${lsb_version}" == '22.04' ]] {
|
||||
sudo apt install ${project_root}/build-aux/CI/linux/ubuntu22/libproc2-0_4.0.2-3_amd64.deb
|
||||
sudo apt install ${project_root}/build-aux/CI/linux/ubuntu22/libproc2-dev_4.0.2-3_amd64.deb
|
||||
}
|
||||
# Nothing to do for now
|
||||
;;
|
||||
}
|
||||
}
|
||||
|
||||
31
.github/scripts/Build-Deps-Windows.ps1
vendored
31
.github/scripts/Build-Deps-Windows.ps1
vendored
@@ -219,6 +219,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
|
||||
|
||||
0
.github/test
vendored
0
.github/test
vendored
2
.github/workflows/build-debian.yml
vendored
2
.github/workflows/build-debian.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
# devscripts and libobs-dev are needed but they were already installed
|
||||
# from check_libobs_revision and install_frontend_header sections.
|
||||
sudo apt update
|
||||
sudo apt install cmake debhelper libcurl4-openssl-dev libxss-dev libxtst-dev qtbase5-dev libopencv-dev libprocps-dev
|
||||
sudo apt install build-essential cmake debhelper libcurl4-openssl-dev libxss-dev libxtst-dev qt6-base-dev libopencv-dev libproc2-dev
|
||||
- name: build
|
||||
run: |
|
||||
debuild --no-lintian --no-sign
|
||||
|
||||
13
.github/workflows/build-project.yaml
vendored
13
.github/workflows/build-project.yaml
vendored
@@ -10,7 +10,7 @@ env:
|
||||
jobs:
|
||||
check-event:
|
||||
name: Check GitHub Event Data 🔎
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
@@ -177,7 +177,7 @@ jobs:
|
||||
|
||||
ubuntu-build:
|
||||
name: Build for Ubuntu 🐧
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
needs: check-event
|
||||
defaults:
|
||||
run:
|
||||
@@ -210,6 +210,11 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-ccache-x86_64-
|
||||
|
||||
- name: Set up CMake 🏗️
|
||||
uses: jwlawson/actions-setup-cmake@v1.13
|
||||
with:
|
||||
cmake-version: '3.24.x'
|
||||
|
||||
- name: Set up Homebrew 🍺
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
|
||||
@@ -241,14 +246,14 @@ jobs:
|
||||
- name: Upload Artifacts 📡
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-22.04-x86_64-${{ needs.check-event.outputs.commitHash }}
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-24.04-x86_64-${{ needs.check-event.outputs.commitHash }}
|
||||
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*.*
|
||||
|
||||
- name: Upload debug symbol artifacts 🪲
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ fromJSON(needs.check-event.outputs.package) }}
|
||||
with:
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-22.04-x86_64-${{ needs.check-event.outputs.commitHash }}-dbgsym
|
||||
name: ${{ steps.setup.outputs.pluginName }}-${{ steps.setup.outputs.pluginVersion }}-ubuntu-24.04-x86_64-${{ needs.check-event.outputs.commitHash }}-dbgsym
|
||||
path: ${{ github.workspace }}/release/${{ steps.setup.outputs.pluginName }}-*-x86_64*-dbgsym.ddeb
|
||||
|
||||
windows-build:
|
||||
|
||||
4
.github/workflows/check-format.yaml
vendored
4
.github/workflows/check-format.yaml
vendored
@@ -3,7 +3,7 @@ on:
|
||||
workflow_call:
|
||||
jobs:
|
||||
clang-format:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
failCondition: error
|
||||
|
||||
cmake-format:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
|
||||
4
.github/workflows/push.yaml
vendored
4
.github/workflows/push.yaml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
create-release:
|
||||
name: Create Release 🛫
|
||||
if: github.ref_type == 'tag'
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-project
|
||||
defaults:
|
||||
run:
|
||||
@@ -77,7 +77,7 @@ jobs:
|
||||
variants=(
|
||||
'windows-x64;zip|exe'
|
||||
'macos-universal;tar.xz|pkg'
|
||||
'ubuntu-22.04-x86_64;tar.xz|deb|ddeb'
|
||||
'ubuntu-24.04-x86_64;tar.xz|deb|ddeb'
|
||||
'sources;tar.xz'
|
||||
)
|
||||
|
||||
|
||||
9
.gitmodules
vendored
9
.gitmodules
vendored
@@ -28,3 +28,12 @@
|
||||
[submodule "deps/libusb"]
|
||||
path = deps/libusb
|
||||
url = https://github.com/libusb/libusb.git
|
||||
[submodule "deps/date"]
|
||||
path = deps/date
|
||||
url = https://github.com/HowardHinnant/date.git
|
||||
[submodule "deps/jsoncons"]
|
||||
path = deps/jsoncons
|
||||
url = https://github.com/danielaparker/jsoncons.git
|
||||
[submodule "deps/paho.mqtt.cpp"]
|
||||
path = deps/paho.mqtt.cpp
|
||||
url = https://github.com/eclipse-paho/paho.mqtt.cpp.git
|
||||
|
||||
@@ -20,6 +20,12 @@ if(BUILD_OUT_OF_TREE)
|
||||
include(helpers)
|
||||
endif()
|
||||
|
||||
# OBS 31 no longer defines find_qt so check if we need to include it for in-tree
|
||||
# builds
|
||||
if(NOT COMMAND find_qt)
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/helpers_common.cmake")
|
||||
endif()
|
||||
|
||||
set(LIB_NAME "${PROJECT_NAME}-lib")
|
||||
add_library(${PROJECT_NAME} MODULE)
|
||||
add_library(${LIB_NAME} SHARED)
|
||||
@@ -27,6 +33,11 @@ add_library(${LIB_NAME} SHARED)
|
||||
include(cmake/common/get_git_revision_description.cmake)
|
||||
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
|
||||
git_describe(GIT_TAG)
|
||||
|
||||
if(${GIT_TAG} STREQUAL "GIT-NOTFOUND")
|
||||
set(GIT_TAG ${PROJECT_VERSION})
|
||||
endif()
|
||||
message(STATUS "${PROJECT_NAME} version: ${GIT_TAG}")
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/version.cpp.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/lib/version.cpp" @ONLY)
|
||||
|
||||
@@ -157,6 +168,8 @@ target_sources(
|
||||
lib/queue/action-queue.hpp
|
||||
lib/queue/action-queue-tab.cpp
|
||||
lib/queue/action-queue-tab.hpp
|
||||
lib/utils/auto-update-tooltip-label.cpp
|
||||
lib/utils/auto-update-tooltip-label.hpp
|
||||
lib/utils/backup.cpp
|
||||
lib/utils/backup.hpp
|
||||
lib/utils/condition-logic.cpp
|
||||
@@ -182,6 +195,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
|
||||
@@ -217,8 +232,6 @@ target_sources(
|
||||
lib/utils/resizing-text-edit.hpp
|
||||
lib/utils/resource-table.cpp
|
||||
lib/utils/resource-table.hpp
|
||||
lib/utils/resource-table-hotkey-handler.cpp
|
||||
lib/utils/resource-table-hotkey-handler.hpp
|
||||
lib/utils/scene-selection.cpp
|
||||
lib/utils/scene-selection.hpp
|
||||
lib/utils/scene-switch-helpers.cpp
|
||||
@@ -287,9 +300,16 @@ include(cmake/common/advss_helpers.cmake)
|
||||
setup_obs_lib_dependency(${LIB_NAME})
|
||||
setup_obs_lib_dependency(${PROJECT_NAME})
|
||||
|
||||
find_qt(COMPONENTS Widgets Core)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt::Core Qt::Widgets)
|
||||
target_link_libraries(${LIB_NAME} PRIVATE Qt::Core Qt::Widgets)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Core)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Core Qt6::Widgets)
|
||||
target_link_libraries(${LIB_NAME} PRIVATE Qt6::Core Qt6::Widgets)
|
||||
|
||||
# Ignore QCheckBox::stateChanged deprecation warning until minimum supported Qt
|
||||
# version is at least Qt 6.7, which introduces QCheckBox::checkStateChanged
|
||||
if(Qt6_VERSION VERSION_GREATER "6.0.0")
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE QT_NO_DEPRECATED_WARNINGS)
|
||||
endif()
|
||||
|
||||
target_compile_options(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE
|
||||
@@ -338,6 +358,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)
|
||||
@@ -405,7 +440,12 @@ else()
|
||||
set(PROCESS_CONDITION_SUPPORTED 1)
|
||||
endif()
|
||||
if(PROCPS2_INCLUDE_DIR)
|
||||
message(STATUS "${PROJECT_NAME} using libproc2")
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(libproc2 IMPORTED_TARGET libproc2<4.0.5 QUIET)
|
||||
if(libproc2_FOUND)
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_USE_INFO)
|
||||
endif()
|
||||
pkg_check_modules(libproc2 REQUIRED IMPORTED_TARGET libproc2)
|
||||
set(PROC_INCLUDE_DIR "${PROCPS2_INCLUDE_DIR}")
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_AVAILABLE)
|
||||
set(PROCESS_CONDITION_SUPPORTED 1)
|
||||
@@ -418,6 +458,9 @@ else()
|
||||
endif()
|
||||
target_include_directories(${LIB_NAME} PRIVATE "${PROC_INCLUDE_DIR}")
|
||||
target_sources(${LIB_NAME} PRIVATE lib/linux/advanced-scene-switcher-nix.cpp)
|
||||
|
||||
# Don't include irrelevant folders into sources archive
|
||||
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\.deps/.*")
|
||||
endif()
|
||||
|
||||
if(NOT OS_WINDOWS)
|
||||
|
||||
@@ -19,6 +19,8 @@ The **Snap** package manager offers an OBS Studio installation which is bundled
|
||||
sudo snap install obs-studio
|
||||
```
|
||||
|
||||
More information can be found [here](https://github.com/WarmUpTill/SceneSwitcher/wiki/Installation).
|
||||
|
||||
## Contributing
|
||||
|
||||
- If you wish to contribute code to the project, have a look at this [section](BUILDING.md) describing how to compile the plugin.
|
||||
|
||||
@@ -7,7 +7,7 @@ Build-Depends: cmake,
|
||||
libcurl4-openssl-dev,
|
||||
libobs-dev,
|
||||
libxtst-dev,
|
||||
qtbase5-dev,
|
||||
qt6-base-dev,
|
||||
libxss-dev,
|
||||
libopencv-dev
|
||||
Standards-Version: 4.6.0
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||
|
||||
export QT_SELECT = qt5
|
||||
export QT_SELECT = qt6
|
||||
|
||||
%:
|
||||
dh $@
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -283,8 +283,14 @@ endfunction()
|
||||
|
||||
function(setup_advss_plugin target)
|
||||
setup_obs_lib_dependency(${target})
|
||||
find_qt(COMPONENTS Widgets Core)
|
||||
target_link_libraries(${target} PRIVATE Qt::Core Qt::Widgets)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Core)
|
||||
target_link_libraries(${target} PRIVATE Qt6::Core Qt6::Widgets)
|
||||
|
||||
# Ignore QCheckBox::stateChanged deprecation warning until minimum supported
|
||||
# Qt version is at least Qt 6.7, which introduces QCheckBox::checkStateChanged
|
||||
if(Qt6_VERSION VERSION_GREATER "6.7.0")
|
||||
target_compile_definitions(${target} PRIVATE QT_NO_DEPRECATED_WARNINGS)
|
||||
endif()
|
||||
|
||||
set_target_properties(
|
||||
${target}
|
||||
|
||||
@@ -17,85 +17,6 @@ if(NOT QT_VERSION)
|
||||
set_property(CACHE QT_VERSION PROPERTY STRINGS AUTO 5 6)
|
||||
endif()
|
||||
|
||||
# find_qt: Macro to find best possible Qt version for use with the project:
|
||||
macro(find_qt)
|
||||
set(multiValueArgs COMPONENTS COMPONENTS_WIN COMPONENTS_MAC COMPONENTS_LINUX)
|
||||
cmake_parse_arguments(find_qt "" "${oneValueArgs}" "${multiValueArgs}"
|
||||
${ARGN})
|
||||
|
||||
# Do not use versionless targets in the first step to avoid Qt::Core being
|
||||
# clobbered by later opportunistic find_package runs
|
||||
set(QT_NO_CREATE_VERSIONLESS_TARGETS TRUE)
|
||||
|
||||
message(DEBUG "Start Qt version discovery...")
|
||||
# Loop until _QT_VERSION is set or FATAL_ERROR aborts script execution early
|
||||
while(NOT _QT_VERSION)
|
||||
message(DEBUG "QT_VERSION set to ${QT_VERSION}")
|
||||
if(QT_VERSION STREQUAL AUTO AND NOT qt_test_version)
|
||||
set(qt_test_version 6)
|
||||
elseif(NOT QT_VERSION STREQUAL AUTO)
|
||||
set(qt_test_version ${QT_VERSION})
|
||||
endif()
|
||||
message(DEBUG "Attempting to find Qt${qt_test_version}")
|
||||
|
||||
find_package(
|
||||
Qt${qt_test_version}
|
||||
COMPONENTS Core
|
||||
QUIET)
|
||||
|
||||
if(TARGET Qt${qt_test_version}::Core)
|
||||
set(_QT_VERSION
|
||||
${qt_test_version}
|
||||
CACHE INTERNAL "")
|
||||
message(STATUS "Qt version found: ${_QT_VERSION}")
|
||||
unset(qt_test_version)
|
||||
break()
|
||||
elseif(QT_VERSION STREQUAL AUTO)
|
||||
if(qt_test_version EQUAL 6)
|
||||
message(WARNING "Qt6 was not found, falling back to Qt5")
|
||||
set(qt_test_version 5)
|
||||
continue()
|
||||
endif()
|
||||
endif()
|
||||
message(FATAL_ERROR "Neither Qt6 nor Qt5 found.")
|
||||
endwhile()
|
||||
|
||||
# Enable versionless targets for the remaining Qt components
|
||||
set(QT_NO_CREATE_VERSIONLESS_TARGETS FALSE)
|
||||
|
||||
set(qt_components ${find_qt_COMPONENTS})
|
||||
if(OS_WINDOWS)
|
||||
list(APPEND qt_components ${find_qt_COMPONENTS_WIN})
|
||||
elseif(OS_MACOS)
|
||||
list(APPEND qt_components ${find_qt_COMPONENTS_MAC})
|
||||
else()
|
||||
list(APPEND qt_components ${find_qt_COMPONENTS_LINUX})
|
||||
endif()
|
||||
message(DEBUG "Trying to find Qt components ${qt_components}...")
|
||||
|
||||
find_package(Qt${_QT_VERSION} REQUIRED ${qt_components})
|
||||
|
||||
list(APPEND qt_components Core)
|
||||
|
||||
if("Gui" IN_LIST find_qt_COMPONENTS_LINUX)
|
||||
list(APPEND qt_components "GuiPrivate")
|
||||
endif()
|
||||
|
||||
# Check for versionless targets of each requested component and create if
|
||||
# necessary
|
||||
foreach(component IN LISTS qt_components)
|
||||
message(DEBUG "Checking for target Qt::${component}")
|
||||
if(NOT TARGET Qt::${component} AND TARGET Qt${_QT_VERSION}::${component})
|
||||
add_library(Qt::${component} INTERFACE IMPORTED)
|
||||
set_target_properties(
|
||||
Qt::${component} PROPERTIES INTERFACE_LINK_LIBRARIES
|
||||
Qt${_QT_VERSION}::${component})
|
||||
endif()
|
||||
set_property(TARGET Qt::${component} PROPERTY INTERFACE_COMPILE_FEATURES "")
|
||||
endforeach()
|
||||
|
||||
endmacro()
|
||||
|
||||
# check_uuid: Helper function to check for valid UUID
|
||||
function(check_uuid uuid_string return_value)
|
||||
set(valid_uuid TRUE)
|
||||
|
||||
@@ -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"
|
||||
@@ -212,7 +211,6 @@ AdvSceneSwitcher.condition.stream.state.start="Stream läuft"
|
||||
AdvSceneSwitcher.condition.stream.state.stop="Stream gestoppt"
|
||||
AdvSceneSwitcher.condition.stream.state.starting="Stream wird gestartet"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="Stream wird gestoppt"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
AdvSceneSwitcher.condition.record="Aufnahme"
|
||||
AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
|
||||
@@ -490,7 +488,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Nach unten verschieben"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="An erste Stelle verschieben"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="An letzte Stelle verschieben"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="An Position verschieben"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Auf{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Auf{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Szenenelement transformieren"
|
||||
AdvSceneSwitcher.action.sceneTransform.getTransform="Transformation erhalten"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="Auf{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}"
|
||||
@@ -527,7 +525,6 @@ AdvSceneSwitcher.action.screenshot.save.default="Standard"
|
||||
AdvSceneSwitcher.action.screenshot.save.custom="Benutzerdefiniert"
|
||||
AdvSceneSwitcher.action.screenshot.type.source="Quelle"
|
||||
AdvSceneSwitcher.action.screenshot.type.scene="Szene"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="OBS's Haupt-Ausgabe"
|
||||
AdvSceneSwitcher.action.screenshot.blackscreenNote="Quellen oder Szenen, die nicht immer gerendert werden, können dazu führen, dass einige Teile der Screenshots leer bleiben."
|
||||
AdvSceneSwitcher.action.screenshot.entry="Screenshot{{targetType}}{{sources}}{{scenes}}und speichere in{{saveType}}{{variables}}Pfad"
|
||||
AdvSceneSwitcher.action.profile="Profil"
|
||||
@@ -755,9 +752,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}}"
|
||||
|
||||
@@ -29,11 +29,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 +42,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 +53,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!"
|
||||
@@ -97,6 +98,7 @@ AdvSceneSwitcher.actionQueueTab.queueAddButton.tooltip="Add new action queue"
|
||||
AdvSceneSwitcher.actionQueueTab.queueRemoveButton.tooltip="Remove selected action queues"
|
||||
AdvSceneSwitcher.actionQueueTab.name.header="Name"
|
||||
AdvSceneSwitcher.actionQueueTab.size.header="Size"
|
||||
AdvSceneSwitcher.actionQueueTab.lastEmpty.header="Last empty"
|
||||
AdvSceneSwitcher.actionQueueTab.isRunning.header="Is running"
|
||||
AdvSceneSwitcher.actionQueueTab.runOnStartup.header="Run on startup"
|
||||
AdvSceneSwitcher.actionQueueTab.yes="Yes"
|
||||
@@ -131,6 +133,18 @@ 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"
|
||||
@@ -198,8 +212,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."
|
||||
@@ -307,7 +324,7 @@ AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="During transi
|
||||
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"
|
||||
@@ -376,6 +393,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"
|
||||
@@ -395,16 +419,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"
|
||||
@@ -418,7 +444,10 @@ AdvSceneSwitcher.condition.stream.state.stop="Stream stopped"
|
||||
AdvSceneSwitcher.condition.stream.state.starting="Stream starting"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="Stream stopping"
|
||||
AdvSceneSwitcher.condition.stream.state.keyFrameInterval="Keyframe interval equals"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
AdvSceneSwitcher.condition.stream.state.streamKey="Stream key is"
|
||||
AdvSceneSwitcher.condition.stream.state.service="Service name matches"
|
||||
AdvSceneSwitcher.condition.stream.service.tooltip="Current service name: %1"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}{{streamKey}}{{serviceName}}{{regex}}{{currentService}}"
|
||||
AdvSceneSwitcher.condition.record="Recording"
|
||||
AdvSceneSwitcher.condition.record.state.start="Recording running"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Recording paused"
|
||||
@@ -765,6 +794,13 @@ AdvSceneSwitcher.condition.streamDeck.checkData="Check data field"
|
||||
AdvSceneSwitcher.condition.streamDeck.startListen="Start listening"
|
||||
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}}"
|
||||
|
||||
# Macro Actions
|
||||
AdvSceneSwitcher.action.unknown="Unknown action"
|
||||
@@ -899,6 +935,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"
|
||||
@@ -956,7 +993,9 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Move down"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="Move to top"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Move to bottom"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Move to position"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="On{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.above="Move above"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.below="Move below"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="On{{scenes}}{{actions}}{{sources}}{{position}}{{sources2}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Scene item transform"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.manual="Set transform string"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.setSingleSetting="Set transform setting"
|
||||
@@ -1011,7 +1050,6 @@ AdvSceneSwitcher.action.screenshot.save.custom="Custom file path"
|
||||
AdvSceneSwitcher.action.screenshot.save.variable="Variable (base64 encoded PNG)"
|
||||
AdvSceneSwitcher.action.screenshot.type.source="Source"
|
||||
AdvSceneSwitcher.action.screenshot.type.scene="Scene"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="OBS's main output"
|
||||
AdvSceneSwitcher.action.screenshot.blackscreenNote="Sources or scenes, which are not always rendered, may result in some parts of screenshots to remain blank."
|
||||
AdvSceneSwitcher.action.screenshot.entry="Screenshot{{targetType}}{{sources}}{{scenes}}and save to{{saveType}}{{variables}}"
|
||||
AdvSceneSwitcher.action.profile="Profile"
|
||||
@@ -1040,21 +1078,35 @@ AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.request="Send{{api}}of typ
|
||||
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.event="Send{{api}}of type{{type}}to connected clients"
|
||||
AdvSceneSwitcher.action.websocket.entry.generic="Send{{api}}via{{connection}}"
|
||||
AdvSceneSwitcher.action.http="HTTP"
|
||||
AdvSceneSwitcher.action.http.legacy="HTTP (legacy)"
|
||||
AdvSceneSwitcher.action.http.setHeaders="Set headers"
|
||||
AdvSceneSwitcher.action.http.headers="Headers:"
|
||||
AdvSceneSwitcher.action.http.addHeader="Add header"
|
||||
AdvSceneSwitcher.action.http.addHeader.name="Header name"
|
||||
AdvSceneSwitcher.action.http.addHeader.value="Header value"
|
||||
AdvSceneSwitcher.action.http.setParams="Set parameters"
|
||||
AdvSceneSwitcher.action.http.params="Parameters:"
|
||||
AdvSceneSwitcher.action.http.addParam.name="Parameter name"
|
||||
AdvSceneSwitcher.action.http.addParam.value="Parameter value"
|
||||
AdvSceneSwitcher.action.http.body="Message body:"
|
||||
AdvSceneSwitcher.action.http.type.get="GET"
|
||||
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.contentType="Content type:{{contentType}}"
|
||||
AdvSceneSwitcher.action.http.layout.timeout="Timeout:{{timeout}}seconds"
|
||||
AdvSceneSwitcher.action.http.entry.line1="Send{{method}}to{{url}}"
|
||||
AdvSceneSwitcher.action.http.entry.line2="Timeout:{{timeout}}seconds"
|
||||
AdvSceneSwitcher.action.variable="Variable"
|
||||
AdvSceneSwitcher.action.variable.type.set="Set to fixed value"
|
||||
AdvSceneSwitcher.action.variable.type.set="Set to value"
|
||||
AdvSceneSwitcher.action.variable.type.append="Append"
|
||||
AdvSceneSwitcher.action.variable.type.appendVar="Append variable"
|
||||
AdvSceneSwitcher.action.variable.type.increment="Increment"
|
||||
AdvSceneSwitcher.action.variable.type.decrement="Decrement"
|
||||
AdvSceneSwitcher.action.variable.type.setActionValue="Set to action value"
|
||||
AdvSceneSwitcher.action.variable.type.setConditionValue="Set to condition value"
|
||||
AdvSceneSwitcher.action.variable.type.setActionValue="Set to action value (legacy)"
|
||||
AdvSceneSwitcher.action.variable.type.setConditionValue="Set to condition value (legacy)"
|
||||
AdvSceneSwitcher.action.variable.type.roundToInt="Round to nearest integer"
|
||||
AdvSceneSwitcher.action.variable.type.subString="Set to substring of current value"
|
||||
AdvSceneSwitcher.action.variable.type.findAndReplace="Find and replace in current value"
|
||||
@@ -1063,7 +1115,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"
|
||||
@@ -1072,6 +1127,7 @@ AdvSceneSwitcher.action.variable.type.truncateValue="Truncate current value"
|
||||
AdvSceneSwitcher.action.variable.type.swapValues="Swap variable values"
|
||||
AdvSceneSwitcher.action.variable.type.trim="Trim whitespace"
|
||||
AdvSceneSwitcher.action.variable.type.changeCase="Change case"
|
||||
AdvSceneSwitcher.action.variable.type.randomNumber="Generate random number"
|
||||
AdvSceneSwitcher.action.variable.case.type.lowerCase="lowercase"
|
||||
AdvSceneSwitcher.action.variable.case.type.upperCase="UPPERCASE"
|
||||
AdvSceneSwitcher.action.variable.case.type.capitalized="Capitalized"
|
||||
@@ -1086,19 +1142,23 @@ AdvSceneSwitcher.action.variable.findAndReplace.replace="Text to replace with"
|
||||
AdvSceneSwitcher.action.variable.findAndReplace.replace.tooltip="Using \1, \2, etc. to represent first, second, etc. capture groups is supported."
|
||||
AdvSceneSwitcher.action.variable.subString.begin="Beginning"
|
||||
AdvSceneSwitcher.action.variable.subString.all="All"
|
||||
AdvSceneSwitcher.action.variable.generateInteger="Only generate integers"
|
||||
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.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"
|
||||
AdvSceneSwitcher.action.projector.type.source="Source"
|
||||
AdvSceneSwitcher.action.projector.type.scene="Scene"
|
||||
AdvSceneSwitcher.action.projector.type.preview="Preview"
|
||||
@@ -1107,8 +1167,9 @@ AdvSceneSwitcher.action.projector.type.multiview="Multiview"
|
||||
AdvSceneSwitcher.action.projector.display="Display"
|
||||
AdvSceneSwitcher.action.projector.windowed="Windowed"
|
||||
AdvSceneSwitcher.action.projector.fullscreen="Fullscreen"
|
||||
AdvSceneSwitcher.action.projector.entry="Open{{windowTypes}}projector of{{types}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.projector.entry.monitor="on{{monitors}}"
|
||||
AdvSceneSwitcher.action.projector.entry.close="{{actions}}projector with name{{projectorWindowName}}{{regex}}"
|
||||
AdvSceneSwitcher.action.projector.entry.open.windowed="{{actions}}{{windowTypes}}projector of{{types}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.projector.entry.open.fullscreen="{{actions}}{{windowTypes}}projector of{{types}}{{scenes}}{{sources}}on{{monitors}}"
|
||||
AdvSceneSwitcher.action.midi="MIDI"
|
||||
AdvSceneSwitcher.action.midi.entry="Send message to{{device}}:"
|
||||
AdvSceneSwitcher.action.midi.entry.listen="Set MIDI message selection to messages incoming on{{listenDevices}}:{{listenButton}}"
|
||||
@@ -1128,10 +1189,15 @@ AdvSceneSwitcher.action.twitch.type.clip.create="Create stream clip"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.announcement.send="Send chat announcement"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Enable chat's emote-only mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Disable chat's emote-only mode"
|
||||
AdvSceneSwitcher.action.twitch.type.sendChatMessage="Send chat message"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Send chat message"
|
||||
AdvSceneSwitcher.action.twitch.type.user.getInfo="Get user information"
|
||||
AdvSceneSwitcher.action.twitch.type.reward.getInfo="Get channel points reward information"
|
||||
AdvSceneSwitcher.action.twitch.reward.toggleControl="Toggle reward name / variable selection control"
|
||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Cannot select category without selecting a Twitch account first!"
|
||||
AdvSceneSwitcher.action.twitch.entry.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="Using account{{account}}{{actions}}on{{channel}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="Using account{{account}}{{actions}}on{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.user.getInfo="Using account{{account}}{{actions}}for{{userInfoQueryType}}{{userLogin}}{{userId}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.reward.getInfo="Using account{{account}}{{actions}}for channel{{channel}}{{pointsReward}}{{rewardVariable}}{{toggleRewardSelection}}"
|
||||
AdvSceneSwitcher.action.twitch.title.title="Enter title"
|
||||
AdvSceneSwitcher.action.twitch.marker.description="Describe marker"
|
||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="Add a slight delay before capturing the clip"
|
||||
@@ -1141,6 +1207,8 @@ AdvSceneSwitcher.action.twitch.announcement.blue="Blue"
|
||||
AdvSceneSwitcher.action.twitch.announcement.green="Green"
|
||||
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.clipboard="Clipboard"
|
||||
AdvSceneSwitcher.action.clipboard.type.copy.text="Copy text"
|
||||
AdvSceneSwitcher.action.clipboard.type.copy.image="Copy image"
|
||||
@@ -1165,6 +1233,23 @@ 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.getCurrentValue="Get current value"
|
||||
AdvSceneSwitcher.action.obsSettings.layout="{{actions}}{{fpsType}}{{fpsIntValue}}{{fpsStringValue}}{{canvasSizeValue}}{{getCurrentValue}}"
|
||||
|
||||
# Hotkey
|
||||
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher"
|
||||
@@ -1173,9 +1258,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}}"
|
||||
@@ -1205,7 +1291,7 @@ AdvSceneSwitcher.validation.text.maxLength="Only %1 characters are allowed in th
|
||||
AdvSceneSwitcher.variable.select="--select variable--"
|
||||
AdvSceneSwitcher.variable.add="Add new variable"
|
||||
AdvSceneSwitcher.variable.configure="Configure variable settings"
|
||||
AdvSceneSwitcher.variable.invalid="Invalid varialbe selection"
|
||||
AdvSceneSwitcher.variable.invalid="Invalid variable selection"
|
||||
AdvSceneSwitcher.variable.name="Name:"
|
||||
AdvSceneSwitcher.variable.value="Current value:"
|
||||
AdvSceneSwitcher.variable.save="Save / load behavior"
|
||||
@@ -1321,6 +1407,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--"
|
||||
@@ -1372,6 +1487,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."
|
||||
@@ -1584,12 +1700,21 @@ AdvSceneSwitcher.tempVar.twitch.started_at.shoutoutReceived="Shoutout time"
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.shoutoutReceived.description="The UTC timestamp (in RFC3339 format) of when the moderator sent the Shoutout."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.id.reward="Reward ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.id.redemption="Redemption ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.reward="User ID redeeming the reward"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.reward="User login redeeming the reward"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.reward="User name redeeming the reward"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_input.reward="User input for reward"
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.reward="Reward Information"
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.reward.description="Basic information about the reward that was redeemed, at the time it was redeemed."
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.reward="Reward Information (JSON)"
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.reward.description="Basic information about the reward that was redeemed in JSON form, at the time it was redeemed."
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.id.reward="Reward ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.id.reward.description="The ID that uniquely identifies the reward."
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.title.reward="Reward title"
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.title.reward.description="The reward’s title."
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.prompt.reward="Reward prompt"
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.prompt.reward.description="The prompt displayed to the viewer if user input is required."
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.cost.reward="Reward cost"
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.cost.reward.description="The reward’s cost, in Channel Points."
|
||||
AdvSceneSwitcher.tempVar.twitch.status.reward="Reward status"
|
||||
AdvSceneSwitcher.tempVar.twitch.status.reward.description="Defaults to unfulfilled. Possible values are unknown, unfulfilled, fulfilled, and canceled."
|
||||
AdvSceneSwitcher.tempVar.twitch.redeemed_at.reward="Redemption time"
|
||||
@@ -1604,22 +1729,37 @@ AdvSceneSwitcher.tempVar.twitch.title.reward="Reward title"
|
||||
AdvSceneSwitcher.tempVar.twitch.cost.reward="Reward cost"
|
||||
AdvSceneSwitcher.tempVar.twitch.prompt.reward="Reward description"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_user_input_required.reward="Reward requires user input"
|
||||
AdvSceneSwitcher.tempVar.twitch.should_redemptions_skip_request_queue.reward="Redemptions skip request queue"
|
||||
AdvSceneSwitcher.tempVar.twitch.should_redemptions_skip_request_queue.reward.description="Should redemptions be set to fulfilled status immediately when redeemed and skip the request queue instead of the normal unfulfilled status."
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.reward="Reward maximum per stream"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.reward="Reward maximum per user per stream"
|
||||
AdvSceneSwitcher.tempVar.twitch.background_color.reward="Reward background color"
|
||||
AdvSceneSwitcher.tempVar.twitch.image.reward="Reward image"
|
||||
AdvSceneSwitcher.tempVar.twitch.image.reward="Reward image (JSON)"
|
||||
AdvSceneSwitcher.tempVar.twitch.image.reward.description="Set of custom images of 1x, 2x and 4x sizes for the reward. Can be null if no images have been uploaded."
|
||||
AdvSceneSwitcher.tempVar.twitch.default_image.reward="Reward default image"
|
||||
AdvSceneSwitcher.tempVar.twitch.image.url_4x.reward="Reward image URL"
|
||||
AdvSceneSwitcher.tempVar.twitch.image.url_4x.reward.description="The URL to the custom image for the reward. This field is null if the broadcaster didn’t upload images."
|
||||
AdvSceneSwitcher.tempVar.twitch.default_image.reward="Reward default image (JSON)"
|
||||
AdvSceneSwitcher.tempVar.twitch.default_image.reward.description="Set of default images of 1x, 2x and 4x sizes for the reward."
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.reward="Reward cooldown"
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.reward.description="Whether a cooldown is enabled and what the cooldown is in seconds."
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_expires_at.reward="Reward cooldown expiration"
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_expires_at.reward.description="Timestamp of the cooldown expiration. null if the reward isn’t on cooldown."
|
||||
AdvSceneSwitcher.tempVar.twitch.default_image.url_4x.reward="Reward default image URL"
|
||||
AdvSceneSwitcher.tempVar.twitch.default_image.url_4x.reward.description="The URL to the default image for the reward."
|
||||
AdvSceneSwitcher.tempVar.twitch.redemptions_redeemed_current_stream.reward="Redemption count"
|
||||
AdvSceneSwitcher.tempVar.twitch.redemptions_redeemed_current_stream.reward.description="The number of redemptions redeemed during the current live stream. Counts against the max_per_stream limit. null if the broadcasters stream isn’t live or max_per_stream isn’t enabled."
|
||||
AdvSceneSwitcher.tempVar.twitch.redemptions_redeemed_current_stream.reward.description="The number of redemptions redeemed during the current live stream. Counts against the max_per_stream limit. null if the broadcasters stream isn’t live or max_per_stream isn’t enabled."
|
||||
AdvSceneSwitcher.tempVar.twitch.should_redemptions_skip_request_queue.reward="Redemptions skip request queue"
|
||||
AdvSceneSwitcher.tempVar.twitch.should_redemptions_skip_request_queue.reward.description="Should redemptions be set to fulfilled status immediately when redeemed and skip the request queue instead of the normal unfulfilled status."
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.reward="Maximum redemptions per stream (JSON)"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.is_enabled.reward="Maximum redemptions per stream enabled"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.is_enabled.reward.description="A Boolean value that determines whether the reward applies a limit on the number of redemptions allowed per live stream. Is true if the reward applies a limit."
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.max_per_stream.reward="Maximum redemptions per stream"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.max_per_stream.reward.description="The maximum number of redemptions allowed per live stream."
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.reward="Reward maximum per user per stream (JSON)"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.is_enabled.reward="Maximum redemptions per user per stream enabled"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.is_enabled.reward.description="A Boolean value that determines whether the reward applies a limit on the number of redemptions allowed per user per live stream. Is true if the reward applies a limit."
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.max_per_user_per_stream.reward="Maximum redemptions per user per stream"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.max_per_user_per_stream.reward.description="The settings used to determine whether to apply a maximum to the number of redemptions allowed per user per live stream."
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.reward="Global cooldown (JSON)"
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.reward.description="Whether a cooldown is enabled and what the cooldown is in seconds."
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.is_enabled.reward="Global cooldown enabled"
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.is_enabled.reward.description="A Boolean value that determines whether to apply a cooldown period. Is true if a cooldown period is enabled."
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.global_cooldown_seconds.reward="Global cooldown"
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.global_cooldown_seconds.reward.description="The cooldown period, in seconds."
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_expires_at.reward="Reward cooldown expiration"
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_expires_at.reward.description="Timestamp of the cooldown expiration. null if the reward isn’t on cooldown."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.charity_name="Charity name"
|
||||
AdvSceneSwitcher.tempVar.twitch.charity_description="Charity description"
|
||||
@@ -1788,6 +1928,24 @@ AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_name.raid.description="The b
|
||||
AdvSceneSwitcher.tempVar.twitch.viewers.raid="Raid participants"
|
||||
AdvSceneSwitcher.tempVar.twitch.viewers.raid.description="The number of viewers in the raid."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.id.user.getInfo="User ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.id.user.getInfo.description="The user ID of the queried account."
|
||||
AdvSceneSwitcher.tempVar.twitch.login.user.getInfo="User login"
|
||||
AdvSceneSwitcher.tempVar.twitch.login.user.getInfo.description="The user login of the queried account."
|
||||
AdvSceneSwitcher.tempVar.twitch.display_name.user.getInfo="User name"
|
||||
AdvSceneSwitcher.tempVar.twitch.display_name.user.getInfo.description="The display name of the queried account."
|
||||
AdvSceneSwitcher.tempVar.twitch.type.user.getInfo="User type"
|
||||
AdvSceneSwitcher.tempVar.twitch.type.user.getInfo.description="The type of user. Possible values are:\n admin — Twitch administrator\n global_mod\n staff — Twitch staff\n \"\" — Normal user"
|
||||
AdvSceneSwitcher.tempVar.twitch.broadcaster_type.user.getInfo="Broadcaster type"
|
||||
AdvSceneSwitcher.tempVar.twitch.broadcaster_type.user.getInfo.description="The type of broadcaster. Possible values are:\n affiliate — An affiliate broadcaster\n partner — A partner broadcaster\n \"\" — A normal broadcaster"
|
||||
AdvSceneSwitcher.tempVar.twitch.description.user.getInfo="Description"
|
||||
AdvSceneSwitcher.tempVar.twitch.description.user.getInfo.description="The user's description of their channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.profile_image_url.user.getInfo="Profile image URL"
|
||||
AdvSceneSwitcher.tempVar.twitch.offline_image_url.user.getInfo="Offline image URL"
|
||||
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.audio.output_volume="Output volume"
|
||||
AdvSceneSwitcher.tempVar.audio.output_volume.description="The volume the audio source is outputting."
|
||||
AdvSceneSwitcher.tempVar.audio.configured_volume="Configured volume"
|
||||
@@ -1877,8 +2035,11 @@ AdvSceneSwitcher.tempVar.display.height.description="The height of the display w
|
||||
|
||||
AdvSceneSwitcher.tempVar.streaming.keyframeInterval="Stream keyframe interval"
|
||||
AdvSceneSwitcher.tempVar.streaming.keyframeInterval.description="Stream keyframe interval configured in the OBS settings."
|
||||
AdvSceneSwitcher.tempVar.streaming.streamKey="Stream key"
|
||||
AdvSceneSwitcher.tempVar.streaming.durationSeconds="Stream duration"
|
||||
AdvSceneSwitcher.tempVar.streaming.durationSeconds.description="Seconds passed since the stream was started.\nThis value will be zero if the stream is stopped."
|
||||
AdvSceneSwitcher.tempVar.streaming.serviceName="Service"
|
||||
AdvSceneSwitcher.tempVar.streaming.serviceName.description="The name of the streaming service being streamed to (e.g. Twitch)"
|
||||
|
||||
AdvSceneSwitcher.tempVar.clipboard.text="Clipboard text"
|
||||
AdvSceneSwitcher.tempVar.clipboard.text.description="The text contained in the clipboard.\nWill be empty if the clipboard does not contain text."
|
||||
@@ -1958,6 +2119,30 @@ AdvSceneSwitcher.tempVar.streamDeck.column="Key column"
|
||||
AdvSceneSwitcher.tempVar.streamDeck.data="Data"
|
||||
AdvSceneSwitcher.tempVar.streamDeck.data.description="The value of the \"Data\" field configured in the action on the Stream Deck side."
|
||||
|
||||
AdvSceneSwitcher.tempVar.queue.size="Size"
|
||||
AdvSceneSwitcher.tempVar.queue.running="Is running"
|
||||
AdvSceneSwitcher.tempVar.queue.running.description="Returns \"true\" if the queue is started and \"false\" if it is stopped."
|
||||
|
||||
AdvSceneSwitcher.tempVar.screenshot.lastScreenshotPath="Last screenshot path"
|
||||
AdvSceneSwitcher.tempVar.screenshot.lastScreenshotPath.description="The filesystem path to the last screenshot taken."
|
||||
|
||||
AdvSceneSwitcher.tempVar.gameCapture.title="Title"
|
||||
AdvSceneSwitcher.tempVar.gameCapture.title.description="Window title of the application captured by the source."
|
||||
AdvSceneSwitcher.tempVar.gameCapture.class="Class"
|
||||
AdvSceneSwitcher.tempVar.gameCapture.class.description="Window class of the application captured by the source."
|
||||
AdvSceneSwitcher.tempVar.gameCapture.executable="Executable"
|
||||
AdvSceneSwitcher.tempVar.gameCapture.executable.description="Executable name of the application captured by the source."
|
||||
|
||||
AdvSceneSwitcher.tempVar.http.status="Status code"
|
||||
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.selectPreviousScene="Previous Scene"
|
||||
AdvSceneSwitcher.selectCurrentScene="Current Scene"
|
||||
@@ -1996,7 +2181,6 @@ AdvSceneSwitcher.settings.suffix.type.list=" (List)"
|
||||
AdvSceneSwitcher.settings.suffix.type.color=" (Color)"
|
||||
AdvSceneSwitcher.settings.suffix.type.button=" (Button)"
|
||||
AdvSceneSwitcher.settings.suffix.type.font=" (Font)"
|
||||
AdvSceneSwitcher.settings.suffix.type.font=" (Font)"
|
||||
AdvSceneSwitcher.settings.suffix.type.editableList=" (Editable list)"
|
||||
AdvSceneSwitcher.settings.suffix.type.frameRate=" (Frame rate)"
|
||||
AdvSceneSwitcher.settings.suffix.type.group=" (Group)"
|
||||
@@ -2078,13 +2262,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"
|
||||
@@ -2101,7 +2284,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:"
|
||||
@@ -2109,6 +2292,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"
|
||||
|
||||
@@ -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"
|
||||
@@ -172,7 +171,6 @@ AdvSceneSwitcher.condition.stream.state.start="Transmisión en ejecución"
|
||||
AdvSceneSwitcher.condition.stream.state.stop="Transmisión detenida"
|
||||
AdvSceneSwitcher.condition.stream.state.starting="Inicio de transmisión"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="Detener transmisión"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
AdvSceneSwitcher.condition.record="Grabación"
|
||||
AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
|
||||
@@ -407,7 +405,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Mover hacia abajo"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="Mover al principio"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Mover al final"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Mover a la posición"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="En{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="En{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Transformar elemento de escena"
|
||||
AdvSceneSwitcher.action.sceneTransform.getTransform="Obtener transformación"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="En{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}"
|
||||
@@ -439,7 +437,6 @@ AdvSceneSwitcher.action.random="Aleatorio"
|
||||
AdvSceneSwitcher.action.random.entry="Ejecute aleatoriamente cualquiera de las siguientes macros (las macros en pausa se ignoran)"
|
||||
AdvSceneSwitcher.action.systray="Notificación de la bandeja del sistema"
|
||||
AdvSceneSwitcher.action.screenshot="Captura de pantalla"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="Salida principal de OBS"
|
||||
AdvSceneSwitcher.action.profile="Perfil"
|
||||
AdvSceneSwitcher.action.profile.entry="Cambiar perfil activo a {{profiles}}"
|
||||
AdvSceneSwitcher.action.sceneCollection="Colección de escenas"
|
||||
@@ -643,9 +640,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}}"
|
||||
|
||||
@@ -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"
|
||||
@@ -597,7 +596,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Déplacer vers le bas"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="Déplacer en haut"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Déplacer en bas"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Déplacer à la position"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Sur{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Sur{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Transformation de l'élément de la scène"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.manual="Transform"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.reset="Réinitialiser la transformation"
|
||||
@@ -647,7 +646,6 @@ AdvSceneSwitcher.action.screenshot.save.default="Par défaut"
|
||||
AdvSceneSwitcher.action.screenshot.save.custom="Personnalisé"
|
||||
AdvSceneSwitcher.action.screenshot.type.source="Source"
|
||||
AdvSceneSwitcher.action.screenshot.type.scene="Scène"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="Sortie principale d'OBS"
|
||||
AdvSceneSwitcher.action.screenshot.blackscreenNote="Les sources ou les scènes qui ne sont pas toujours rendues peuvent entraîner des parties de captures d'écran vides."
|
||||
AdvSceneSwitcher.action.screenshot.entry="Capturer{{targetType}}{{sources}}{{scenes}}et enregistrer à l'emplacement{{saveType}}{{variables}}"
|
||||
AdvSceneSwitcher.action.profile="Profil"
|
||||
@@ -705,10 +703,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"
|
||||
@@ -718,8 +716,6 @@ AdvSceneSwitcher.action.projector.type.multiview="Multivue"
|
||||
AdvSceneSwitcher.action.projector.display="Affichage"
|
||||
AdvSceneSwitcher.action.projector.windowed="Fenêtré"
|
||||
AdvSceneSwitcher.action.projector.fullscreen="Plein écran"
|
||||
AdvSceneSwitcher.action.projector.entry="Ouvrir le projecteur{{windowTypes}}de{{types}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.projector.entry.monitor="sur{{monitors}}"
|
||||
AdvSceneSwitcher.action.midi="MIDI"
|
||||
AdvSceneSwitcher.action.midi.entry="Envoyer un message à{{device}}:"
|
||||
AdvSceneSwitcher.action.midi.entry.listen="Définir la sélection de messages MIDI sur les messages entrants de{{listenDevices}}:{{listenButton}}"
|
||||
@@ -924,9 +920,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}}"
|
||||
|
||||
@@ -30,7 +30,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.logLevel="ログレベル:"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default="デフォルト"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.logAction="実行されたアクションのログ"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose="詳細ログ(Verbose)"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="詳細ログを有効にする(生成されるログファイルのサイズが増加します)"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="ウィンドウのサイズと位置を記憶する"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="システムトレイ通知を表示"
|
||||
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="UIヒントを無効にする"
|
||||
@@ -49,7 +48,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エクスポートされたデータにはセンシティブ情報が含まれている可能性があります!"
|
||||
@@ -380,16 +379,14 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="一致と
|
||||
AdvSceneSwitcher.condition.video.type.main="OBS's main output"
|
||||
AdvSceneSwitcher.condition.video.type.source="ソース"
|
||||
AdvSceneSwitcher.condition.video.type.scene="シーン"
|
||||
; AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="モデルデータ (そのカスケード分類子):{{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.modelPath="モデルデータ (そのカスケード分類子):{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.minNeighbor="最小近傍数:{{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}:{{throttleCount}}ミリ秒ごとにのみチェックを実行することでCPU負荷を軽減します"
|
||||
AdvSceneSwitcher.condition.video.layout.checkAreaEnable="エリア内のみチェックを実施"
|
||||
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="範囲指定"
|
||||
@@ -925,7 +922,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="下へ移動"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="トップへ移動"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="一番下へ移動"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="ポジションへの移動"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="オン{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="オン{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="シーンアイテムの変形"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.manual="変形"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.setSingleSetting="トランスフォーム設定を行う"
|
||||
@@ -979,7 +976,6 @@ AdvSceneSwitcher.action.screenshot.save.default="デフォルト"
|
||||
AdvSceneSwitcher.action.screenshot.save.custom="カスタム"
|
||||
; AdvSceneSwitcher.action.screenshot.type.source="Source"
|
||||
AdvSceneSwitcher.action.screenshot.type.scene="シーン"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="OBSの主な出力"
|
||||
AdvSceneSwitcher.action.screenshot.blackscreenNote="常にレンダリングされるわけではないソースやシーンにより、スクリーンショットの一部が空白のままになる場合があります。"
|
||||
AdvSceneSwitcher.action.screenshot.entry="スクリーンショット{{targetType}}{{sources}}{{scenes}}を作成し、{{saveType}}{{variables}}の場所に保存します"
|
||||
AdvSceneSwitcher.action.profile="プロファイル"
|
||||
@@ -1031,7 +1027,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="インデックスのシーン項目名に設定"
|
||||
@@ -1051,14 +1047,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}}"
|
||||
AdvSceneSwitcher.action.variable.entry.pad="{{actions}}の{{variables}}の長さを{{stringLength}}にするには、{{paddingCharSelection}}を{{direction}}に追加します。"
|
||||
AdvSceneSwitcher.action.variable.entry.truncate="{{actions}}の{{variables}}の長さを{{stringLength}}にするには、{{direction}}から文字を削除します。"
|
||||
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.layout.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}"
|
||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}の{{variables}}の長さを{{stringLength}}にするには、{{paddingCharSelection}}を{{direction}}に追加します。"
|
||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}の{{variables}}の長さを{{stringLength}}にするには、{{direction}}から文字を削除します。"
|
||||
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.projector="プロジェクター"
|
||||
AdvSceneSwitcher.action.projector.type.source="ソース"
|
||||
AdvSceneSwitcher.action.projector.type.scene="シーン"
|
||||
@@ -1068,8 +1064,6 @@ AdvSceneSwitcher.action.projector.type.multiview="マルチビュー"
|
||||
AdvSceneSwitcher.action.projector.display="ディスプレイ"
|
||||
AdvSceneSwitcher.action.projector.windowed="ウィンドウ"
|
||||
AdvSceneSwitcher.action.projector.fullscreen="フルスクリーン"
|
||||
AdvSceneSwitcher.action.projector.entry="{{types}}{{scenes}}{{sources}}の{{windowTypes}}プロジェクターを開きます"
|
||||
AdvSceneSwitcher.action.projector.entry.monitor="{{monitors}}上で"
|
||||
; AdvSceneSwitcher.action.midi="MIDI"
|
||||
AdvSceneSwitcher.action.midi.entry="メッセージを{{device}}に送信します:"
|
||||
AdvSceneSwitcher.action.midi.entry.listen="MIDI メッセージの選択を {{listenDevices}} で受信するメッセージに設定します:{{listenButton}}"
|
||||
@@ -1089,10 +1083,10 @@ AdvSceneSwitcher.action.twitch.type.clip.create="ストリームクリップの
|
||||
AdvSceneSwitcher.action.twitch.type.chat.announcement.send="チャット通知の送信"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="チャットのエモート専用モードを有効にする"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="チャットのエモート専用モードを無効にする"
|
||||
AdvSceneSwitcher.action.twitch.type.sendChatMessage="チャットメッセージを送る"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="チャットメッセージを送る"
|
||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Twitchアカウントを選択しないとカテゴリを選択できません!"
|
||||
; AdvSceneSwitcher.action.twitch.entry.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="{{channel}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}} でアカウント{{account}}{{actions}}を使用しています"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="{{channel}}でアカウント{{account}}{{actions}}を使用しています"
|
||||
AdvSceneSwitcher.action.twitch.title.title="タイトルを入力してください"
|
||||
AdvSceneSwitcher.action.twitch.marker.description="マーカーの説明"
|
||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="クリップをキャプチャする前にわずかな遅延を追加します"
|
||||
@@ -1134,9 +1128,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}}"
|
||||
|
||||
@@ -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"
|
||||
@@ -395,7 +394,6 @@ AdvSceneSwitcher.condition.stream.state.stop="Streaming parado"
|
||||
AdvSceneSwitcher.condition.stream.state.starting="Iniciando o streaming"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="Parando o streaming"
|
||||
AdvSceneSwitcher.condition.stream.state.keyFrameInterval="Intervalo de keyframe igual a"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
AdvSceneSwitcher.condition.record="Gravação"
|
||||
AdvSceneSwitcher.condition.record.state.start="Gravação em execução"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Gravação pausada"
|
||||
@@ -907,7 +905,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Mover para baixo"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="Mover para o topo"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Mover para o fundo"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Mover para posição"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Em{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Em{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Transformação de item de cena"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.manual="Definir string de transformação"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.setSingleSetting="Definir configuração de transformação"
|
||||
@@ -961,7 +959,6 @@ AdvSceneSwitcher.action.screenshot.save.default="Padrão"
|
||||
AdvSceneSwitcher.action.screenshot.save.custom="Personalizado"
|
||||
AdvSceneSwitcher.action.screenshot.type.source="Fonte"
|
||||
AdvSceneSwitcher.action.screenshot.type.scene="Cena"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="Saída principal do OBS"
|
||||
AdvSceneSwitcher.action.screenshot.blackscreenNote="Fontes ou cenas, que nem sempre são renderizadas, podem resultar em algumas partes das capturas de tela permanecendo em branco."
|
||||
AdvSceneSwitcher.action.screenshot.entry="Captura de tela{{targetType}}{{sources}}{{scenes}}e salvar em{{saveType}}{{variables}}localização"
|
||||
AdvSceneSwitcher.action.profile="Perfil"
|
||||
@@ -1014,7 +1011,7 @@ AdvSceneSwitcher.action.variable.type.askForValue="Obter entrada do usuário"
|
||||
AdvSceneSwitcher.action.variable.type.environmentVariable="Definir valor da variável de ambiente"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemCount="Definir para contagem de itens de cena"
|
||||
AdvSceneSwitcher.action.variable.type.stringLength="Definir comprimento da string"
|
||||
AdvSceneSwitcher.action.variable.type.extractJson="Extrair campo json com nome"
|
||||
AdvSceneSwitcher.action.variable.type.extractJsonField="Extrair campo json com nome"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar="Definir para propriedade da macro"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar.help="Este tipo de ação permite extrair valores de segmentos da macro atual e atribuir esses valores à variável selecionada.\nPor exemplo, você pode obter o nome da cena atual de uma condição de cena e atribuir esse nome a uma variável."
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemName="Definir para nome do item de cena no índice"
|
||||
@@ -1034,13 +1031,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"
|
||||
@@ -1050,8 +1047,6 @@ AdvSceneSwitcher.action.projector.type.multiview="Multivisão"
|
||||
AdvSceneSwitcher.action.projector.display="Exibição"
|
||||
AdvSceneSwitcher.action.projector.windowed="Janela"
|
||||
AdvSceneSwitcher.action.projector.fullscreen="Tela cheia"
|
||||
AdvSceneSwitcher.action.projector.entry="Abrir{{windowTypes}}projetor de{{types}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.projector.entry.monitor="em{{monitors}}"
|
||||
AdvSceneSwitcher.action.midi="MIDI"
|
||||
AdvSceneSwitcher.action.midi.entry="Enviar mensagem para{{device}}:"
|
||||
AdvSceneSwitcher.action.midi.entry.listen="Definir seleção de mensagem MIDI para mensagens recebidas em{{listenDevices}}:{{listenButton}}"
|
||||
@@ -1071,10 +1066,10 @@ AdvSceneSwitcher.action.twitch.type.clip.create="Criar clipe da transmissão"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.announcement.send="Enviar anúncio de chat"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Habilitar modo apenas emotes no chat"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Desabilitar modo apenas emotes no chat"
|
||||
AdvSceneSwitcher.action.twitch.type.sendChatMessage="Enviar mensagem de chat"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Enviar mensagem de chat"
|
||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Não é possível selecionar categoria sem selecionar uma conta Twitch primeiro!"
|
||||
AdvSceneSwitcher.action.twitch.entry.default="Em{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="Usando conta{{account}}{{actions}}em{{channel}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.default="Em{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="Usando conta{{account}}{{actions}}em{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.title.title="Digite o título"
|
||||
AdvSceneSwitcher.action.twitch.marker.description="Descreva o marcador"
|
||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="Adicionar um leve atraso antes de capturar o clipe"
|
||||
@@ -1116,9 +1111,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}}"
|
||||
|
||||
@@ -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="Содержание файла"
|
||||
|
||||
@@ -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,16 +139,15 @@ AdvSceneSwitcher.condition.video.screenshotFail="Kaynağın ekran görüntüsü
|
||||
AdvSceneSwitcher.condition.video.patternMatchFail="Desen bulunamadı!"
|
||||
AdvSceneSwitcher.condition.video.objectMatchFail="Nesne bulunamadı!"
|
||||
AdvSceneSwitcher.condition.video.modelLoadFail="Model verileri yüklenemedi!"
|
||||
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.modelPath="Model verileri (haar kademeli sınıflandırıcı):{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimum komşular: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}} Yalnızca her seferinde kontrol gerçekleştirerek CPU yükünü azaltın {{throttleCount}} millisaniyeler"
|
||||
AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.modelPath="Model verileri (haar kademeli sınıflandırıcı):{{modelDataPath}}"
|
||||
AdvSceneSwitcher.condition.video.layout.minNeighbor="Minimum komşular: {{minNeighbors}}"
|
||||
AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}} Yalnızca her seferinde kontrol gerçekleştirerek CPU yükünü azaltın {{throttleCount}} millisaniyeler"
|
||||
AdvSceneSwitcher.condition.stream="Yayınlama"
|
||||
AdvSceneSwitcher.condition.stream.state.start="Yayın çalışıyor"
|
||||
AdvSceneSwitcher.condition.stream.state.stop="Yayın durdu"
|
||||
AdvSceneSwitcher.condition.stream.state.starting="Yayın başlıyor"
|
||||
AdvSceneSwitcher.condition.stream.state.stopping="Yayın duruyor"
|
||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
|
||||
AdvSceneSwitcher.condition.record="Kayıt"
|
||||
AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
|
||||
@@ -336,7 +334,7 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Aşağı indir"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="En üste taşı"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Aşağıya taşı"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Konuma taşı"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Açık{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Açık{{scenes}}{{actions}}{{sources}}{{sources2}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Sahne öğesi dönüşümü"
|
||||
AdvSceneSwitcher.action.sceneTransform.getTransform="Dönüşümü al"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="Açık{{scenes}}{{action}}{{rotation}}{{sources}}{{settingSelection}}{{singleSettingValue}}"
|
||||
@@ -357,7 +355,6 @@ AdvSceneSwitcher.action.random="Rastgele"
|
||||
AdvSceneSwitcher.action.random.entry="Aşağıdaki makrolardan herhangi birini rastgele çalıştırın (duraklatılmış makrolar yoksayılır)"
|
||||
AdvSceneSwitcher.action.systray="Sistem tepsisi bildirimi"
|
||||
AdvSceneSwitcher.action.screenshot="Ekran görüntüsü"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="OBS'nin ana çıkışı"
|
||||
AdvSceneSwitcher.action.profile="Profil"
|
||||
AdvSceneSwitcher.action.profile.entry="Aktif profili şununla değiştir: {{profiles}}"
|
||||
AdvSceneSwitcher.action.sceneCollection="Sahne koleksiyonu"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1
deps/date
vendored
Submodule
1
deps/date
vendored
Submodule
Submodule deps/date added at 5bdb7e6f31
13156
deps/exprtk/exprtk.hpp
vendored
13156
deps/exprtk/exprtk.hpp
vendored
File diff suppressed because it is too large
Load Diff
1
deps/jsoncons
vendored
Submodule
1
deps/jsoncons
vendored
Submodule
Submodule deps/jsoncons added at 64b9da1e9f
2
deps/libremidi
vendored
2
deps/libremidi
vendored
Submodule deps/libremidi updated: d6d6557b5b...73e6ea40de
1
deps/paho.mqtt.cpp
vendored
Submodule
1
deps/paho.mqtt.cpp
vendored
Submodule
Submodule deps/paho.mqtt.cpp added at 165476b1dc
@@ -181,28 +181,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 +294,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>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "backup.hpp"
|
||||
#include "curl-helper.hpp"
|
||||
#include "log-helper.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
@@ -19,10 +18,15 @@
|
||||
#include <obs-frontend-api.h>
|
||||
#include <QAction>
|
||||
#include <QDirIterator>
|
||||
#include <QLibrary>
|
||||
#include <QMainWindow>
|
||||
#include <QTextStream>
|
||||
#include <regex>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
namespace advss {
|
||||
|
||||
AdvSceneSwitcher *AdvSceneSwitcher::window = nullptr;
|
||||
@@ -307,7 +311,7 @@ void SwitcherData::Thread()
|
||||
}
|
||||
}
|
||||
|
||||
ResetForNextInterval();
|
||||
RunIntervalResetSteps();
|
||||
|
||||
if (match) {
|
||||
if (macroMatch) {
|
||||
@@ -357,14 +361,6 @@ void SwitcherData::SetPreconditions()
|
||||
InvalidateMacroTempVarValues();
|
||||
}
|
||||
|
||||
void SwitcherData::ResetForNextInterval()
|
||||
{
|
||||
// Plugin reset functions
|
||||
for (const auto &func : resetIntervalSteps) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
|
||||
OBSWeakSource &transition, int &linger,
|
||||
bool &setPrevSceneAfterLinger,
|
||||
@@ -445,7 +441,7 @@ void AutoStartActionQueues();
|
||||
void SwitcherData::Start()
|
||||
{
|
||||
if (!(th && th->isRunning())) {
|
||||
ResetForNextInterval();
|
||||
RunIntervalResetSteps();
|
||||
ResetMacros();
|
||||
AutoStartActionQueues();
|
||||
|
||||
@@ -453,10 +449,7 @@ void SwitcherData::Start()
|
||||
th = new SwitcherThread();
|
||||
th->start((QThread::Priority)threadPriority);
|
||||
|
||||
// Will be overwritten quickly but might be useful
|
||||
writeToStatusFile("Advanced Scene Switcher running");
|
||||
SendWebsocketVendorEvent("AdvancedSceneSwitcherStarted",
|
||||
nullptr);
|
||||
RunStartSteps();
|
||||
}
|
||||
|
||||
if (showSystemTrayNotifications) {
|
||||
@@ -483,11 +476,7 @@ void SwitcherData::Stop()
|
||||
th->wait();
|
||||
delete th;
|
||||
th = nullptr;
|
||||
writeToStatusFile("Advanced Scene Switcher stopped");
|
||||
if (!obsIsShuttingDown) {
|
||||
SendWebsocketVendorEvent("AdvancedSceneSwitcherStopped",
|
||||
nullptr);
|
||||
}
|
||||
RunStopSteps();
|
||||
}
|
||||
|
||||
if (showSystemTrayNotifications) {
|
||||
@@ -735,7 +724,7 @@ void OpenSettingsWindow()
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighligthMacroSettingsButton(bool enable)
|
||||
void AdvSceneSwitcher::HighlightMacroSettingsButton(bool enable)
|
||||
{
|
||||
static QObject *highlight = nullptr;
|
||||
if ((highlight && enable) || (!highlight && !enable)) {
|
||||
@@ -755,13 +744,13 @@ void AdvSceneSwitcher::HighligthMacroSettingsButton(bool enable)
|
||||
highlight = HighlightWidget(ui->macroSettings, Qt::green);
|
||||
}
|
||||
|
||||
void HighligthMacroSettingsButton(bool enable)
|
||||
void HighlightMacroSettingsButton(bool enable)
|
||||
{
|
||||
auto window = GetSettingsWindow();
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
static_cast<AdvSceneSwitcher *>(window)->HighligthMacroSettingsButton(
|
||||
static_cast<AdvSceneSwitcher *>(window)->HighlightMacroSettingsButton(
|
||||
enable);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,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();
|
||||
@@ -82,31 +83,33 @@ public:
|
||||
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();
|
||||
std::shared_ptr<Macro> GetSelectedMacro() const;
|
||||
std::vector<std::shared_ptr<Macro>> GetSelectedMacros() const;
|
||||
void SetEditMacro(Macro &m);
|
||||
void SetMacroEditAreaDisabled(bool);
|
||||
void HighlightAction(int idx, QColor color = QColor(Qt::green));
|
||||
void HighlightElseAction(int idx, QColor color = QColor(Qt::green));
|
||||
void HighlightCondition(int idx, QColor color = QColor(Qt::green));
|
||||
void SetMacroEditAreaDisabled(bool) const;
|
||||
void HighlightAction(int idx, QColor color = QColor(Qt::green)) const;
|
||||
void HighlightElseAction(int idx,
|
||||
QColor color = QColor(Qt::green)) const;
|
||||
void HighlightCondition(int idx,
|
||||
QColor color = QColor(Qt::green)) const;
|
||||
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroElseActions(Macro &m, uint32_t afterIdx = 0);
|
||||
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
|
||||
void SetActionData(Macro &m);
|
||||
void SetElseActionData(Macro &m);
|
||||
void SetConditionData(Macro &m);
|
||||
void SetActionData(Macro &m) const;
|
||||
void SetElseActionData(Macro &m) const;
|
||||
void SetConditionData(Macro &m) const;
|
||||
void SwapActions(Macro *m, int pos1, int pos2);
|
||||
void SwapConditions(Macro *m, int pos1, int pos2);
|
||||
void HighligthMacroSettingsButton(bool enable = true);
|
||||
void HighlightMacroSettingsButton(bool enable = true);
|
||||
|
||||
public slots:
|
||||
void on_macroAdd_clicked();
|
||||
void on_macroRemove_clicked();
|
||||
void on_macroUp_clicked();
|
||||
void on_macroDown_clicked();
|
||||
void on_macroUp_clicked() const;
|
||||
void on_macroDown_clicked() const;
|
||||
void on_macroName_editingFinished();
|
||||
void on_runMacroInParallel_stateChanged(int value);
|
||||
void on_runMacroOnChange_stateChanged(int value);
|
||||
void on_runMacroInParallel_stateChanged(int value) const;
|
||||
void on_runMacroOnChange_stateChanged(int value) const;
|
||||
void on_conditionAdd_clicked();
|
||||
void on_conditionRemove_clicked();
|
||||
void on_conditionTop_clicked();
|
||||
@@ -119,14 +122,14 @@ public slots:
|
||||
void on_actionUp_clicked();
|
||||
void on_actionDown_clicked();
|
||||
void on_actionBottom_clicked();
|
||||
void on_toggleElseActions_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 MacroSelectionAboutToChange();
|
||||
void MacroSelectionAboutToChange() const;
|
||||
void MacroSelectionChanged();
|
||||
void UpMacroSegementHotkey();
|
||||
void DownMacroSegementHotkey();
|
||||
@@ -137,22 +140,22 @@ public slots:
|
||||
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 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,
|
||||
@@ -178,8 +181,8 @@ public slots:
|
||||
void RemoveMacroCondition(int idx);
|
||||
void MoveMacroConditionUp(int idx);
|
||||
void MoveMacroConditionDown(int idx);
|
||||
void HighlightControls();
|
||||
void HighlightOnChange();
|
||||
void HighlightControls() const;
|
||||
void HighlightOnChange() const;
|
||||
void on_macroSettings_clicked();
|
||||
void CopyMacroSegment();
|
||||
void PasteMacroSegment();
|
||||
@@ -386,6 +389,6 @@ private:
|
||||
};
|
||||
|
||||
void OpenSettingsWindow();
|
||||
void HighligthMacroSettingsButton(bool enable);
|
||||
void HighlightMacroSettingsButton(bool enable);
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -113,12 +113,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)
|
||||
@@ -205,6 +205,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 +285,15 @@ static bool containsSensitiveData(obs_data_t *data)
|
||||
obs_data_get_array(data, "twitchConnections");
|
||||
OBSDataArrayAutoRelease websocketConnections =
|
||||
obs_data_get_array(data, "websocketConnections");
|
||||
OBSDataArrayAutoRelease mqttConnections =
|
||||
obs_data_get_array(data, "mqttConnections");
|
||||
|
||||
auto isNotEmpty = [](obs_data_array *array) {
|
||||
return obs_data_array_count(array) > 0;
|
||||
};
|
||||
|
||||
return isNotEmpty(twitchTokens) || isNotEmpty(websocketConnections);
|
||||
return isNotEmpty(twitchTokens) || isNotEmpty(websocketConnections) ||
|
||||
isNotEmpty(mqttConnections);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_exportSettings_clicked()
|
||||
@@ -344,6 +357,10 @@ void AdvSceneSwitcher::on_importSettings_clicked()
|
||||
return;
|
||||
}
|
||||
|
||||
// We have to make sure to that no macro is currently being edited while
|
||||
// the new settings are loaded
|
||||
ui->macros->clearSelection();
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->LoadSettings(obj);
|
||||
switcher->lastImportPath = path.toStdString();
|
||||
@@ -379,6 +396,7 @@ void AdvSceneSwitcher::CheckFirstTimeSetup()
|
||||
switcher->firstBoot = false;
|
||||
DisplayMessage(
|
||||
obs_module_text("AdvSceneSwitcher.firstBootMessage"));
|
||||
switcher->Start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,13 +543,15 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
|
||||
obs_data_set_int(obj, "autoStartEvent",
|
||||
static_cast<int>(autoStartEvent));
|
||||
|
||||
obs_data_set_int(obj, "logLevel", static_cast<int>(logLevel));
|
||||
obs_data_set_int(obj, "logLevelVersion", 1);
|
||||
SaveLogLevel(obj);
|
||||
|
||||
obs_data_set_bool(obj, "showSystemTrayNotifications",
|
||||
showSystemTrayNotifications);
|
||||
obs_data_set_bool(obj, "disableHints", disableHints);
|
||||
obs_data_set_bool(obj, "disableFilterComboboxFilter",
|
||||
disableFilterComboboxFilter);
|
||||
obs_data_set_bool(obj, "disableMacroWidgetCache",
|
||||
disableMacroWidgetCache);
|
||||
obs_data_set_bool(obj, "warnPluginLoadFailure", warnPluginLoadFailure);
|
||||
obs_data_set_bool(obj, "hideLegacyTabs", hideLegacyTabs);
|
||||
|
||||
@@ -582,31 +602,15 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
||||
autoStartEvent =
|
||||
static_cast<AutoStart>(obs_data_get_int(obj, "autoStartEvent"));
|
||||
|
||||
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);
|
||||
@@ -890,7 +894,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(
|
||||
@@ -900,6 +906,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);
|
||||
|
||||
|
||||
@@ -259,7 +259,8 @@ void AudioSwitch::setVolumeLevel(void *data, const float *,
|
||||
}
|
||||
}
|
||||
|
||||
obs_volmeter_t *AddVolmeterToSource(AudioSwitch *entry, obs_weak_source *source)
|
||||
static obs_volmeter_t *addVolmeterToSource(AudioSwitch *entry,
|
||||
obs_weak_source *source)
|
||||
{
|
||||
obs_volmeter_t *volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
||||
obs_volmeter_add_callback(volmeter, AudioSwitch::setVolumeLevel, entry);
|
||||
@@ -279,7 +280,7 @@ void AudioSwitch::resetVolmeter()
|
||||
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
|
||||
obs_volmeter_destroy(volmeter);
|
||||
|
||||
volmeter = AddVolmeterToSource(this, audioSource);
|
||||
volmeter = addVolmeterToSource(this, audioSource);
|
||||
}
|
||||
|
||||
bool AudioSwitch::initialized()
|
||||
@@ -318,7 +319,7 @@ void AudioSwitch::load(obs_data_t *obj)
|
||||
duration.Load(obj, "duration");
|
||||
ignoreInactiveSource = obs_data_get_bool(obj, "ignoreInactiveSource");
|
||||
|
||||
volmeter = AddVolmeterToSource(this, audioSource);
|
||||
volmeter = addVolmeterToSource(this, audioSource);
|
||||
}
|
||||
|
||||
void AudioSwitchFallback::save(obs_data_t *obj)
|
||||
@@ -349,7 +350,7 @@ AudioSwitch::AudioSwitch(const AudioSwitch &other)
|
||||
condition(other.condition),
|
||||
duration(other.duration)
|
||||
{
|
||||
volmeter = AddVolmeterToSource(this, other.audioSource);
|
||||
volmeter = addVolmeterToSource(this, other.audioSource);
|
||||
}
|
||||
|
||||
AudioSwitch::AudioSwitch(AudioSwitch &&other) noexcept
|
||||
|
||||
@@ -21,6 +21,29 @@ bool FileSwitch::pause = false;
|
||||
static QObject *addPulse = nullptr;
|
||||
static std::hash<std::string> strHash;
|
||||
|
||||
static void writeToStatusFile(const QString &msg)
|
||||
{
|
||||
if (!GetSwitcher() || !GetSwitcher()->fileIO.writeEnabled ||
|
||||
GetSwitcher()->fileIO.writePath.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(QString::fromStdString(GetSwitcher()->fileIO.writePath));
|
||||
if (file.open(QIODevice::ReadWrite)) {
|
||||
QTextStream stream(&file);
|
||||
stream << msg << Qt::endl;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
static bool _ = []() {
|
||||
AddStartStep(
|
||||
[]() { writeToStatusFile("Advanced Scene Switcher running"); });
|
||||
AddStopStep(
|
||||
[]() { writeToStatusFile("Advanced Scene Switcher stopped"); });
|
||||
return true;
|
||||
}();
|
||||
|
||||
void AdvSceneSwitcher::on_browseButton_clicked()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(
|
||||
@@ -113,24 +136,6 @@ void SwitcherData::writeSceneInfoToFile()
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::writeToStatusFile(const QString &msg)
|
||||
{
|
||||
if (!fileIO.writeEnabled || fileIO.writePath.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(QString::fromStdString(fileIO.writePath));
|
||||
if (file.open(QIODevice::ReadWrite)) {
|
||||
QTextStream stream(&file);
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
stream << msg << "\n";
|
||||
#else
|
||||
stream << msg << Qt::endl;
|
||||
#endif
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
bool SwitcherData::checkSwitchInfoFromFile(OBSWeakSource &scene,
|
||||
OBSWeakSource &transition)
|
||||
{
|
||||
|
||||
@@ -384,7 +384,11 @@ static void getProcessListProcps2(QStringList &processes)
|
||||
return;
|
||||
}
|
||||
while ((stack = procps_pids_get_(info, PIDS_FETCH_TASKS_ONLY))) {
|
||||
#ifdef PROCPS2_USE_INFO
|
||||
auto cmd = PIDS_VAL(0, str, stack, info);
|
||||
#else
|
||||
auto cmd = PIDS_VAL(0, str, stack);
|
||||
#endif
|
||||
QString procName(cmd);
|
||||
if (!procName.isEmpty() && !processes.contains(procName)) {
|
||||
processes << procName;
|
||||
@@ -546,6 +550,11 @@ static void initProc2()
|
||||
#endif
|
||||
}
|
||||
|
||||
int ignoreXerror(Display *d, XErrorEvent *e)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PlatformInit()
|
||||
{
|
||||
auto display = disp();
|
||||
@@ -556,6 +565,7 @@ void PlatformInit()
|
||||
initXss();
|
||||
initProcps();
|
||||
initProc2();
|
||||
XSetErrorHandler(ignoreXerror);
|
||||
}
|
||||
|
||||
static void cleanupHelper(QLibrary *lib)
|
||||
@@ -572,6 +582,7 @@ void PlatformCleanup()
|
||||
cleanupHelper(libprocps);
|
||||
cleanupHelper(libproc2);
|
||||
cleanupDisplay();
|
||||
XSetErrorHandler(NULL);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
#include "section.hpp"
|
||||
#include "switch-button.hpp"
|
||||
|
||||
#include <QGraphicsOpacityEffect>
|
||||
|
||||
namespace advss {
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
@@ -17,6 +15,9 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
QString entry(obs_module_text(action._name.c_str()));
|
||||
if (list->findText(entry) == -1) {
|
||||
list->addItem(entry);
|
||||
qobject_cast<QListView *>(list->view())
|
||||
->setRowHidden(list->count() - 1,
|
||||
action._hidden);
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"did not insert duplicate action entry with name \"%s\"",
|
||||
@@ -34,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);
|
||||
@@ -60,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) {
|
||||
@@ -95,38 +126,11 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
SetFocusPolicyOfWidgets();
|
||||
}
|
||||
|
||||
void MacroActionEdit::UpdateEntryData(const std::string &id)
|
||||
{
|
||||
_actionSelection->setCurrentText(
|
||||
obs_module_text(MacroActionFactory::GetActionName(id).c_str()));
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
_enable->setChecked(enabled);
|
||||
SetDisableEffect(!enabled);
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
HeaderInfoChanged(
|
||||
QString::fromStdString((*_entryData)->GetShortDesc()));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetFocusPolicyOfWidgets();
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetEntryData(std::shared_ptr<MacroAction> *data)
|
||||
{
|
||||
_entryData = data;
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetDisableEffect(bool value)
|
||||
{
|
||||
if (value) {
|
||||
auto effect = new QGraphicsOpacityEffect(this);
|
||||
effect->setOpacity(0.5);
|
||||
_section->setGraphicsEffect(effect);
|
||||
} else {
|
||||
_section->setGraphicsEffect(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionEdit::ActionEnableChanged(bool value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
@@ -144,13 +148,9 @@ void MacroActionEdit::UpdateActionState()
|
||||
return;
|
||||
}
|
||||
|
||||
SetEnableAppearance((*_entryData)->Enabled());
|
||||
}
|
||||
|
||||
void MacroActionEdit::SetEnableAppearance(bool value)
|
||||
{
|
||||
_enable->setChecked(value);
|
||||
SetDisableEffect(!value);
|
||||
const bool enabled = (*_entryData)->Enabled();
|
||||
SetEnableAppearance(enabled);
|
||||
_enable->setChecked(enabled);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
||||
|
||||
@@ -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:
|
||||
@@ -27,14 +27,11 @@ private slots:
|
||||
|
||||
private:
|
||||
std::shared_ptr<MacroSegment> Data() const;
|
||||
void SetDisableEffect(bool);
|
||||
void SetEnableAppearance(bool);
|
||||
|
||||
FilterComboBox *_actionSelection;
|
||||
SwitchButton *_enable;
|
||||
|
||||
std::shared_ptr<MacroAction> *_entryData;
|
||||
QTimer _actionStateTimer;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ struct MacroActionInfo {
|
||||
std::function<std::shared_ptr<MacroAction>(Macro *m)> _create = nullptr;
|
||||
CreateActionWidget _createWidget = nullptr;
|
||||
std::string _name;
|
||||
bool _hidden = false;
|
||||
};
|
||||
|
||||
class MacroActionFactory {
|
||||
|
||||
@@ -12,25 +12,6 @@ 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()
|
||||
{
|
||||
auto macro = _macro.GetMacro();
|
||||
@@ -45,6 +26,9 @@ 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;
|
||||
@@ -210,8 +194,31 @@ 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::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"},
|
||||
};
|
||||
|
||||
for (const auto &[value, name] : actions) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,11 +316,11 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void HighligthMacroSettingsButton(bool enable);
|
||||
void HighlightMacroSettingsButton(bool enable);
|
||||
|
||||
MacroActionMacroEdit::~MacroActionMacroEdit()
|
||||
{
|
||||
HighligthMacroSettingsButton(false);
|
||||
HighlightMacroSettingsButton(false);
|
||||
}
|
||||
|
||||
void MacroActionMacroEdit::UpdateEntryData()
|
||||
@@ -321,7 +328,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);
|
||||
@@ -350,10 +358,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();
|
||||
}
|
||||
|
||||
@@ -480,7 +489,7 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
||||
_inputs->setVisible(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN &&
|
||||
_entryData->_runOptions.setInputs);
|
||||
HighligthMacroSettingsButton(_entryData->_action ==
|
||||
HighlightMacroSettingsButton(_entryData->_action ==
|
||||
MacroActionMacro::Action::RUN &&
|
||||
_entryData->_runOptions.setInputs &&
|
||||
!_inputs->HasInputsToSet());
|
||||
|
||||
@@ -49,6 +49,7 @@ public:
|
||||
DISABLE_ACTION,
|
||||
ENABLE_ACTION,
|
||||
TOGGLE_ACTION,
|
||||
TOGGLE_PAUSE,
|
||||
};
|
||||
Action _action = Action::RUN;
|
||||
IntVariable _actionIndex = 1;
|
||||
|
||||
@@ -6,14 +6,17 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
MacroActionScript::MacroActionScript(Macro *m, const std::string &id,
|
||||
const OBSData &defaultSettings,
|
||||
const std::string &propertiesSignalName,
|
||||
const std::string &triggerSignal,
|
||||
const std::string &completionSignal)
|
||||
MacroActionScript::MacroActionScript(
|
||||
Macro *m, const std::string &id, const OBSData &defaultSettings,
|
||||
const std::string &propertiesSignalName,
|
||||
const std::string &triggerSignalName,
|
||||
const std::string &completionSignalName,
|
||||
const std::string &newInstanceSignalName,
|
||||
const std::string &deletedInstanceSignalName)
|
||||
: MacroAction(m),
|
||||
MacroSegmentScript(defaultSettings, propertiesSignalName,
|
||||
triggerSignal, completionSignal),
|
||||
triggerSignalName, completionSignalName,
|
||||
newInstanceSignalName, deletedInstanceSignalName),
|
||||
_id(id)
|
||||
{
|
||||
}
|
||||
@@ -89,4 +92,29 @@ void MacroActionScript::WaitForCompletion() const
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionScript::RegisterTempVarHelper(const std::string &variableId,
|
||||
const std::string &name,
|
||||
const std::string &helpText)
|
||||
{
|
||||
AddTempvar(variableId, name, helpText);
|
||||
}
|
||||
|
||||
void MacroActionScript::DeregisterAllTempVarsHelper()
|
||||
{
|
||||
MacroSegment::SetupTempVars();
|
||||
}
|
||||
|
||||
void MacroActionScript::SetTempVarValueHelper(const std::string &variableId,
|
||||
const std::string &value)
|
||||
{
|
||||
MacroAction::SetTempVarValue(variableId, value);
|
||||
}
|
||||
|
||||
void MacroActionScript::SetupTempVars()
|
||||
{
|
||||
// This just exists so MacroSegment::SetupTempVars() is not called.
|
||||
// We want the ScriptHandler to handle the registration and clearing of
|
||||
// the temp vars.
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -10,8 +10,10 @@ public:
|
||||
MacroActionScript(Macro *m, const std::string &id,
|
||||
const OBSData &defaultSettings,
|
||||
const std::string &propertiesSignalName,
|
||||
const std::string &triggerSignal,
|
||||
const std::string &signalComplete);
|
||||
const std::string &triggerSignalName,
|
||||
const std::string &completionSignalName,
|
||||
const std::string &newInstanceSignalName,
|
||||
const std::string &deletedInstanceSignalName);
|
||||
MacroActionScript(const advss::MacroActionScript &);
|
||||
bool PerformAction();
|
||||
void LogAction() const;
|
||||
@@ -22,6 +24,13 @@ public:
|
||||
|
||||
private:
|
||||
void WaitForCompletion() const;
|
||||
void RegisterTempVarHelper(const std::string &variableId,
|
||||
const std::string &name,
|
||||
const std::string &helpText);
|
||||
void DeregisterAllTempVarsHelper();
|
||||
void SetTempVarValueHelper(const std::string &variableId,
|
||||
const std::string &value);
|
||||
void SetupTempVars();
|
||||
|
||||
std::string _id = "";
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -28,8 +28,8 @@ public:
|
||||
int GetSegmentIndexValue() const;
|
||||
void ResolveVariablesToFixedValues();
|
||||
|
||||
enum class Type {
|
||||
SET_FIXED_VALUE,
|
||||
enum class Action {
|
||||
SET_VALUE,
|
||||
APPEND,
|
||||
APPEND_VAR,
|
||||
INCREMENT,
|
||||
@@ -52,18 +52,21 @@ public:
|
||||
SWAP_VALUES,
|
||||
TRIM,
|
||||
CHANGE_CASE,
|
||||
RANDOM_NUMBER,
|
||||
QUERY_JSON,
|
||||
ARRAY_JSON,
|
||||
};
|
||||
|
||||
Type _type = Type::SET_FIXED_VALUE;
|
||||
Action _action = Action::SET_VALUE;
|
||||
std::weak_ptr<Variable> _variable;
|
||||
std::weak_ptr<Variable> _variable2;
|
||||
StringVariable _strValue = "";
|
||||
double _numValue = 0;
|
||||
int _subStringStart = 0;
|
||||
int _subStringSize = 0;
|
||||
DoubleVariable _numValue = 0;
|
||||
IntVariable _subStringStart = 0;
|
||||
IntVariable _subStringSize = 0;
|
||||
RegexConfig _subStringRegex = RegexConfig::PartialMatchRegexConfig();
|
||||
std::string _regexPattern = ".*";
|
||||
int _regexMatchIdx = 0;
|
||||
IntVariable _regexMatchIdx = 0;
|
||||
RegexConfig _findRegex;
|
||||
StringVariable _findStr = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.findAndReplace.find");
|
||||
@@ -99,6 +102,12 @@ public:
|
||||
};
|
||||
|
||||
CaseType _caseType = CaseType::LOWER_CASE;
|
||||
DoubleVariable _randomNumberStart = 0;
|
||||
DoubleVariable _randomNumberEnd = 100;
|
||||
bool _generateInteger = true;
|
||||
|
||||
StringVariable _jsonQuery = "$.some.nested.value";
|
||||
IntVariable _jsonIndex = 0;
|
||||
|
||||
private:
|
||||
void DecrementCurrentSegmentVariableRef();
|
||||
@@ -108,6 +117,7 @@ private:
|
||||
void HandleMathExpression(Variable *);
|
||||
void HandleCaseChange(Variable *);
|
||||
void SetToSceneItemName(Variable *);
|
||||
void GenerateRandomNumber(Variable *);
|
||||
|
||||
std::weak_ptr<MacroSegment> _macroSegment;
|
||||
int _segmentIdxLoadValue = -1;
|
||||
@@ -136,15 +146,15 @@ private slots:
|
||||
void Variable2Changed(const QString &);
|
||||
void ActionChanged(int);
|
||||
void StrValueChanged();
|
||||
void NumValueChanged(double);
|
||||
void NumValueChanged(const NumberVariable<double> &value);
|
||||
void SegmentIndexChanged(const IntVariable &);
|
||||
void UpdateSegmentVariableValue();
|
||||
void MacroSegmentOrderChanged();
|
||||
void SubStringStartChanged(int val);
|
||||
void SubStringSizeChanged(int val);
|
||||
void SubStringStartChanged(const NumberVariable<int> &start);
|
||||
void SubStringSizeChanged(const NumberVariable<int> &size);
|
||||
void SubStringRegexChanged(const RegexConfig &conf);
|
||||
void RegexPatternChanged();
|
||||
void RegexMatchIdxChanged(int val);
|
||||
void RegexMatchIdxChanged(const NumberVariable<int> &index);
|
||||
void FindStrValueChanged();
|
||||
void FindRegexChanged(const RegexConfig &conf);
|
||||
void ReplaceStrValueChanged();
|
||||
@@ -161,6 +171,11 @@ private slots:
|
||||
void StringLengthChanged(const NumberVariable<int> &);
|
||||
void CharSelectionChanged(const QString &);
|
||||
void CaseTypeChanged(int index);
|
||||
void RandomNumberStartChanged(const NumberVariable<double> &);
|
||||
void RandomNumberEndChanged(const NumberVariable<double> &);
|
||||
void GenerateIntegerChanged(int);
|
||||
void JsonQueryChanged();
|
||||
void JsonIndexChanged(const NumberVariable<int> &);
|
||||
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
@@ -173,18 +188,18 @@ private:
|
||||
VariableSelection *_variables2;
|
||||
FilterComboBox *_actions;
|
||||
VariableTextEdit *_strValue;
|
||||
QDoubleSpinBox *_numValue;
|
||||
VariableDoubleSpinBox *_numValue;
|
||||
MacroSegmentSelection *_segmentIdx;
|
||||
QLabel *_segmentValueStatus;
|
||||
ResizingPlainTextEdit *_segmentValue;
|
||||
QVBoxLayout *_substringLayout;
|
||||
QHBoxLayout *_subStringIndexEntryLayout;
|
||||
QHBoxLayout *_subStringRegexEntryLayout;
|
||||
QSpinBox *_subStringStart;
|
||||
QSpinBox *_subStringSize;
|
||||
VariableSpinBox *_subStringStart;
|
||||
VariableSpinBox *_subStringSize;
|
||||
RegexConfigWidget *_substringRegex;
|
||||
ResizingPlainTextEdit *_regexPattern;
|
||||
QSpinBox *_regexMatchIdx;
|
||||
VariableSpinBox *_regexMatchIdx;
|
||||
QHBoxLayout *_findReplaceLayout;
|
||||
RegexConfigWidget *_findRegex;
|
||||
VariableTextEdit *_findStr;
|
||||
@@ -206,6 +221,13 @@ private:
|
||||
VariableSpinBox *_stringLength;
|
||||
SingleCharSelection *_paddingCharSelection;
|
||||
FilterComboBox *_caseType;
|
||||
VariableDoubleSpinBox *_randomNumberStart;
|
||||
VariableDoubleSpinBox *_randomNumberEnd;
|
||||
QCheckBox *_generateInteger;
|
||||
QVBoxLayout *_randomLayout;
|
||||
VariableLineEdit *_jsonQuery;
|
||||
QLabel *_jsonQueryHelp;
|
||||
VariableSpinBox *_jsonIndex;
|
||||
QHBoxLayout *_entryLayout;
|
||||
|
||||
std::shared_ptr<MacroActionVariable> _entryData;
|
||||
|
||||
@@ -11,15 +11,12 @@ bool MacroAction::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroSegment::Save(obj);
|
||||
obs_data_set_string(obj, "id", GetId().c_str());
|
||||
obs_data_set_bool(obj, "enabled", _enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroAction::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroSegment::Load(obj);
|
||||
obs_data_set_default_bool(obj, "enabled", true);
|
||||
_enabled = obs_data_get_bool(obj, "enabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -28,16 +25,6 @@ void MacroAction::LogAction() const
|
||||
ablog(LOG_INFO, "performed action %s", GetId().c_str());
|
||||
}
|
||||
|
||||
void MacroAction::SetEnabled(bool value)
|
||||
{
|
||||
_enabled = value;
|
||||
}
|
||||
|
||||
bool MacroAction::Enabled() const
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
void MacroAction::ResolveVariablesToFixedValues() {}
|
||||
|
||||
std::string_view MacroAction::GetDefaultID()
|
||||
|
||||
@@ -19,13 +19,9 @@ public:
|
||||
// Used to resolve variables before actions are added to action queues
|
||||
virtual void ResolveVariablesToFixedValues();
|
||||
|
||||
void SetEnabled(bool);
|
||||
bool Enabled() const;
|
||||
|
||||
static std::string_view GetDefaultID();
|
||||
|
||||
private:
|
||||
bool _enabled = true;
|
||||
};
|
||||
|
||||
class EXPORT MacroRefAction : virtual public MacroAction {
|
||||
|
||||
@@ -138,7 +138,7 @@ MacroConditionEdit::MacroConditionEdit(
|
||||
mainLayout->addWidget(_frame);
|
||||
setLayout(mainLayout);
|
||||
|
||||
UpdateEntryData(id);
|
||||
SetupWidgets(true);
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
@@ -152,9 +152,11 @@ void MacroConditionEdit::LogicSelectionChanged(int idx)
|
||||
const auto logic = static_cast<Logic::Type>(
|
||||
_logicSelection->itemData(idx).toInt());
|
||||
(*_entryData)->SetLogicType(logic);
|
||||
|
||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||
}
|
||||
|
||||
bool MacroConditionEdit::IsRootNode()
|
||||
bool MacroConditionEdit::IsRootNode() const
|
||||
{
|
||||
return _isRoot;
|
||||
}
|
||||
@@ -164,6 +166,7 @@ void MacroConditionEdit::SetLogicSelection()
|
||||
const auto logic = (*_entryData)->GetLogicType();
|
||||
_logicSelection->setCurrentIndex(
|
||||
_logicSelection->findData(static_cast<int>(logic)));
|
||||
SetEnableAppearance(logic != Logic::Type::NONE);
|
||||
}
|
||||
|
||||
void MacroConditionEdit::SetRootNode(bool root)
|
||||
@@ -175,23 +178,36 @@ void MacroConditionEdit::SetRootNode(bool root)
|
||||
SetLogicSelection();
|
||||
}
|
||||
|
||||
void MacroConditionEdit::UpdateEntryData(const std::string &id)
|
||||
void MacroConditionEdit::SetupWidgets(bool basicSetup)
|
||||
{
|
||||
if (_allWidgetsAreSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto id = (*_entryData)->GetId();
|
||||
_conditionSelection->setCurrentText(obs_module_text(
|
||||
MacroConditionFactory::GetConditionName(id).c_str()));
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
|
||||
HeaderInfoChanged(
|
||||
QString::fromStdString((*_entryData)->GetShortDesc()));
|
||||
SetLogicSelection();
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
|
||||
_dur->setVisible(MacroConditionFactory::UsesDurationModifier(id));
|
||||
auto modifier = (*_entryData)->GetDurationModifier();
|
||||
_dur->SetValue(modifier);
|
||||
|
||||
if (basicSetup) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
_section->SetContent(widget, (*_entryData)->GetCollapsed());
|
||||
SetFocusPolicyOfWidgets();
|
||||
|
||||
_allWidgetsAreSetup = true;
|
||||
}
|
||||
|
||||
void MacroConditionEdit::SetEntryData(std::shared_ptr<MacroCondition> *data)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include <QPushButton>
|
||||
#include <QHBoxLayout>
|
||||
#include <QTimer>
|
||||
#include <QListWidget>
|
||||
|
||||
namespace advss {
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@ bool MacroConditionQueue::CheckCondition()
|
||||
return false;
|
||||
}
|
||||
|
||||
SetTempVarValue("size", std::to_string(queue->Size()));
|
||||
SetTempVarValue("running", queue->IsRunning());
|
||||
|
||||
switch (_condition) {
|
||||
case Condition::STARTED:
|
||||
return queue->IsRunning();
|
||||
@@ -63,6 +66,18 @@ std::string MacroConditionQueue::GetShortDesc() const
|
||||
return GetActionQueueName(_queue);
|
||||
}
|
||||
|
||||
void MacroConditionQueue::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
AddTempvar("size",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.queue.size"));
|
||||
AddTempvar(
|
||||
"running",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.queue.running"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.queue.running.description"));
|
||||
}
|
||||
|
||||
static inline void populateQueueTypeSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[_, name] : conditionTypes) {
|
||||
@@ -141,6 +156,7 @@ void MacroConditionQueueEdit::UpdateEntryData()
|
||||
}
|
||||
_conditions->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||
_queues->SetActionQueue(_entryData->_queue);
|
||||
_size->SetValue(_entryData->_size);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ public:
|
||||
IntVariable _size = 1;
|
||||
|
||||
private:
|
||||
void SetupTempVars();
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
@@ -8,10 +8,14 @@ namespace advss {
|
||||
MacroConditionScript::MacroConditionScript(
|
||||
Macro *m, const std::string &id, const OBSData &defaultSettings,
|
||||
const std::string &propertiesSignalName,
|
||||
const std::string &triggerSignal, const std::string &completionSignal)
|
||||
const std::string &triggerSignalName,
|
||||
const std::string &completionSignalName,
|
||||
const std::string &newInstanceSignalName,
|
||||
const std::string &deletedInstanceSignalName)
|
||||
: MacroCondition(m),
|
||||
MacroSegmentScript(defaultSettings, propertiesSignalName,
|
||||
triggerSignal, completionSignal),
|
||||
triggerSignalName, completionSignalName,
|
||||
newInstanceSignalName, deletedInstanceSignalName),
|
||||
_id(id)
|
||||
{
|
||||
}
|
||||
@@ -76,4 +80,29 @@ void MacroConditionScript::WaitForCompletion() const
|
||||
}
|
||||
}
|
||||
|
||||
void MacroConditionScript::RegisterTempVarHelper(const std::string &variableId,
|
||||
const std::string &name,
|
||||
const std::string &helpText)
|
||||
{
|
||||
AddTempvar(variableId, name, helpText);
|
||||
}
|
||||
|
||||
void MacroConditionScript::DeregisterAllTempVarsHelper()
|
||||
{
|
||||
MacroSegment::SetupTempVars();
|
||||
}
|
||||
|
||||
void MacroConditionScript::SetTempVarValueHelper(const std::string &variableId,
|
||||
const std::string &value)
|
||||
{
|
||||
MacroCondition::SetTempVarValue(variableId, value);
|
||||
}
|
||||
|
||||
void MacroConditionScript::SetupTempVars()
|
||||
{
|
||||
// This just exists so MacroSegment::SetupTempVars() is not called.
|
||||
// We want the ScriptHandler to handle the registration and clearing of
|
||||
// the temp vars.
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -10,8 +10,10 @@ public:
|
||||
MacroConditionScript(Macro *m, const std::string &id,
|
||||
const OBSData &defaultSettings,
|
||||
const std::string &propertiesSignalName,
|
||||
const std::string &triggerSignal,
|
||||
const std::string &signalComplete);
|
||||
const std::string &triggerSignalName,
|
||||
const std::string &completionSignalName,
|
||||
const std::string &newInstanceSignalName,
|
||||
const std::string &deletedInstanceSignalName);
|
||||
MacroConditionScript(const advss::MacroConditionScript &);
|
||||
bool CheckCondition();
|
||||
bool Save(obs_data_t *obj) const;
|
||||
@@ -20,6 +22,13 @@ public:
|
||||
|
||||
private:
|
||||
void WaitForCompletion() const;
|
||||
void RegisterTempVarHelper(const std::string &variableId,
|
||||
const std::string &name,
|
||||
const std::string &helpText);
|
||||
void DeregisterAllTempVarsHelper();
|
||||
void SetTempVarValueHelper(const std::string &variableId,
|
||||
const std::string &value);
|
||||
void SetupTempVars();
|
||||
|
||||
std::string _id = "";
|
||||
};
|
||||
|
||||
@@ -67,9 +67,7 @@ void SetMacroSwitchedScene(bool value)
|
||||
{
|
||||
static bool setupDone = false;
|
||||
if (!setupDone) {
|
||||
// Will always be called with switcher lock already held
|
||||
AddIntervalResetStep([]() { macroSceneSwitched = false; },
|
||||
false);
|
||||
AddIntervalResetStep([]() { macroSceneSwitched = false; });
|
||||
setupDone = true;
|
||||
}
|
||||
macroSceneSwitched = value;
|
||||
@@ -80,35 +78,43 @@ bool MacroSwitchedScene()
|
||||
return macroSceneSwitched;
|
||||
}
|
||||
|
||||
std::string GetMacroName(Macro *macro)
|
||||
std::string GetMacroName(const Macro *macro)
|
||||
{
|
||||
return macro ? macro->Name() : "";
|
||||
}
|
||||
|
||||
std::chrono::high_resolution_clock::time_point
|
||||
LastMacroConditionCheckTime(Macro *macro)
|
||||
LastMacroConditionCheckTime(const Macro *macro)
|
||||
{
|
||||
return macro ? macro->LastConditionCheckTime()
|
||||
: std::chrono::high_resolution_clock::time_point{};
|
||||
}
|
||||
|
||||
bool MacroIsStopped(Macro *macro)
|
||||
bool MacroIsStopped(const Macro *macro)
|
||||
{
|
||||
return macro ? macro->GetStop() : true;
|
||||
}
|
||||
|
||||
bool MacroIsPaused(Macro *macro)
|
||||
bool MacroIsPaused(const Macro *macro)
|
||||
{
|
||||
return macro ? macro->Paused() : true;
|
||||
}
|
||||
|
||||
bool MacroWasPausedSince(
|
||||
Macro *macro,
|
||||
const Macro *macro,
|
||||
const std::chrono::high_resolution_clock::time_point &time)
|
||||
{
|
||||
return macro ? macro->WasPausedSince(time) : false;
|
||||
}
|
||||
|
||||
bool MacroWasCheckedSinceLastStart(const Macro *macro)
|
||||
{
|
||||
if (!macro) {
|
||||
return false;
|
||||
}
|
||||
return macro->LastConditionCheckTime().time_since_epoch().count() != 0;
|
||||
}
|
||||
|
||||
void AddMacroHelperThread(Macro *macro, std::thread &&newThread)
|
||||
{
|
||||
if (!macro) {
|
||||
@@ -138,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,16 +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(const Macro *);
|
||||
|
||||
EXPORT void AddMacroHelperThread(Macro *, std::thread &&);
|
||||
|
||||
@@ -67,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
|
||||
|
||||
@@ -181,15 +181,7 @@ void MacroInputEdit::SetInputVariablesAndValues(
|
||||
_variables = inputs;
|
||||
_values = values;
|
||||
if ((size_t)_values.size() < _variables._inputVariables.size()) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
for (int i = 0;
|
||||
_variables._inputVariables.size() - (size_t)_values.size();
|
||||
i++) {
|
||||
_values.push_back({});
|
||||
}
|
||||
#else
|
||||
_values.resize(_variables._inputVariables.size());
|
||||
#endif
|
||||
}
|
||||
SetupWidgets();
|
||||
}
|
||||
@@ -199,7 +191,7 @@ bool MacroInputEdit::HasInputsToSet() const
|
||||
return !_variables._inputVariables.empty();
|
||||
}
|
||||
|
||||
void HighligthMacroSettingsButton(bool enable);
|
||||
void HighlightMacroSettingsButton(bool enable);
|
||||
|
||||
void MacroInputEdit::SetupWidgets()
|
||||
{
|
||||
|
||||
@@ -29,6 +29,10 @@ static constexpr std::string_view defaultSettingsParam = "default_settings";
|
||||
static constexpr std::string_view propertiesSignalParam =
|
||||
"properties_signal_name";
|
||||
static constexpr std::string_view triggerSignalParam = "trigger_signal_name";
|
||||
static constexpr std::string_view newInstanceSignalNameParam =
|
||||
"new_instance_signal_name";
|
||||
static constexpr std::string_view deletedInstanceSignalNameParam =
|
||||
"deleted_instance_signal_name";
|
||||
|
||||
static std::string getRegisterScriptSegmentDeclString(const char *funcName)
|
||||
{
|
||||
@@ -72,16 +76,55 @@ static const std::string deregisterScriptConditionDeclString =
|
||||
/* Script variables */
|
||||
|
||||
static constexpr std::string_view valueParam = "value";
|
||||
static constexpr std::string_view tempVarIdParam = "temp_var_id";
|
||||
static constexpr std::string_view tempVarNameParam = "temp_var_name";
|
||||
static constexpr std::string_view tempVarHelpParam = "temp_var_help";
|
||||
static constexpr std::string_view getVariableValueFuncName =
|
||||
"advss_get_variable_value";
|
||||
static constexpr std::string_view setVariableValueFuncName =
|
||||
"advss_set_variable_value";
|
||||
static constexpr std::string_view registerTempVarFuncName =
|
||||
"advss_register_temp_var";
|
||||
static constexpr std::string_view deregisterAllTempVarsFuncName =
|
||||
"advss_deregister_temp_vars";
|
||||
static constexpr std::string_view setTempVarValueFuncName =
|
||||
"advss_set_temp_var_value";
|
||||
static const std::string getVariableValueDeclString =
|
||||
std::string("bool ") + getVariableValueFuncName.data() + "(in string " +
|
||||
nameParam.data() + ", out string " + valueParam.data() + ")";
|
||||
static const std::string setVariableValueDeclString =
|
||||
std::string("bool ") + setVariableValueFuncName.data() + "(in string " +
|
||||
nameParam.data() + ", in string " + valueParam.data() + ")";
|
||||
static const std::string registerTempVarDeclString =
|
||||
std::string("bool ") + registerTempVarFuncName.data() + "(in string " +
|
||||
tempVarIdParam.data() + ", in string " + tempVarNameParam.data() +
|
||||
", in string " + tempVarHelpParam.data() + ", in int " +
|
||||
GetInstanceIdParamName().data() + ")";
|
||||
static const std::string deregisterAllTempVarsDeclString =
|
||||
std::string("bool ") + deregisterAllTempVarsFuncName.data() +
|
||||
"(in int " + GetInstanceIdParamName().data() + ")";
|
||||
static const std::string setTempVarValueDeclString =
|
||||
std::string("bool ") + setTempVarValueFuncName.data() + "(in string " +
|
||||
tempVarIdParam.data() + ", in string " + valueParam.data() +
|
||||
", in int " + GetInstanceIdParamName().data() + ")";
|
||||
|
||||
/* Plugin status */
|
||||
|
||||
static constexpr std::string_view stopSignalName = "advss_plugin_stopped";
|
||||
static constexpr std::string_view startSignalName = "advss_plugin_started";
|
||||
static constexpr std::string_view getRunningStatusFuncName =
|
||||
"advss_plugin_running";
|
||||
static constexpr std::string_view resetIntervalSignalName =
|
||||
"advss_interval_reset";
|
||||
|
||||
static const std::string stopSignalDeclString =
|
||||
std::string("void ") + stopSignalName.data() + "()";
|
||||
static const std::string startSignalDeclString =
|
||||
std::string("void ") + startSignalName.data() + "()";
|
||||
static const std::string resetIntervalDeclString =
|
||||
std::string("void ") + resetIntervalSignalName.data() + "()";
|
||||
static const std::string getRunningStatusDeclString =
|
||||
std::string("bool ") + getRunningStatusFuncName.data() + "()";
|
||||
|
||||
static bool setup();
|
||||
static bool setupDone = setup();
|
||||
@@ -103,13 +146,42 @@ static bool setup()
|
||||
&ScriptHandler::GetVariableValue, nullptr);
|
||||
proc_handler_add(ph, setVariableValueDeclString.c_str(),
|
||||
&ScriptHandler::SetVariableValue, nullptr);
|
||||
proc_handler_add(ph, registerTempVarDeclString.c_str(),
|
||||
&ScriptHandler::RegisterTempVar, nullptr);
|
||||
proc_handler_add(ph, deregisterAllTempVarsDeclString.c_str(),
|
||||
&ScriptHandler::DeregisterAllTempVars, nullptr);
|
||||
proc_handler_add(ph, setTempVarValueDeclString.c_str(),
|
||||
&ScriptHandler::SetTempVarValue, nullptr);
|
||||
proc_handler_add(ph, getRunningStatusDeclString.c_str(),
|
||||
&ScriptHandler::GetRunningStatus, nullptr);
|
||||
|
||||
auto sh = obs_get_signal_handler();
|
||||
signal_handler_add(sh, stopSignalDeclString.c_str());
|
||||
signal_handler_add(sh, startSignalDeclString.c_str());
|
||||
signal_handler_add(sh, resetIntervalDeclString.c_str());
|
||||
|
||||
static constexpr auto triggerSignal = [](const std::string_view &name) {
|
||||
auto sh = obs_get_signal_handler();
|
||||
struct calldata data;
|
||||
calldata_init(&data);
|
||||
signal_handler_signal(sh, name.data(), &data);
|
||||
calldata_free(&data);
|
||||
};
|
||||
|
||||
AddIntervalResetStep([]() { triggerSignal(resetIntervalSignalName); });
|
||||
AddStartStep([]() { triggerSignal(startSignalName); });
|
||||
AddStopStep([]() { triggerSignal(stopSignalName); });
|
||||
return true;
|
||||
}
|
||||
|
||||
static void replaceWhitespace(std::string &string)
|
||||
static void replaceProblematicChars(std::string &string)
|
||||
{
|
||||
std::transform(string.begin(), string.end(), string.begin(), [](char c) {
|
||||
return std::isspace(static_cast<unsigned char>(c)) ? '_' : c;
|
||||
if (std::isspace(static_cast<unsigned char>(c)) || c == '(' ||
|
||||
c == ')' || c == '[' || c == ']' || c == '{' || c == '}') {
|
||||
return '_';
|
||||
}
|
||||
return c;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -122,7 +194,7 @@ static std::string getTriggerSignal(const std::string &name,
|
||||
const bool isAction)
|
||||
{
|
||||
std::string signal = name;
|
||||
replaceWhitespace(signal);
|
||||
replaceProblematicChars(signal);
|
||||
signal += "_run";
|
||||
signal += isAction ? "_action" : "_condition";
|
||||
return signal;
|
||||
@@ -140,12 +212,32 @@ static std::string getPropertiesSignal(const std::string &name,
|
||||
const bool isAction)
|
||||
{
|
||||
std::string signal = name;
|
||||
replaceWhitespace(signal);
|
||||
replaceProblematicChars(signal);
|
||||
signal += isAction ? "_action" : "_condition";
|
||||
signal += "_get_properties";
|
||||
return signal;
|
||||
}
|
||||
|
||||
static std::string getNewInstanceSignal(const std::string &name,
|
||||
const bool isAction)
|
||||
{
|
||||
std::string signal = name;
|
||||
replaceProblematicChars(signal);
|
||||
signal += isAction ? "_action" : "_condition";
|
||||
signal += "_new_instance";
|
||||
return signal;
|
||||
}
|
||||
|
||||
static std::string getDeletedInstanceSignal(const std::string &name,
|
||||
const bool isAction)
|
||||
{
|
||||
std::string signal = name;
|
||||
replaceProblematicChars(signal);
|
||||
signal += isAction ? "_action" : "_condition";
|
||||
signal += "_deleted_instance";
|
||||
return signal;
|
||||
}
|
||||
|
||||
void ScriptHandler::RegisterScriptAction(void *, calldata_t *data)
|
||||
{
|
||||
const char *actionName;
|
||||
@@ -177,14 +269,19 @@ void ScriptHandler::RegisterScriptAction(void *, calldata_t *data)
|
||||
auto triggerSignalName = getTriggerSignal(actionName, true);
|
||||
auto completionSignalName = getCompletionSignal(actionName, true);
|
||||
auto propertiesSignalName = getPropertiesSignal(actionName, true);
|
||||
auto newInstanceSignalName = getNewInstanceSignal(actionName, true);
|
||||
auto deletedInstanceSignalName =
|
||||
getDeletedInstanceSignal(actionName, true);
|
||||
|
||||
const auto createScriptAction =
|
||||
[id, defaultSettings, propertiesSignalName, triggerSignalName,
|
||||
completionSignalName](
|
||||
completionSignalName, newInstanceSignalName,
|
||||
deletedInstanceSignalName](
|
||||
Macro *m) -> std::shared_ptr<MacroAction> {
|
||||
return std::make_shared<MacroActionScript>(
|
||||
m, id, defaultSettings, propertiesSignalName,
|
||||
triggerSignalName, completionSignalName);
|
||||
triggerSignalName, completionSignalName,
|
||||
newInstanceSignalName, deletedInstanceSignalName);
|
||||
};
|
||||
if (!MacroActionFactory::Register(id, {createScriptAction,
|
||||
MacroSegmentScriptEdit::Create,
|
||||
@@ -202,9 +299,15 @@ void ScriptHandler::RegisterScriptAction(void *, calldata_t *data)
|
||||
triggerSignalName.c_str());
|
||||
calldata_set_string(data, propertiesSignalParam.data(),
|
||||
propertiesSignalName.c_str());
|
||||
calldata_set_string(data, newInstanceSignalNameParam.data(),
|
||||
newInstanceSignalName.c_str());
|
||||
calldata_set_string(data, deletedInstanceSignalNameParam.data(),
|
||||
deletedInstanceSignalName.c_str());
|
||||
_actions.emplace(id, ScriptSegmentType(id, propertiesSignalName,
|
||||
triggerSignalName,
|
||||
completionSignalName));
|
||||
completionSignalName,
|
||||
newInstanceSignalName,
|
||||
deletedInstanceSignalName));
|
||||
|
||||
RETURN_SUCCESS();
|
||||
}
|
||||
@@ -279,14 +382,19 @@ void ScriptHandler::RegisterScriptCondition(void *, calldata_t *data)
|
||||
auto triggerSignalName = getTriggerSignal(conditionName, false);
|
||||
auto completionSignalName = getCompletionSignal(conditionName, false);
|
||||
auto propertiesSignalName = getPropertiesSignal(conditionName, false);
|
||||
auto newInstanceSignalName = getNewInstanceSignal(conditionName, false);
|
||||
auto deletedInstanceSignalName =
|
||||
getDeletedInstanceSignal(conditionName, false);
|
||||
|
||||
const auto createScriptCondition =
|
||||
[id, defaultSettings, propertiesSignalName, triggerSignalName,
|
||||
completionSignalName](
|
||||
completionSignalName, newInstanceSignalName,
|
||||
deletedInstanceSignalName](
|
||||
Macro *m) -> std::shared_ptr<MacroCondition> {
|
||||
return std::make_shared<MacroConditionScript>(
|
||||
m, id, defaultSettings, propertiesSignalName,
|
||||
triggerSignalName, completionSignalName);
|
||||
triggerSignalName, completionSignalName,
|
||||
newInstanceSignalName, deletedInstanceSignalName);
|
||||
};
|
||||
if (!MacroConditionFactory::Register(
|
||||
id, {createScriptCondition, MacroSegmentScriptEdit::Create,
|
||||
@@ -304,9 +412,15 @@ void ScriptHandler::RegisterScriptCondition(void *, calldata_t *data)
|
||||
triggerSignalName.c_str());
|
||||
calldata_set_string(data, propertiesSignalParam.data(),
|
||||
propertiesSignalName.c_str());
|
||||
calldata_set_string(data, newInstanceSignalNameParam.data(),
|
||||
newInstanceSignalName.c_str());
|
||||
calldata_set_string(data, deletedInstanceSignalNameParam.data(),
|
||||
deletedInstanceSignalName.c_str());
|
||||
_conditions.emplace(id, ScriptSegmentType(id, propertiesSignalName,
|
||||
triggerSignalName,
|
||||
completionSignalName));
|
||||
completionSignalName,
|
||||
newInstanceSignalName,
|
||||
deletedInstanceSignalName));
|
||||
|
||||
RETURN_SUCCESS();
|
||||
}
|
||||
@@ -399,6 +513,97 @@ void ScriptHandler::SetVariableValue(void *, calldata_t *data)
|
||||
RETURN_SUCCESS();
|
||||
}
|
||||
|
||||
void ScriptHandler::GetRunningStatus(void *ctx, calldata_t *data)
|
||||
{
|
||||
calldata_set_bool(data, "is_running", PluginIsRunning());
|
||||
}
|
||||
|
||||
void ScriptHandler::RegisterTempVar(void *, calldata_t *data)
|
||||
{
|
||||
const char *variableId;
|
||||
if (!calldata_get_string(data, tempVarIdParam.data(), &variableId) ||
|
||||
strlen(variableId) == 0) {
|
||||
blog(LOG_WARNING, "[%s] failed! \"%s\" parameter missing!",
|
||||
registerTempVarFuncName.data(), tempVarIdParam.data());
|
||||
RETURN_FAILURE();
|
||||
}
|
||||
const char *name;
|
||||
if (!calldata_get_string(data, tempVarNameParam.data(), &name) ||
|
||||
strlen(name) == 0) {
|
||||
blog(LOG_WARNING, "[%s] failed! \"%s\" parameter missing!",
|
||||
registerTempVarFuncName.data(), tempVarNameParam.data());
|
||||
RETURN_FAILURE();
|
||||
}
|
||||
const char *helpText;
|
||||
if (!calldata_get_string(data, tempVarHelpParam.data(), &helpText)) {
|
||||
blog(LOG_WARNING, "[%s] failed! \"%s\" parameter missing!",
|
||||
registerTempVarFuncName.data(), tempVarHelpParam.data());
|
||||
RETURN_FAILURE();
|
||||
}
|
||||
long long instanceId;
|
||||
if (!calldata_get_int(data, GetInstanceIdParamName().data(),
|
||||
&instanceId)) {
|
||||
blog(LOG_WARNING, "[%s] failed! \"%s\" parameter missing!",
|
||||
registerTempVarFuncName.data(),
|
||||
GetInstanceIdParamName().data());
|
||||
RETURN_FAILURE();
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
MacroSegmentScript::RegisterTempVar(variableId, name, helpText,
|
||||
instanceId);
|
||||
RETURN_SUCCESS();
|
||||
}
|
||||
|
||||
void ScriptHandler::DeregisterAllTempVars(void *, calldata_t *data)
|
||||
{
|
||||
long long instanceId;
|
||||
if (!calldata_get_int(data, GetInstanceIdParamName().data(),
|
||||
&instanceId)) {
|
||||
blog(LOG_WARNING, "[%s] failed! \"%s\" parameter missing!",
|
||||
deregisterAllTempVarsFuncName.data(),
|
||||
GetInstanceIdParamName().data());
|
||||
RETURN_FAILURE();
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
MacroSegmentScript::DeregisterAllTempVars(instanceId);
|
||||
RETURN_SUCCESS();
|
||||
}
|
||||
|
||||
void ScriptHandler::SetTempVarValue(void *, calldata_t *data)
|
||||
{
|
||||
const char *variableId;
|
||||
if (!calldata_get_string(data, tempVarIdParam.data(), &variableId) ||
|
||||
strlen(variableId) == 0) {
|
||||
blog(LOG_WARNING, "[%s] failed! \"%s\" parameter missing!",
|
||||
setTempVarValueFuncName.data(), tempVarIdParam.data());
|
||||
RETURN_FAILURE();
|
||||
}
|
||||
|
||||
const char *variableValue;
|
||||
if (!calldata_get_string(data, valueParam.data(), &variableValue) ||
|
||||
strlen(variableValue) == 0) {
|
||||
blog(LOG_WARNING, "[%s] failed! \"%s\" parameter missing!",
|
||||
setTempVarValueFuncName.data(), valueParam.data());
|
||||
RETURN_FAILURE();
|
||||
}
|
||||
|
||||
long long instanceId;
|
||||
if (!calldata_get_int(data, GetInstanceIdParamName().data(),
|
||||
&instanceId)) {
|
||||
blog(LOG_WARNING, "[%s] failed! \"%s\" parameter missing!",
|
||||
setTempVarValueFuncName.data(),
|
||||
GetInstanceIdParamName().data());
|
||||
RETURN_FAILURE();
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
MacroSegmentScript::SetTempVarValue(variableId, variableValue,
|
||||
instanceId);
|
||||
RETURN_SUCCESS();
|
||||
}
|
||||
|
||||
bool ScriptHandler::ActionIdIsValid(const std::string &id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
@@ -424,24 +629,39 @@ static std::string signalNameToPropertiesSignalDecl(const std::string &name)
|
||||
static std::string signalNameToCompletionSignalDecl(const std::string &name)
|
||||
{
|
||||
return std::string("bool ") + name + "(in int " +
|
||||
GeCompletionIdParamName().data() + ")";
|
||||
GetCompletionIdParamName().data() + ")";
|
||||
}
|
||||
|
||||
ScriptSegmentType::ScriptSegmentType(const std::string &id,
|
||||
const std::string &propertiesSignal,
|
||||
const std::string &triggerSignal,
|
||||
const std::string &completionSignal)
|
||||
static std::string signalNameToInstanceSignalDecl(const std::string &name)
|
||||
{
|
||||
return std::string("void ") + name + "(out int " +
|
||||
GetInstanceIdParamName().data() + ")";
|
||||
}
|
||||
|
||||
ScriptSegmentType::ScriptSegmentType(
|
||||
const std::string &id, const std::string &propertiesSignalName,
|
||||
const std::string &triggerSignalName,
|
||||
const std::string &completionSignalName,
|
||||
const std::string &newInstanceSignalName,
|
||||
const std::string &deletedInstanceSignalName)
|
||||
: _id(id)
|
||||
{
|
||||
auto sh = obs_get_signal_handler();
|
||||
|
||||
signal_handler_add(
|
||||
obs_get_signal_handler(),
|
||||
signalNameToPropertiesSignalDecl(propertiesSignal).c_str());
|
||||
sh,
|
||||
signalNameToPropertiesSignalDecl(propertiesSignalName).c_str());
|
||||
signal_handler_add(
|
||||
obs_get_signal_handler(),
|
||||
signalNameToTriggerSignalDecl(triggerSignal).c_str());
|
||||
sh, signalNameToTriggerSignalDecl(triggerSignalName).c_str());
|
||||
signal_handler_add(
|
||||
obs_get_signal_handler(),
|
||||
signalNameToCompletionSignalDecl(completionSignal).c_str());
|
||||
sh,
|
||||
signalNameToCompletionSignalDecl(completionSignalName).c_str());
|
||||
signal_handler_add(
|
||||
sh,
|
||||
signalNameToInstanceSignalDecl(newInstanceSignalName).c_str());
|
||||
signal_handler_add(
|
||||
sh, signalNameToInstanceSignalDecl(deletedInstanceSignalName)
|
||||
.c_str());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -10,9 +10,11 @@ class ScriptSegmentType {
|
||||
public:
|
||||
ScriptSegmentType() = delete;
|
||||
ScriptSegmentType(const std::string &id,
|
||||
const std::string &propertiesSignal,
|
||||
const std::string &triggerSignal,
|
||||
const std::string &completionSignal);
|
||||
const std::string &propertiesSignalName,
|
||||
const std::string &triggerSignalName,
|
||||
const std::string &completionSignalName,
|
||||
const std::string &newInstanceSignalName,
|
||||
const std::string &deletedInstanceSignalName);
|
||||
|
||||
private:
|
||||
std::string _id;
|
||||
@@ -26,7 +28,11 @@ public:
|
||||
static void RegisterScriptCondition(void *ctx, calldata_t *data);
|
||||
static void DeregisterScriptCondition(void *ctx, calldata_t *data);
|
||||
static void GetVariableValue(void *ctx, calldata_t *data);
|
||||
static void RegisterTempVar(void *ctx, calldata_t *data);
|
||||
static void DeregisterAllTempVars(void *ctx, calldata_t *data);
|
||||
static void SetTempVarValue(void *ctx, calldata_t *data);
|
||||
static void SetVariableValue(void *ctx, calldata_t *data);
|
||||
static void GetRunningStatus(void *ctx, calldata_t *data);
|
||||
static bool ActionIdIsValid(const std::string &id);
|
||||
static bool ConditionIdIsValid(const std::string &id);
|
||||
|
||||
@@ -46,14 +52,19 @@ static constexpr std::string_view GetActionCompletionSignalParamName()
|
||||
return "completion_signal_name";
|
||||
}
|
||||
|
||||
static constexpr std::string_view GeCompletionIdParamName()
|
||||
static constexpr std::string_view GetCompletionIdParamName()
|
||||
{
|
||||
return "completion_id";
|
||||
}
|
||||
|
||||
static constexpr std::string_view GeResultSignalParamName()
|
||||
static constexpr std::string_view GetResultSignalParamName()
|
||||
{
|
||||
return "result";
|
||||
}
|
||||
|
||||
static constexpr std::string_view GetInstanceIdParamName()
|
||||
{
|
||||
return "instance_id";
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
bool MacroSegmentList::_useCache = true;
|
||||
|
||||
MacroSegmentList::MacroSegmentList(QWidget *parent)
|
||||
: QScrollArea(parent),
|
||||
_layout(new QVBoxLayout),
|
||||
@@ -35,14 +37,28 @@ MacroSegmentList::MacroSegmentList(QWidget *parent)
|
||||
setWidget(wrapper);
|
||||
setWidgetResizable(true);
|
||||
setAcceptDrops(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();
|
||||
}
|
||||
|
||||
for (const auto &[_, widgets] : _widgetCache) {
|
||||
clearWidgetVector(widgets);
|
||||
}
|
||||
}
|
||||
|
||||
static bool posIsInScrollbar(const QScrollBar *scrollbar, const QPoint &pos)
|
||||
@@ -53,7 +69,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);
|
||||
@@ -98,16 +114,18 @@ void MacroSegmentList::SetHelpMsgVisible(bool visible) const
|
||||
_helpMsg->setVisible(visible);
|
||||
}
|
||||
|
||||
void MacroSegmentList::Insert(int idx, MacroSegmentEdit *widget)
|
||||
void MacroSegmentList::Insert(int idx, QWidget *widget)
|
||||
{
|
||||
widget->installEventFilter(this);
|
||||
_contentLayout->insertWidget(idx, widget);
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
}
|
||||
|
||||
void MacroSegmentList::Add(QWidget *widget)
|
||||
{
|
||||
widget->installEventFilter(this);
|
||||
_contentLayout->addWidget(widget);
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
}
|
||||
|
||||
void MacroSegmentList::Remove(int idx) const
|
||||
@@ -120,6 +138,63 @@ void MacroSegmentList::Clear(int idx) const
|
||||
ClearLayout(_contentLayout, idx);
|
||||
}
|
||||
|
||||
void MacroSegmentList::SetCachingEnabled(bool enable)
|
||||
{
|
||||
_useCache = enable;
|
||||
}
|
||||
|
||||
void MacroSegmentList::CacheCurrentWidgetsFor(const Macro *macro)
|
||||
{
|
||||
if (!_useCache) {
|
||||
_widgetCache.clear();
|
||||
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) {
|
||||
_widgetCache.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = _widgetCache.find(macro);
|
||||
if (it == _widgetCache.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto widget : it->second) {
|
||||
_contentLayout->addWidget(widget);
|
||||
widget->show();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
auto item = _contentLayout->itemAt(idx);
|
||||
@@ -178,11 +253,7 @@ void MacroSegmentList::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton ||
|
||||
event->button() == Qt::RightButton) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
_dragPosition = GetDragIndex(event->globalPos());
|
||||
#else
|
||||
_dragPosition = GetDragIndex(event->globalPosition().toPoint());
|
||||
#endif
|
||||
emit SelectionChanged(_dragPosition);
|
||||
} else {
|
||||
_dragPosition = -1;
|
||||
@@ -300,11 +371,7 @@ void MacroSegmentList::dragMoveEvent(QDragMoveEvent *event)
|
||||
return;
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
_dragCursorPos = (mapToGlobal(event->pos()));
|
||||
#else
|
||||
_dragCursorPos = (mapToGlobal(event->position().toPoint()));
|
||||
#endif
|
||||
CheckDropLine(_dragCursorPos);
|
||||
}
|
||||
|
||||
@@ -330,6 +397,36 @@ QRect MacroSegmentList::GetContentItemRectWithPadding(int idx) const
|
||||
return rect;
|
||||
}
|
||||
|
||||
void MacroSegmentList::SetVisibilityCheckEnable(bool enable)
|
||||
{
|
||||
_checkVisibility = enable;
|
||||
|
||||
if (_checkVisibility) {
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
int MacroSegmentList::GetSegmentIndexFromPos(const QPoint &pos) const
|
||||
{
|
||||
int idx = -1;
|
||||
@@ -450,16 +547,6 @@ void MacroSegmentList::dropEvent(QDropEvent *event)
|
||||
{
|
||||
HideLastDropLine();
|
||||
auto widget = qobject_cast<QWidget *>(event->source());
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
if (widget && !widget->geometry().contains(event->pos()) &&
|
||||
widgetIsInLayout(widget, _contentLayout)) {
|
||||
int dropPosition = GetDropIndex(mapToGlobal(event->pos()));
|
||||
if (dropPosition == -1) {
|
||||
return;
|
||||
}
|
||||
emit Reorder(dropPosition, _dragPosition);
|
||||
}
|
||||
#else
|
||||
if (widget &&
|
||||
!widget->geometry().contains(event->position().toPoint()) &&
|
||||
widgetIsInLayout(widget, _contentLayout)) {
|
||||
@@ -470,8 +557,13 @@ void MacroSegmentList::dropEvent(QDropEvent *event)
|
||||
}
|
||||
emit Reorder(dropPosition, _dragPosition);
|
||||
}
|
||||
#endif
|
||||
_dragPosition = -1;
|
||||
}
|
||||
|
||||
void MacroSegmentList::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QScrollArea::resizeEvent(event);
|
||||
SetupVisibleMacroSegmentWidgets();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -9,25 +9,32 @@
|
||||
|
||||
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;
|
||||
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
|
||||
static void SetCachingEnabled(bool enable);
|
||||
void CacheCurrentWidgetsFor(const Macro *);
|
||||
bool PopulateWidgetsFromCache(const Macro *);
|
||||
void ClearWidgetsFromCacheFor(const Macro *);
|
||||
void Highlight(int idx, QColor color = QColor(Qt::green));
|
||||
void SetCollapsed(bool) const;
|
||||
void SetSelection(int idx) const;
|
||||
QVBoxLayout *ContentLayout() const { return _contentLayout; }
|
||||
void SetVisibilityCheckEnable(bool enable);
|
||||
|
||||
signals:
|
||||
void SelectionChanged(int idx);
|
||||
@@ -42,8 +49,10 @@ protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
void dragMoveEvent(QDragMoveEvent *event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
|
||||
private:
|
||||
void SetupVisibleMacroSegmentWidgets();
|
||||
int GetSegmentIndexFromPos(const QPoint &) const;
|
||||
int GetDragIndex(const QPoint &) const;
|
||||
int GetDropIndex(const QPoint &) const;
|
||||
@@ -62,6 +71,11 @@ private:
|
||||
QVBoxLayout *_layout;
|
||||
QVBoxLayout *_contentLayout;
|
||||
QLabel *_helpMsg;
|
||||
|
||||
bool _checkVisibility = true;
|
||||
|
||||
static bool _useCache;
|
||||
std::unordered_map<const Macro *, std::vector<QWidget *>> _widgetCache;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -11,33 +11,106 @@
|
||||
namespace advss {
|
||||
|
||||
static std::atomic_int completionIdCounter = 0;
|
||||
static std::atomic_int instanceIdCounter = 0;
|
||||
static std::mutex instanceMtx;
|
||||
static std::vector<MacroSegmentScript *> instances{};
|
||||
|
||||
MacroSegmentScript::MacroSegmentScript(obs_data_t *defaultSettings,
|
||||
const std::string &propertiesSignalName,
|
||||
const std::string &triggerSignal,
|
||||
const std::string &completionSignal)
|
||||
MacroSegmentScript::MacroSegmentScript(
|
||||
obs_data_t *defaultSettings, const std::string &propertiesSignalName,
|
||||
const std::string &triggerSignalName,
|
||||
const std::string &completionSignalName,
|
||||
const std::string &newInstanceSignalName,
|
||||
const std::string &deletedInstanceSignalName)
|
||||
: _settings(obs_data_get_defaults(defaultSettings)),
|
||||
_propertiesSignal(propertiesSignalName),
|
||||
_triggerSignal(triggerSignal),
|
||||
_completionSignal(completionSignal)
|
||||
_triggerSignal(triggerSignalName),
|
||||
_completionSignal(completionSignalName),
|
||||
_newInstanceSignal(newInstanceSignalName),
|
||||
_deletedInstanceSignal(deletedInstanceSignalName),
|
||||
_instanceId(++instanceIdCounter)
|
||||
{
|
||||
signal_handler_connect(obs_get_signal_handler(),
|
||||
completionSignal.c_str(),
|
||||
completionSignalName.c_str(),
|
||||
&MacroSegmentScript::CompletionSignalReceived,
|
||||
this);
|
||||
|
||||
std::lock_guard<std::mutex> lock(instanceMtx);
|
||||
instances.emplace_back(this);
|
||||
|
||||
SignalNewInstance();
|
||||
}
|
||||
|
||||
MacroSegmentScript::MacroSegmentScript(const MacroSegmentScript &other)
|
||||
: _settings(obs_data_create()),
|
||||
_propertiesSignal(other._propertiesSignal),
|
||||
_triggerSignal(other._triggerSignal),
|
||||
_completionSignal(other._completionSignal)
|
||||
_completionSignal(other._completionSignal),
|
||||
_newInstanceSignal(other._newInstanceSignal),
|
||||
_deletedInstanceSignal(other._deletedInstanceSignal),
|
||||
_instanceId(++instanceIdCounter)
|
||||
{
|
||||
signal_handler_connect(obs_get_signal_handler(),
|
||||
_completionSignal.c_str(),
|
||||
&MacroSegmentScript::CompletionSignalReceived,
|
||||
this);
|
||||
obs_data_apply(_settings.Get(), other._settings.Get());
|
||||
|
||||
std::lock_guard<std::mutex> lock(instanceMtx);
|
||||
instances.emplace_back(this);
|
||||
|
||||
SignalNewInstance();
|
||||
}
|
||||
|
||||
MacroSegmentScript::~MacroSegmentScript()
|
||||
{
|
||||
auto data = calldata_create();
|
||||
calldata_set_int(data, GetInstanceIdParamName().data(), _instanceId);
|
||||
signal_handler_signal(obs_get_signal_handler(),
|
||||
_deletedInstanceSignal.c_str(), data);
|
||||
calldata_destroy(data);
|
||||
|
||||
std::lock_guard<std::mutex> lock(instanceMtx);
|
||||
instances.erase(std::remove(instances.begin(), instances.end(), this),
|
||||
instances.end());
|
||||
}
|
||||
|
||||
void MacroSegmentScript::RegisterTempVar(const std::string &variableId,
|
||||
const std::string &name,
|
||||
const std::string &helpText,
|
||||
int instanceId)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(instanceMtx);
|
||||
for (auto instance : instances) {
|
||||
if (instance->_instanceId != instanceId) {
|
||||
continue;
|
||||
}
|
||||
instance->RegisterTempVarHelper(variableId, name, helpText);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSegmentScript::DeregisterAllTempVars(int instanceId)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(instanceMtx);
|
||||
for (auto instance : instances) {
|
||||
if (instance->_instanceId != instanceId) {
|
||||
continue;
|
||||
}
|
||||
instance->DeregisterAllTempVarsHelper();
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSegmentScript::SetTempVarValue(const std::string &variableId,
|
||||
const std::string &value,
|
||||
int instanceId)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(instanceMtx);
|
||||
for (auto instance : instances) {
|
||||
if (instance->_instanceId != instanceId) {
|
||||
continue;
|
||||
}
|
||||
instance->SetTempVarValueHelper(variableId, value);
|
||||
}
|
||||
}
|
||||
|
||||
bool MacroSegmentScript::Save(obs_data_t *obj) const
|
||||
@@ -85,8 +158,10 @@ bool MacroSegmentScript::SendTriggerSignal()
|
||||
auto data = calldata_create();
|
||||
calldata_set_string(data, GetActionCompletionSignalParamName().data(),
|
||||
_completionSignal.c_str());
|
||||
calldata_set_int(data, GeCompletionIdParamName().data(), _completionId);
|
||||
calldata_set_int(data, GetCompletionIdParamName().data(),
|
||||
_completionId);
|
||||
calldata_set_string(data, "settings", obs_data_get_json(GetSettings()));
|
||||
calldata_set_int(data, GetInstanceIdParamName().data(), _instanceId);
|
||||
signal_handler_signal(obs_get_signal_handler(), _triggerSignal.c_str(),
|
||||
data);
|
||||
calldata_destroy(data);
|
||||
@@ -101,18 +176,18 @@ void MacroSegmentScript::CompletionSignalReceived(void *param, calldata_t *data)
|
||||
{
|
||||
auto segment = static_cast<MacroSegmentScript *>(param);
|
||||
long long int id;
|
||||
if (!calldata_get_int(data, GeCompletionIdParamName().data(), &id)) {
|
||||
if (!calldata_get_int(data, GetCompletionIdParamName().data(), &id)) {
|
||||
blog(LOG_WARNING,
|
||||
"received completion signal without \"%s\" parameter",
|
||||
GeCompletionIdParamName().data());
|
||||
GetCompletionIdParamName().data());
|
||||
return;
|
||||
}
|
||||
bool result;
|
||||
if (!calldata_get_bool(data, GeResultSignalParamName().data(),
|
||||
if (!calldata_get_bool(data, GetResultSignalParamName().data(),
|
||||
&result)) {
|
||||
blog(LOG_WARNING,
|
||||
"received completion signal without \"%s\" parameter",
|
||||
GeResultSignalParamName().data());
|
||||
GetResultSignalParamName().data());
|
||||
return;
|
||||
}
|
||||
if (id != segment->_completionId) {
|
||||
@@ -122,6 +197,19 @@ void MacroSegmentScript::CompletionSignalReceived(void *param, calldata_t *data)
|
||||
segment->_triggerResult = result;
|
||||
}
|
||||
|
||||
void MacroSegmentScript::SignalNewInstance() const
|
||||
{
|
||||
std::thread signalNewInstanceThread([this]() {
|
||||
auto data = calldata_create();
|
||||
calldata_set_int(data, GetInstanceIdParamName().data(),
|
||||
_instanceId);
|
||||
signal_handler_signal(obs_get_signal_handler(),
|
||||
_newInstanceSignal.c_str(), data);
|
||||
calldata_destroy(data);
|
||||
});
|
||||
signalNewInstanceThread.detach();
|
||||
}
|
||||
|
||||
obs_properties_t *MacroSegmentScriptEdit::GetProperties(void *obj)
|
||||
{
|
||||
auto segmentEdit = reinterpret_cast<MacroSegmentScriptEdit *>(obj);
|
||||
|
||||
@@ -15,9 +15,20 @@ class MacroSegmentScript {
|
||||
public:
|
||||
MacroSegmentScript(obs_data_t *defaultSettings,
|
||||
const std::string &propertiesSignalName,
|
||||
const std::string &triggerSignal,
|
||||
const std::string &completionSignal);
|
||||
const std::string &triggerSignalName,
|
||||
const std::string &completionSignalName,
|
||||
const std::string &newInstanceSignalName,
|
||||
const std::string &deletedInstanceSignalName);
|
||||
MacroSegmentScript(const advss::MacroSegmentScript &);
|
||||
virtual ~MacroSegmentScript();
|
||||
|
||||
static void RegisterTempVar(const std::string &variableId,
|
||||
const std::string &name,
|
||||
const std::string &helpText,
|
||||
int instanceId);
|
||||
static void DeregisterAllTempVars(int instanceId);
|
||||
static void SetTempVarValue(const std::string &variableId,
|
||||
const std::string &value, int instanceId);
|
||||
|
||||
protected:
|
||||
bool Save(obs_data_t *obj) const;
|
||||
@@ -31,15 +42,27 @@ protected:
|
||||
double GetTimeoutSeconds() const { return _timeout.Seconds(); };
|
||||
bool TriggerIsCompleted() const { return _triggerIsComplete; }
|
||||
|
||||
virtual void RegisterTempVarHelper(const std::string &variableId,
|
||||
const std::string &name,
|
||||
const std::string &helpText) = 0;
|
||||
virtual void DeregisterAllTempVarsHelper() = 0;
|
||||
virtual void SetTempVarValueHelper(const std::string &variableId,
|
||||
const std::string &value) = 0;
|
||||
|
||||
const int64_t _instanceId;
|
||||
|
||||
private:
|
||||
virtual void WaitForCompletion() const = 0;
|
||||
static void CompletionSignalReceived(void *param, calldata_t *data);
|
||||
void SignalNewInstance() const;
|
||||
|
||||
OBSDataAutoRelease _settings;
|
||||
std::string _propertiesSignal = "";
|
||||
|
||||
std::string _triggerSignal = "";
|
||||
std::string _completionSignal = "";
|
||||
std::string _newInstanceSignal = "";
|
||||
std::string _deletedInstanceSignal = "";
|
||||
std::atomic_bool _triggerIsComplete = {false};
|
||||
bool _triggerResult = false;
|
||||
int64_t _completionId = 0;
|
||||
|
||||
@@ -21,7 +21,7 @@ MacroSegmentSelection::MacroSegmentSelection(QWidget *parent, Type type,
|
||||
{
|
||||
_index->setMinimum(0);
|
||||
_index->setMaximum(99);
|
||||
_index->specialValueText("-");
|
||||
_index->setSpecialValueText("-");
|
||||
if (!allowVariables) {
|
||||
_index->DisableVariableSelection();
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <QApplication>
|
||||
#include <QEvent>
|
||||
#include <QGraphicsOpacityEffect>
|
||||
#include <QLabel>
|
||||
#include <QMouseEvent>
|
||||
#include <QScrollBar>
|
||||
@@ -24,24 +25,24 @@ bool MacroSegment::Save(obs_data_t *obj) const
|
||||
obs_data_set_bool(data, "collapsed", _collapsed);
|
||||
obs_data_set_bool(data, "useCustomLabel", _useCustomLabel);
|
||||
obs_data_set_string(data, "customLabel", _customLabel.c_str());
|
||||
obs_data_set_bool(data, "enabled", _enabled);
|
||||
obs_data_set_int(data, "version", 1);
|
||||
obs_data_set_obj(obj, "segmentSettings", data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroSegment::Load(obs_data_t *obj)
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_get_obj(obj, "segmentSettings");
|
||||
_collapsed = obs_data_get_bool(data, "collapsed");
|
||||
_useCustomLabel = obs_data_get_bool(data, "useCustomLabel");
|
||||
_customLabel = obs_data_get_string(data, "customLabel");
|
||||
obs_data_set_default_bool(data, "enabled", true);
|
||||
_enabled = obs_data_get_bool(data, "enabled");
|
||||
|
||||
// TODO: remove this fallback at some point
|
||||
if (obs_data_has_user_value(obj, "segmentSettings")) {
|
||||
OBSDataAutoRelease data =
|
||||
obs_data_get_obj(obj, "segmentSettings");
|
||||
_collapsed = obs_data_get_bool(data, "collapsed");
|
||||
_useCustomLabel = obs_data_get_bool(data, "useCustomLabel");
|
||||
_customLabel = obs_data_get_string(data, "customLabel");
|
||||
} else {
|
||||
_collapsed = obs_data_get_bool(obj, "collapsed");
|
||||
_useCustomLabel = false;
|
||||
_customLabel = obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.segment.defaultCustomLabel");
|
||||
if (!obs_data_has_user_value(data, "version")) {
|
||||
_enabled = obs_data_get_bool(obj, "enabled");
|
||||
}
|
||||
|
||||
ClearAvailableTempvars();
|
||||
@@ -73,6 +74,16 @@ bool MacroSegment::GetHighlightAndReset()
|
||||
return false;
|
||||
}
|
||||
|
||||
void MacroSegment::SetEnabled(bool value)
|
||||
{
|
||||
_enabled = value;
|
||||
}
|
||||
|
||||
bool MacroSegment::Enabled() const
|
||||
{
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
std::string MacroSegment::GetVariableValue() const
|
||||
{
|
||||
if (_supportsVariableValue) {
|
||||
@@ -294,13 +305,8 @@ bool MacroSegmentEdit::eventFilter(QObject *obj, QEvent *ev)
|
||||
QMouseEvent *newEvent = new QMouseEvent(
|
||||
mouseEvent->type(),
|
||||
_headerInfo->mapTo(this, mouseEvent->pos()),
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
mouseEvent->globalPos(),
|
||||
#else
|
||||
mouseEvent->globalPosition(),
|
||||
#endif
|
||||
mouseEvent->button(), mouseEvent->buttons(),
|
||||
mouseEvent->modifiers());
|
||||
mouseEvent->globalPosition(), mouseEvent->button(),
|
||||
mouseEvent->buttons(), mouseEvent->modifiers());
|
||||
QApplication::sendEvent(parentWidget(), newEvent);
|
||||
}
|
||||
return QWidget::eventFilter(obj, ev);
|
||||
@@ -318,13 +324,29 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSegmentEdit::SetDisableEffect(bool value)
|
||||
{
|
||||
if (value) {
|
||||
auto effect = new QGraphicsOpacityEffect(this);
|
||||
effect->setOpacity(0.5);
|
||||
_section->setGraphicsEffect(effect);
|
||||
} else {
|
||||
_section->setGraphicsEffect(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSegmentEdit::SetEnableAppearance(bool value)
|
||||
{
|
||||
SetDisableEffect(!value);
|
||||
}
|
||||
|
||||
void MacroSegmentEdit::SetFocusPolicyOfWidgets()
|
||||
{
|
||||
QList<QWidget *> widgets = this->findChildren<QWidget *>();
|
||||
|
||||
@@ -39,6 +39,8 @@ public:
|
||||
virtual std::string GetId() const = 0;
|
||||
void EnableHighlight();
|
||||
bool GetHighlightAndReset();
|
||||
void SetEnabled(bool);
|
||||
bool Enabled() const;
|
||||
virtual std::string GetVariableValue() const;
|
||||
|
||||
protected:
|
||||
@@ -46,13 +48,22 @@ 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,
|
||||
const std::string &description = "");
|
||||
|
||||
void SetTempVarValue(const std::string &id, const std::string &value);
|
||||
|
||||
template<typename T, typename = std::enable_if_t<
|
||||
std::is_same<std::decay_t<T>, bool>::value>>
|
||||
void SetTempVarValue(const std::string &id, T value)
|
||||
{
|
||||
SetTempVarValue(id, value ? std::string("true")
|
||||
: std::string("false"));
|
||||
}
|
||||
|
||||
private:
|
||||
void ClearAvailableTempvars();
|
||||
std::optional<const TempVariable>
|
||||
@@ -66,6 +77,7 @@ private:
|
||||
// UI helper
|
||||
bool _highlight = false;
|
||||
bool _collapsed = false;
|
||||
bool _enabled = true;
|
||||
|
||||
// Custom header labels
|
||||
bool _useCustomLabel = false;
|
||||
@@ -94,12 +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);
|
||||
void Collapsed(bool) const;
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
@@ -109,12 +122,16 @@ signals:
|
||||
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
||||
|
||||
protected:
|
||||
void SetDisableEffect(bool);
|
||||
void SetEnableAppearance(bool);
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *ev) override;
|
||||
|
||||
Section *_section;
|
||||
QLabel *_headerInfo;
|
||||
QWidget *_frame;
|
||||
QVBoxLayout *_contentLayout;
|
||||
bool _allWidgetsAreSetup = false;
|
||||
|
||||
private:
|
||||
enum class DropLineState {
|
||||
|
||||
@@ -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(
|
||||
@@ -107,6 +115,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 +159,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);
|
||||
@@ -273,6 +288,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 +296,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());
|
||||
@@ -431,6 +450,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 +462,7 @@ bool MacroSettingsDialog::AskForSettings(QWidget *parent,
|
||||
return true;
|
||||
}
|
||||
|
||||
macro->SetCheckInParallel(dialog._currentCheckInParallel->isChecked());
|
||||
macro->EnablePauseHotkeys(
|
||||
dialog._currentMacroRegisterHotkeys->isChecked());
|
||||
macro->SetShortCircuitEvaluation(
|
||||
|
||||
@@ -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;
|
||||
@@ -52,10 +53,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;
|
||||
|
||||
@@ -27,6 +27,14 @@ namespace advss {
|
||||
static QObject *addPulse = nullptr;
|
||||
static QTimer onChangeHighlightTimer;
|
||||
|
||||
static void disableAddButtonHighlight()
|
||||
{
|
||||
if (addPulse) {
|
||||
addPulse->deleteLater();
|
||||
addPulse = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static bool macroNameExists(const std::string &name)
|
||||
{
|
||||
return !!GetMacroByName(name.c_str());
|
||||
@@ -86,24 +94,26 @@ bool AdvSceneSwitcher::AddNewMacro(std::shared_ptr<Macro> &res,
|
||||
return false;
|
||||
}
|
||||
|
||||
res = std::make_shared<Macro>(
|
||||
name, GetGlobalMacroSettings()._newMacroRegisterHotkeys,
|
||||
GetGlobalMacroSettings()._newMacroUseShortCircuitEvaluation);
|
||||
res = std::make_shared<Macro>(name, GetGlobalMacroSettings());
|
||||
return true;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_macroAdd_clicked()
|
||||
{
|
||||
// Hotkey to add new macro will also use this function.
|
||||
// Since we don't want the hotkey to have an effect if the macro tab is
|
||||
// not focused we need to check this here.
|
||||
if (!MacroTabIsInFocus()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string name;
|
||||
std::shared_ptr<Macro> newMacro;
|
||||
if (!AddNewMacro(newMacro, name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (addPulse) {
|
||||
addPulse->deleteLater();
|
||||
addPulse = nullptr;
|
||||
}
|
||||
disableAddButtonHighlight();
|
||||
|
||||
auto selectedMacro = GetSelectedMacro();
|
||||
if (!selectedMacro) {
|
||||
@@ -130,6 +140,42 @@ void AdvSceneSwitcher::on_macroAdd_clicked()
|
||||
emit MacroAdded(QString::fromStdString(name));
|
||||
}
|
||||
|
||||
static void addGroupSubitems(std::vector<std::shared_ptr<Macro>> ¯os,
|
||||
const std::shared_ptr<Macro> &group)
|
||||
{
|
||||
std::vector<std::shared_ptr<Macro>> subitems;
|
||||
subitems.reserve(group->GroupSize());
|
||||
|
||||
// Find all subitems
|
||||
auto allMacros = GetMacros();
|
||||
for (auto it = allMacros.begin(); it < allMacros.end(); it++) {
|
||||
if ((*it)->Name() != group->Name()) {
|
||||
continue;
|
||||
}
|
||||
for (uint32_t i = 1; i <= group->GroupSize(); i++) {
|
||||
subitems.emplace_back(*std::next(it, i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove subitems which were already selected to avoid duplicates
|
||||
for (const auto &subitem : subitems) {
|
||||
auto it = std::find(macros.begin(), macros.end(), subitem);
|
||||
if (it == macros.end()) {
|
||||
continue;
|
||||
}
|
||||
macros.erase(it);
|
||||
}
|
||||
|
||||
// Add group subitems
|
||||
auto it = std::find(macros.begin(), macros.end(), group);
|
||||
if (it == macros.end()) {
|
||||
return;
|
||||
}
|
||||
it = std::next(it);
|
||||
macros.insert(it, subitems.begin(), subitems.end());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveMacro(std::shared_ptr<Macro> ¯o)
|
||||
{
|
||||
if (!macro) {
|
||||
@@ -145,6 +191,28 @@ void AdvSceneSwitcher::RemoveMacro(std::shared_ptr<Macro> ¯o)
|
||||
}
|
||||
}
|
||||
|
||||
const auto clearWidgetCache = [this](Macro *macro) {
|
||||
ui->conditionsList->ClearWidgetsFromCacheFor(macro);
|
||||
ui->actionsList->ClearWidgetsFromCacheFor(macro);
|
||||
ui->elseActionsList->ClearWidgetsFromCacheFor(macro);
|
||||
};
|
||||
|
||||
if (macro->IsGroup()) {
|
||||
std::vector<std::shared_ptr<Macro>> macros = {macro};
|
||||
addGroupSubitems(macros, macro);
|
||||
for (auto macro : macros) {
|
||||
clearWidgetCache(macro.get());
|
||||
}
|
||||
} else {
|
||||
clearWidgetCache(macro.get());
|
||||
}
|
||||
|
||||
// Currently shown macro will always be part of the macros to be
|
||||
// removed, so, we clear the widgets as they should not be cached
|
||||
ui->conditionsList->Clear();
|
||||
ui->actionsList->Clear();
|
||||
ui->elseActionsList->Clear();
|
||||
|
||||
ui->macros->Remove(macro);
|
||||
emit MacroRemoved(name);
|
||||
}
|
||||
@@ -160,7 +228,7 @@ void AdvSceneSwitcher::RemoveSelectedMacros()
|
||||
if (macroCount == 1) {
|
||||
QString deleteWarning = obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text");
|
||||
auto macro = macros.at(0);
|
||||
auto ¯o = macros.at(0);
|
||||
deleteWarning = deleteWarning.arg(
|
||||
QString::fromStdString(macro->Name()));
|
||||
|
||||
@@ -200,7 +268,7 @@ void AdvSceneSwitcher::on_macroRemove_clicked()
|
||||
RemoveSelectedMacros();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_macroUp_clicked()
|
||||
void AdvSceneSwitcher::on_macroUp_clicked() const
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
@@ -209,7 +277,7 @@ void AdvSceneSwitcher::on_macroUp_clicked()
|
||||
ui->macros->Up(macro);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_macroDown_clicked()
|
||||
void AdvSceneSwitcher::on_macroDown_clicked() const
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
@@ -244,42 +312,7 @@ void AdvSceneSwitcher::RenameSelectedMacro()
|
||||
ui->macroName->setText(QString::fromStdString(name));
|
||||
}
|
||||
|
||||
static void addGroupSubitems(std::vector<std::shared_ptr<Macro>> ¯os,
|
||||
const std::shared_ptr<Macro> &group)
|
||||
{
|
||||
std::vector<std::shared_ptr<Macro>> subitems;
|
||||
subitems.reserve(group->GroupSize());
|
||||
|
||||
// Find all subitems
|
||||
auto allMacros = GetMacros();
|
||||
for (auto it = allMacros.begin(); it < allMacros.end(); it++) {
|
||||
if ((*it)->Name() == group->Name()) {
|
||||
for (uint32_t i = 1; i <= group->GroupSize(); i++) {
|
||||
subitems.emplace_back(*std::next(it, i));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove subitems which were already selected to avoid duplicates
|
||||
for (const auto &subitem : subitems) {
|
||||
auto it = std::find(macros.begin(), macros.end(), subitem);
|
||||
if (it == macros.end()) {
|
||||
continue;
|
||||
}
|
||||
macros.erase(it);
|
||||
}
|
||||
|
||||
// Add group subitems
|
||||
auto it = std::find(macros.begin(), macros.end(), group);
|
||||
if (it == macros.end()) {
|
||||
return;
|
||||
}
|
||||
it = std::next(it);
|
||||
macros.insert(it, subitems.begin(), subitems.end());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::ExportMacros()
|
||||
void AdvSceneSwitcher::ExportMacros() const
|
||||
{
|
||||
auto selectedMacros = GetSelectedMacros();
|
||||
auto macros = selectedMacros;
|
||||
@@ -490,6 +523,7 @@ void AdvSceneSwitcher::ImportMacros()
|
||||
|
||||
ui->macros->Reset(GetMacros(),
|
||||
GetGlobalMacroSettings()._highlightExecuted);
|
||||
disableAddButtonHighlight();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_macroName_editingFinished()
|
||||
@@ -510,7 +544,7 @@ void AdvSceneSwitcher::on_macroName_editingFinished()
|
||||
RenameMacro(macro, newName);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_runMacroInParallel_stateChanged(int value)
|
||||
void AdvSceneSwitcher::on_runMacroInParallel_stateChanged(int value) const
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
@@ -520,7 +554,7 @@ void AdvSceneSwitcher::on_runMacroInParallel_stateChanged(int value)
|
||||
macro->SetRunInParallel(value);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_runMacroOnChange_stateChanged(int value)
|
||||
void AdvSceneSwitcher::on_runMacroOnChange_stateChanged(int value) const
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
@@ -533,29 +567,69 @@ void AdvSceneSwitcher::on_runMacroOnChange_stateChanged(int value)
|
||||
void AdvSceneSwitcher::PopulateMacroActions(Macro &m, uint32_t afterIdx)
|
||||
{
|
||||
auto &actions = m.Actions();
|
||||
ui->actionsList->SetHelpMsgVisible(actions.size() == 0);
|
||||
|
||||
if (ui->actionsList->PopulateWidgetsFromCache(&m)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The layout system has not completed geometry propagation yet, so we
|
||||
// can skip those checks for now
|
||||
ui->actionsList->SetVisibilityCheckEnable(false);
|
||||
|
||||
for (; afterIdx < actions.size(); afterIdx++) {
|
||||
auto newEntry = new MacroActionEdit(this, &actions[afterIdx],
|
||||
actions[afterIdx]->GetId());
|
||||
ui->actionsList->Add(newEntry);
|
||||
}
|
||||
ui->actionsList->SetHelpMsgVisible(actions.size() == 0);
|
||||
|
||||
// Give the layout system time before enabling the visibility checks and
|
||||
// fully constructing the visible macro segments
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
ui->actionsList->SetVisibilityCheckEnable(true);
|
||||
});
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::PopulateMacroElseActions(Macro &m, uint32_t afterIdx)
|
||||
{
|
||||
auto &actions = m.ElseActions();
|
||||
ui->elseActionsList->SetHelpMsgVisible(actions.size() == 0);
|
||||
|
||||
if (ui->elseActionsList->PopulateWidgetsFromCache(&m)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The layout system has not completed geometry propagation yet, so we
|
||||
// can skip those checks for now
|
||||
ui->elseActionsList->SetVisibilityCheckEnable(false);
|
||||
|
||||
for (; afterIdx < actions.size(); afterIdx++) {
|
||||
auto newEntry = new MacroActionEdit(this, &actions[afterIdx],
|
||||
actions[afterIdx]->GetId());
|
||||
ui->elseActionsList->Add(newEntry);
|
||||
}
|
||||
ui->elseActionsList->SetHelpMsgVisible(actions.size() == 0);
|
||||
|
||||
// Give the layout system time before enabling the visibility checks and
|
||||
// fully constructing the visible macro segments
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
ui->elseActionsList->SetVisibilityCheckEnable(true);
|
||||
});
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::PopulateMacroConditions(Macro &m, uint32_t afterIdx)
|
||||
{
|
||||
bool root = afterIdx == 0;
|
||||
auto &conditions = m.Conditions();
|
||||
ui->conditionsList->SetHelpMsgVisible(conditions.size() == 0);
|
||||
|
||||
if (ui->conditionsList->PopulateWidgetsFromCache(&m)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The layout system has not completed geometry propagation yet, so we
|
||||
// can skip those checks for now
|
||||
ui->conditionsList->SetVisibilityCheckEnable(false);
|
||||
|
||||
for (; afterIdx < conditions.size(); afterIdx++) {
|
||||
auto newEntry = new MacroConditionEdit(
|
||||
this, &conditions[afterIdx],
|
||||
@@ -563,10 +637,15 @@ void AdvSceneSwitcher::PopulateMacroConditions(Macro &m, uint32_t afterIdx)
|
||||
ui->conditionsList->Add(newEntry);
|
||||
root = false;
|
||||
}
|
||||
ui->conditionsList->SetHelpMsgVisible(conditions.size() == 0);
|
||||
|
||||
// Give the layout system time before enabling the visibility checks and
|
||||
// fully constructing the visible macro segments
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
ui->conditionsList->SetVisibilityCheckEnable(true);
|
||||
});
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetActionData(Macro &m)
|
||||
void AdvSceneSwitcher::SetActionData(Macro &m) const
|
||||
{
|
||||
auto &actions = m.Actions();
|
||||
for (int idx = 0; idx < ui->actionsList->ContentLayout()->count();
|
||||
@@ -583,7 +662,7 @@ void AdvSceneSwitcher::SetActionData(Macro &m)
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetElseActionData(Macro &m)
|
||||
void AdvSceneSwitcher::SetElseActionData(Macro &m) const
|
||||
{
|
||||
auto &actions = m.ElseActions();
|
||||
for (int idx = 0; idx < ui->elseActionsList->ContentLayout()->count();
|
||||
@@ -600,7 +679,7 @@ void AdvSceneSwitcher::SetElseActionData(Macro &m)
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetConditionData(Macro &m)
|
||||
void AdvSceneSwitcher::SetConditionData(Macro &m) const
|
||||
{
|
||||
auto &conditions = m.Conditions();
|
||||
for (int idx = 0; idx < ui->conditionsList->ContentLayout()->count();
|
||||
@@ -678,7 +757,7 @@ void AdvSceneSwitcher::SetEditMacro(Macro &m)
|
||||
m.GetElseActionSplitterPosition());
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetMacroEditAreaDisabled(bool disable)
|
||||
void AdvSceneSwitcher::SetMacroEditAreaDisabled(bool disable) const
|
||||
{
|
||||
ui->macroName->setDisabled(disable);
|
||||
ui->runMacro->setDisabled(disable);
|
||||
@@ -689,32 +768,32 @@ void AdvSceneSwitcher::SetMacroEditAreaDisabled(bool disable)
|
||||
ui->macroActionConditionSplitter->setDisabled(disable);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightAction(int idx, QColor color)
|
||||
void AdvSceneSwitcher::HighlightAction(int idx, QColor color) const
|
||||
{
|
||||
ui->actionsList->Highlight(idx, color);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightElseAction(int idx, QColor color)
|
||||
void AdvSceneSwitcher::HighlightElseAction(int idx, QColor color) const
|
||||
{
|
||||
ui->elseActionsList->Highlight(idx, color);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightCondition(int idx, QColor color)
|
||||
void AdvSceneSwitcher::HighlightCondition(int idx, QColor color) const
|
||||
{
|
||||
ui->conditionsList->Highlight(idx, color);
|
||||
}
|
||||
|
||||
std::shared_ptr<Macro> AdvSceneSwitcher::GetSelectedMacro()
|
||||
std::shared_ptr<Macro> AdvSceneSwitcher::GetSelectedMacro() const
|
||||
{
|
||||
return ui->macros->GetCurrentMacro();
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Macro>> AdvSceneSwitcher::GetSelectedMacros()
|
||||
std::vector<std::shared_ptr<Macro>> AdvSceneSwitcher::GetSelectedMacros() const
|
||||
{
|
||||
return ui->macros->GetCurrentMacros();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroSelectionAboutToChange()
|
||||
void AdvSceneSwitcher::MacroSelectionAboutToChange() const
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
@@ -742,6 +821,10 @@ void AdvSceneSwitcher::MacroSelectionAboutToChange()
|
||||
}
|
||||
macro->SetElseActionSplitterPosition(
|
||||
ui->macroElseActionSplitter->sizes());
|
||||
|
||||
ui->conditionsList->CacheCurrentWidgetsFor(macro);
|
||||
ui->actionsList->CacheCurrentWidgetsFor(macro);
|
||||
ui->elseActionsList->CacheCurrentWidgetsFor(macro);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MacroSelectionChanged()
|
||||
@@ -770,7 +853,7 @@ void AdvSceneSwitcher::MacroSelectionChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightOnChange()
|
||||
void AdvSceneSwitcher::HighlightOnChange() const
|
||||
{
|
||||
if (!GetGlobalMacroSettings()._highlightActions &&
|
||||
!GetGlobalMacroSettings()._highlightExecuted) {
|
||||
@@ -1299,15 +1382,12 @@ void AdvSceneSwitcher::CopyMacro()
|
||||
Macro::PrepareMoveToGroup(macro->Parent(), newMacro);
|
||||
|
||||
ui->macros->Add(newMacro, macro);
|
||||
if (addPulse) {
|
||||
addPulse->deleteLater();
|
||||
addPulse = nullptr;
|
||||
}
|
||||
disableAddButtonHighlight();
|
||||
emit MacroAdded(QString::fromStdString(name));
|
||||
}
|
||||
|
||||
void setCollapsedHelper(const std::shared_ptr<Macro> &m, MacroSegmentList *list,
|
||||
bool collapsed)
|
||||
static void setCollapsedHelper(const std::shared_ptr<Macro> &m,
|
||||
MacroSegmentList *list, bool collapsed)
|
||||
{
|
||||
if (!m) {
|
||||
return;
|
||||
@@ -1315,32 +1395,32 @@ void setCollapsedHelper(const std::shared_ptr<Macro> &m, MacroSegmentList *list,
|
||||
list->SetCollapsed(collapsed);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::ExpandAllActions()
|
||||
void AdvSceneSwitcher::ExpandAllActions() const
|
||||
{
|
||||
setCollapsedHelper(GetSelectedMacro(), ui->actionsList, false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::ExpandAllElseActions()
|
||||
void AdvSceneSwitcher::ExpandAllElseActions() const
|
||||
{
|
||||
setCollapsedHelper(GetSelectedMacro(), ui->elseActionsList, false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::ExpandAllConditions()
|
||||
void AdvSceneSwitcher::ExpandAllConditions() const
|
||||
{
|
||||
setCollapsedHelper(GetSelectedMacro(), ui->conditionsList, false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::CollapseAllActions()
|
||||
void AdvSceneSwitcher::CollapseAllActions() const
|
||||
{
|
||||
setCollapsedHelper(GetSelectedMacro(), ui->actionsList, true);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::CollapseAllElseActions()
|
||||
void AdvSceneSwitcher::CollapseAllElseActions() const
|
||||
{
|
||||
setCollapsedHelper(GetSelectedMacro(), ui->elseActionsList, true);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::CollapseAllConditions()
|
||||
void AdvSceneSwitcher::CollapseAllConditions() const
|
||||
{
|
||||
setCollapsedHelper(GetSelectedMacro(), ui->conditionsList, true);
|
||||
}
|
||||
@@ -1355,7 +1435,7 @@ static void reduceSizeOfSplitterIdx(QSplitter *splitter, int idx)
|
||||
splitter->setSizes(sizes);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MinimizeActions()
|
||||
void AdvSceneSwitcher::MinimizeActions() const
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
@@ -1369,13 +1449,13 @@ void AdvSceneSwitcher::MinimizeActions()
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MaximizeActions()
|
||||
void AdvSceneSwitcher::MaximizeActions() const
|
||||
{
|
||||
MinimizeElseActions();
|
||||
MinimizeConditions();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MinimizeElseActions()
|
||||
void AdvSceneSwitcher::MinimizeElseActions() const
|
||||
{
|
||||
auto macro = GetSelectedMacro();
|
||||
if (!macro) {
|
||||
@@ -1388,24 +1468,24 @@ void AdvSceneSwitcher::MinimizeElseActions()
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MaximizeElseActions()
|
||||
void AdvSceneSwitcher::MaximizeElseActions() const
|
||||
{
|
||||
MinimizeConditions();
|
||||
reduceSizeOfSplitterIdx(ui->macroElseActionSplitter, 0);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MinimizeConditions()
|
||||
void AdvSceneSwitcher::MinimizeConditions() const
|
||||
{
|
||||
reduceSizeOfSplitterIdx(ui->macroActionConditionSplitter, 0);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::MaximizeConditions()
|
||||
void AdvSceneSwitcher::MaximizeConditions() const
|
||||
{
|
||||
MinimizeElseActions();
|
||||
MinimizeActions();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_toggleElseActions_clicked()
|
||||
void AdvSceneSwitcher::on_toggleElseActions_clicked() const
|
||||
{
|
||||
auto elsePosition = ui->macroElseActionSplitter->sizes();
|
||||
if (elsePosition[1] == 0) {
|
||||
@@ -1416,14 +1496,14 @@ void AdvSceneSwitcher::on_toggleElseActions_clicked()
|
||||
maximizeFirstSplitterEntry(ui->macroElseActionSplitter);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetElseActionsStateToHidden()
|
||||
void AdvSceneSwitcher::SetElseActionsStateToHidden() const
|
||||
{
|
||||
ui->toggleElseActions->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.toggleElseActions.show.tooltip"));
|
||||
ui->toggleElseActions->setChecked(false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetElseActionsStateToVisible()
|
||||
void AdvSceneSwitcher::SetElseActionsStateToVisible() const
|
||||
{
|
||||
ui->toggleElseActions->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.toggleElseActions.hide.tooltip"));
|
||||
@@ -1601,7 +1681,7 @@ static void fadeWidgets(const std::vector<QWidget *> &widgets, bool fadeOut)
|
||||
}
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::HighlightControls()
|
||||
void AdvSceneSwitcher::HighlightControls() const
|
||||
{
|
||||
const std::vector<QWidget *> conditionControls{
|
||||
ui->conditionAdd, ui->conditionRemove, ui->conditionTop,
|
||||
|
||||
@@ -178,6 +178,7 @@ void MacroTreeItem::Update(bool force)
|
||||
QSizePolicy::Maximum);
|
||||
_expand->setMaximumSize(10, 16);
|
||||
_expand->setMinimumSize(10, 0);
|
||||
_expand->setProperty("class", "checkbox-icon indicator-expand");
|
||||
#ifdef __APPLE__
|
||||
_expand->setAttribute(Qt::WA_LayoutUsesWidgetRect);
|
||||
#endif
|
||||
@@ -888,14 +889,7 @@ void MacroTree::dropEvent(QDropEvent *event)
|
||||
QModelIndexList indices = selectedIndexes();
|
||||
|
||||
DropIndicatorPosition indicator = dropIndicatorPosition();
|
||||
int row = indexAt(
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
event->position().toPoint()
|
||||
#else
|
||||
event->pos()
|
||||
#endif
|
||||
)
|
||||
.row();
|
||||
int row = indexAt(event->position().toPoint()).row();
|
||||
bool emptyDrop = row == -1;
|
||||
|
||||
if (emptyDrop) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#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"
|
||||
@@ -76,15 +77,21 @@ 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)
|
||||
{
|
||||
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()
|
||||
@@ -104,7 +111,8 @@ 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);
|
||||
}
|
||||
@@ -244,14 +252,52 @@ bool Macro::CheckConditions(bool ignorePause)
|
||||
return false;
|
||||
}
|
||||
|
||||
_matched = false;
|
||||
for (auto &condition : _conditions) {
|
||||
if (_paused && !ignorePause) {
|
||||
vblog(LOG_INFO, "Macro %s is paused", _name.c_str());
|
||||
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());
|
||||
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);
|
||||
@@ -268,7 +314,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) {
|
||||
@@ -286,14 +334,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);
|
||||
}
|
||||
@@ -331,6 +380,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);
|
||||
@@ -383,6 +439,9 @@ bool Macro::RunActionsHelper(
|
||||
|
||||
bool actionsExecutedSuccessfully = true;
|
||||
for (auto &action : actions) {
|
||||
if (!action) {
|
||||
continue;
|
||||
}
|
||||
if (action->Enabled()) {
|
||||
action->LogAction();
|
||||
actionsExecutedSuccessfully =
|
||||
@@ -400,7 +459,6 @@ bool Macro::RunActionsHelper(
|
||||
action->EnableHighlight();
|
||||
}
|
||||
}
|
||||
_done = true;
|
||||
return actionsExecutedSuccessfully;
|
||||
}
|
||||
|
||||
@@ -500,9 +558,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
|
||||
@@ -640,16 +724,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;
|
||||
@@ -704,6 +803,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);
|
||||
@@ -789,6 +889,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");
|
||||
@@ -1460,6 +1561,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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "variable-string.hpp"
|
||||
#include "temp-variable.hpp"
|
||||
|
||||
#include <future>
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
#include <string>
|
||||
@@ -20,6 +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,6 +79,9 @@ 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;
|
||||
@@ -90,8 +95,11 @@ public:
|
||||
|
||||
// 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();
|
||||
@@ -182,11 +190,10 @@ private:
|
||||
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 +211,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;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "sync-helpers.hpp"
|
||||
#include "tab-helpers.hpp"
|
||||
#include "time-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
|
||||
#include <QTimer>
|
||||
@@ -39,8 +40,8 @@ ActionQueueTable *ActionQueueTable::Create()
|
||||
void ActionQueueTable::Add()
|
||||
{
|
||||
auto newQueue = std::make_shared<ActionQueue>();
|
||||
auto accepted =
|
||||
ActionQueueSettingsDialog::AskForSettings(this, *newQueue);
|
||||
auto accepted = ActionQueueSettingsDialog::AskForSettings(
|
||||
GetSettingsWindow(), *newQueue);
|
||||
if (!accepted) {
|
||||
return;
|
||||
}
|
||||
@@ -55,6 +56,13 @@ void ActionQueueTable::Add()
|
||||
QString::fromStdString(newQueue->Name()));
|
||||
}
|
||||
|
||||
static double getSecondsSinceLastEmpty(ActionQueue *queue)
|
||||
{
|
||||
const auto time = std::chrono::high_resolution_clock::now() -
|
||||
queue->GetLastEmptyTime();
|
||||
return std::chrono::duration_cast<std::chrono::seconds>(time).count();
|
||||
}
|
||||
|
||||
static QStringList getCellLabels(ActionQueue *queue, bool addName = true)
|
||||
{
|
||||
assert(queue);
|
||||
@@ -64,6 +72,7 @@ static QStringList getCellLabels(ActionQueue *queue, bool addName = true)
|
||||
result << QString::fromStdString(queue->Name());
|
||||
}
|
||||
result << QString::number(queue->Size())
|
||||
<< FormatRelativeTime(getSecondsSinceLastEmpty(queue))
|
||||
<< QString::fromStdString(obs_module_text(
|
||||
queue->IsRunning()
|
||||
? "AdvSceneSwitcher.actionQueueTab.yes"
|
||||
@@ -115,7 +124,7 @@ static void openSettingsDialog()
|
||||
|
||||
auto oldName = queue->Name();
|
||||
bool accepted = ActionQueueSettingsDialog::AskForSettings(
|
||||
tabWidget->Table(), *queue.get());
|
||||
GetSettingsWindow(), *queue.get());
|
||||
if (accepted && oldName != queue->Name()) {
|
||||
ActionQueueSignalManager::Instance()->Rename(
|
||||
QString::fromStdString(oldName),
|
||||
@@ -199,6 +208,8 @@ ActionQueueTable::ActionQueueTable(QTabWidget *parent)
|
||||
"AdvSceneSwitcher.actionQueueTab.name.header")
|
||||
<< obs_module_text(
|
||||
"AdvSceneSwitcher.actionQueueTab.size.header")
|
||||
<< obs_module_text(
|
||||
"AdvSceneSwitcher.actionQueueTab.lastEmpty.header")
|
||||
<< obs_module_text(
|
||||
"AdvSceneSwitcher.actionQueueTab.isRunning.header")
|
||||
<< obs_module_text(
|
||||
|
||||
@@ -26,7 +26,10 @@ void SetupActionQueues()
|
||||
done = true;
|
||||
}
|
||||
|
||||
ActionQueue::ActionQueue() : Item() {}
|
||||
ActionQueue::ActionQueue() : Item()
|
||||
{
|
||||
_lastEmpty = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
ActionQueue::~ActionQueue()
|
||||
{
|
||||
@@ -110,6 +113,7 @@ void ActionQueue::Add(const std::shared_ptr<MacroAction> &action)
|
||||
action->Save(data);
|
||||
copy->Load(data);
|
||||
copy->PostLoad();
|
||||
RunPostLoadSteps();
|
||||
copy->ResolveVariablesToFixedValues();
|
||||
_actions.emplace_back(copy);
|
||||
} else {
|
||||
@@ -124,6 +128,14 @@ bool ActionQueue::IsEmpty()
|
||||
return _actions.empty();
|
||||
}
|
||||
|
||||
ActionQueue::TimePoint ActionQueue::GetLastEmptyTime()
|
||||
{
|
||||
if (IsEmpty()) {
|
||||
_lastEmpty = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
return _lastEmpty;
|
||||
}
|
||||
|
||||
size_t ActionQueue::Size()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
@@ -137,6 +149,8 @@ void ActionQueue::RunActions()
|
||||
{ // Grab next action to run
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
while (_actions.empty() && !_stop) {
|
||||
_lastEmpty =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
_cv.wait(lock);
|
||||
}
|
||||
|
||||
@@ -166,7 +180,7 @@ ActionQueueSettingsDialog::ActionQueueSettingsDialog(QWidget *parent,
|
||||
"AdvSceneSwitcher.actionQueues.select",
|
||||
"AdvSceneSwitcher.actionQueues.add",
|
||||
"AdvSceneSwitcher.actionQueues.nameNotAvailable",
|
||||
parent),
|
||||
true, parent),
|
||||
_queueRunStatus(new QLabel()),
|
||||
_startStopToggle(new QPushButton()),
|
||||
_queueSize(new QLabel()),
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
#include "item-selection-helpers.hpp"
|
||||
#include "macro-action.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <obs-data.h>
|
||||
#include <QCheckBox>
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -14,6 +15,8 @@ class ActionQueueSelection;
|
||||
class ActionQueueSettingsDialog;
|
||||
|
||||
class ActionQueue : public Item {
|
||||
using TimePoint = std::chrono::high_resolution_clock::time_point;
|
||||
|
||||
public:
|
||||
ActionQueue();
|
||||
~ActionQueue();
|
||||
@@ -30,6 +33,7 @@ public:
|
||||
|
||||
void Clear();
|
||||
bool IsEmpty();
|
||||
TimePoint GetLastEmptyTime();
|
||||
|
||||
void Add(const std::shared_ptr<MacroAction> &);
|
||||
size_t Size();
|
||||
@@ -44,6 +48,7 @@ private:
|
||||
std::condition_variable _cv;
|
||||
std::thread _thread;
|
||||
std::deque<std::shared_ptr<MacroAction>> _actions;
|
||||
TimePoint _lastEmpty;
|
||||
|
||||
friend ActionQueueSelection;
|
||||
friend ActionQueueSettingsDialog;
|
||||
|
||||
@@ -168,17 +168,6 @@ void SwitcherData::SaveVersion(obs_data_t *obj,
|
||||
obs_data_set_string(obj, "version", currentVersion.c_str());
|
||||
}
|
||||
|
||||
void SwitcherData::AddIntervalResetStep(std::function<void()> function,
|
||||
bool tryLock)
|
||||
{
|
||||
if (!tryLock) {
|
||||
resetIntervalSteps.emplace_back(function);
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
resetIntervalSteps.emplace_back(function);
|
||||
}
|
||||
|
||||
void SwitcherData::RunPostLoadSteps()
|
||||
{
|
||||
for (const auto &func : postLoadSteps) {
|
||||
@@ -266,6 +255,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(
|
||||
@@ -281,19 +280,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;
|
||||
@@ -311,6 +312,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");
|
||||
@@ -323,14 +325,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");
|
||||
|
||||
@@ -57,11 +57,9 @@ public:
|
||||
bool AnySceneTransitionStarted();
|
||||
|
||||
void SetPreconditions();
|
||||
void ResetForNextInterval();
|
||||
void AddSaveStep(std::function<void(obs_data_t *)>);
|
||||
void AddLoadStep(std::function<void(obs_data_t *)>);
|
||||
void AddPostLoadStep(std::function<void()>);
|
||||
void AddIntervalResetStep(std::function<void()>, bool lock = true);
|
||||
void RunPostLoadSteps();
|
||||
bool CheckForMatch(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||
int &linger, bool &setPreviousSceneAsMatch,
|
||||
@@ -100,7 +98,6 @@ public:
|
||||
std::vector<std::function<void(obs_data_t *)>> saveSteps;
|
||||
std::vector<std::function<void(obs_data_t *)>> loadSteps;
|
||||
std::vector<std::function<void()>> postLoadSteps;
|
||||
std::vector<std::function<void()>> resetIntervalSteps;
|
||||
|
||||
bool firstBoot = true;
|
||||
bool transitionActive = false;
|
||||
@@ -135,9 +132,6 @@ public:
|
||||
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;
|
||||
@@ -155,6 +149,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;
|
||||
@@ -169,6 +164,7 @@ public:
|
||||
bool warnPluginLoadFailure = true;
|
||||
bool disableHints = false;
|
||||
bool disableFilterComboboxFilter = false;
|
||||
bool disableMacroWidgetCache = false;
|
||||
bool hideLegacyTabs = true;
|
||||
bool saveWindowGeo = false;
|
||||
QPoint windowPos = {};
|
||||
@@ -233,7 +229,6 @@ public:
|
||||
bool checkPause();
|
||||
void checkDefaultSceneTransitions();
|
||||
void writeSceneInfoToFile();
|
||||
void writeToStatusFile(const QString &msg);
|
||||
void checkSwitchCooldown(bool &match);
|
||||
|
||||
std::deque<WindowSwitch> windowSwitches;
|
||||
|
||||
34
lib/utils/auto-update-tooltip-label.cpp
Normal file
34
lib/utils/auto-update-tooltip-label.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include "auto-update-tooltip-label.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
AutoUpdateTooltipLabel::AutoUpdateTooltipLabel(
|
||||
QWidget *parent, const std::function<QString()> &updateTooltipCallback,
|
||||
int updateIntervalMs)
|
||||
: QLabel(parent),
|
||||
_callback(updateTooltipCallback),
|
||||
_timer(new QTimer(this)),
|
||||
_updateIntervalMs(updateIntervalMs)
|
||||
{
|
||||
connect(_timer, &QTimer::timeout, this,
|
||||
&AutoUpdateTooltipLabel::UpdateTooltip);
|
||||
}
|
||||
|
||||
void AutoUpdateTooltipLabel::enterEvent(QEnterEvent *event)
|
||||
{
|
||||
_timer->start(_updateIntervalMs);
|
||||
QLabel::enterEvent(event);
|
||||
}
|
||||
|
||||
void AutoUpdateTooltipLabel::leaveEvent(QEvent *event)
|
||||
{
|
||||
_timer->stop();
|
||||
QLabel::leaveEvent(event);
|
||||
}
|
||||
|
||||
void AutoUpdateTooltipLabel::UpdateTooltip()
|
||||
{
|
||||
setToolTip(_callback());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
32
lib/utils/auto-update-tooltip-label.hpp
Normal file
32
lib/utils/auto-update-tooltip-label.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include "export-symbol-helper.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class ADVSS_EXPORT AutoUpdateTooltipLabel : public QLabel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AutoUpdateTooltipLabel(
|
||||
QWidget *parent,
|
||||
const std::function<QString()> &updateTooltipCallback,
|
||||
int updateIntervalMs = 300);
|
||||
|
||||
protected:
|
||||
void enterEvent(QEnterEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void UpdateTooltip();
|
||||
|
||||
private:
|
||||
const std::function<QString()> _callback;
|
||||
QTimer *_timer;
|
||||
const int _updateIntervalMs;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -29,6 +29,7 @@ void Duration::Load(obs_data_t *obj, const char *name)
|
||||
// TODO: remove this fallback
|
||||
if (!data || !obs_data_has_user_value(data, "version") ||
|
||||
obs_data_get_int(data, "version") != 1) {
|
||||
_value = 0.;
|
||||
bool usingDefaultArgs = strcmp("duration", name) == 0;
|
||||
if (usingDefaultArgs) {
|
||||
_value = obs_data_get_double(obj, "seconds");
|
||||
|
||||
@@ -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) {
|
||||
@@ -82,7 +87,7 @@ void FilterComboBox::setItemText(int index, const QString &text)
|
||||
void FilterComboBox::focusOutEvent(QFocusEvent *event)
|
||||
{
|
||||
// Reset on invalid selection
|
||||
if (findText(currentText()) == -1) {
|
||||
if (!_allowUnmatchedSelection && findText(currentText()) == -1) {
|
||||
setCurrentIndex(-1);
|
||||
Emit(-1, "");
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ 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);
|
||||
@@ -27,6 +28,7 @@ private slots:
|
||||
private:
|
||||
void Emit(int index, const QString &text);
|
||||
|
||||
bool _allowUnmatchedSelection = false;
|
||||
int _lastEmittedIndex = -1;
|
||||
QString _lastEmittedText;
|
||||
|
||||
|
||||
@@ -59,7 +59,10 @@ ItemSelection::ItemSelection(std::deque<std::shared_ptr<Item>> &items,
|
||||
_conflictStr(conflict)
|
||||
{
|
||||
_modify->setMaximumWidth(22);
|
||||
SetButtonIcon(_modify, ":/settings/images/settings/general.svg");
|
||||
SetButtonIcon(_modify,
|
||||
GetThemeTypeName() == "Light"
|
||||
? ":/settings/images/settings/general.svg"
|
||||
: "theme:Dark/settings/general.svg");
|
||||
_modify->setFlat(true);
|
||||
if (!configureTooltip.empty()) {
|
||||
_modify->setToolTip(obs_module_text(configureTooltip.data()));
|
||||
@@ -265,6 +268,7 @@ ItemSettingsDialog::ItemSettingsDialog(const Item &settings,
|
||||
std::string_view select,
|
||||
std::string_view add,
|
||||
std::string_view nameConflict,
|
||||
bool showNameEmptyWarning,
|
||||
QWidget *parent)
|
||||
: QDialog(parent),
|
||||
_name(new QLineEdit()),
|
||||
@@ -274,7 +278,8 @@ ItemSettingsDialog::ItemSettingsDialog(const Item &settings,
|
||||
_items(items),
|
||||
_selectStr(select),
|
||||
_addStr(add),
|
||||
_conflictStr(nameConflict)
|
||||
_conflictStr(nameConflict),
|
||||
_showNameEmptyWarning(showNameEmptyWarning)
|
||||
{
|
||||
setModal(true);
|
||||
setWindowModality(Qt::WindowModality::WindowModal);
|
||||
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
std::string_view addString = "AdvSceneSwitcher.item.add",
|
||||
std::string_view conflictString =
|
||||
"AdvSceneSwitcher.item.nameNotAvailable",
|
||||
QWidget *parent = 0);
|
||||
bool showEmptyNameWarning = true, QWidget *parent = 0);
|
||||
virtual ~ItemSettingsDialog() = default;
|
||||
|
||||
private slots:
|
||||
|
||||
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
|
||||
@@ -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
|
||||
|
||||
@@ -9,6 +9,27 @@ namespace advss {
|
||||
|
||||
template<class T> class MessageDispatcher {
|
||||
public:
|
||||
MessageDispatcher() = default;
|
||||
~MessageDispatcher() = default;
|
||||
MessageDispatcher(const MessageDispatcher &other)
|
||||
: _clients(other._clients)
|
||||
{
|
||||
}
|
||||
MessageDispatcher(MessageDispatcher &&other) noexcept
|
||||
: _clients(other._clients)
|
||||
{
|
||||
}
|
||||
MessageDispatcher<T> &operator=(const MessageDispatcher<T> &other)
|
||||
{
|
||||
_clients = other._clients;
|
||||
return *this;
|
||||
}
|
||||
MessageDispatcher<T> &operator=(MessageDispatcher<T> &&other) noexcept
|
||||
{
|
||||
std::swap(_clients, other._clients);
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::shared_ptr<MessageBuffer<T>> RegisterClient();
|
||||
void DispatchMessage(const T &message);
|
||||
|
||||
|
||||
@@ -32,7 +32,9 @@ void PreventMouseWheelAdjustWithoutFocus(QWidget *w)
|
||||
QString(w->metaObject()->className()) ==
|
||||
"advss::OSCMessageElementEdit" ||
|
||||
QString(w->metaObject()->className()) ==
|
||||
"advss::ChatMessagePropertyEdit") {
|
||||
"advss::ChatMessagePropertyEdit" ||
|
||||
QString(w->metaObject()->className()) ==
|
||||
"advss::KeyValueListContainerWidget") {
|
||||
return;
|
||||
}
|
||||
w->setFocusPolicy(Qt::StrongFocus);
|
||||
|
||||
@@ -67,6 +67,8 @@ NonModalMessageDialog::NonModalMessageDialog(const QString &message, Type type,
|
||||
}
|
||||
case Type::INPUT: {
|
||||
_inputEdit = new ResizingPlainTextEdit(this);
|
||||
_inputEdit->setTabChangesFocus(true);
|
||||
_inputEdit->setFocus();
|
||||
connect(_inputEdit, &ResizingPlainTextEdit::textChanged, this,
|
||||
&NonModalMessageDialog::InputChanged);
|
||||
layout->addWidget(_inputEdit);
|
||||
|
||||
@@ -21,6 +21,24 @@ static std::vector<std::function<void()>> &getPluginCleanupSteps()
|
||||
return steps;
|
||||
}
|
||||
|
||||
static std::vector<std::function<void()>> &getResetIntervalSteps()
|
||||
{
|
||||
static std::vector<std::function<void()>> steps;
|
||||
return steps;
|
||||
}
|
||||
|
||||
static std::vector<std::function<void()>> &getStartSteps()
|
||||
{
|
||||
static std::vector<std::function<void()>> steps;
|
||||
return steps;
|
||||
}
|
||||
|
||||
static std::vector<std::function<void()>> &getStopSteps()
|
||||
{
|
||||
static std::vector<std::function<void()>> steps;
|
||||
return steps;
|
||||
}
|
||||
|
||||
static std::mutex mutex;
|
||||
|
||||
void SavePluginSettings(obs_data_t *obj)
|
||||
@@ -48,9 +66,10 @@ void AddPostLoadStep(std::function<void()> step)
|
||||
GetSwitcher()->AddPostLoadStep(step);
|
||||
}
|
||||
|
||||
void AddIntervalResetStep(std::function<void()> step, bool lock)
|
||||
void AddIntervalResetStep(std::function<void()> step)
|
||||
{
|
||||
GetSwitcher()->AddIntervalResetStep(step, lock);
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
getResetIntervalSteps().emplace_back(step);
|
||||
}
|
||||
|
||||
void RunPostLoadSteps()
|
||||
@@ -100,6 +119,42 @@ void RunPluginCleanupSteps()
|
||||
}
|
||||
}
|
||||
|
||||
void RunIntervalResetSteps()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
for (const auto &step : getResetIntervalSteps()) {
|
||||
step();
|
||||
}
|
||||
}
|
||||
|
||||
void AddStartStep(std::function<void()> step)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
getStartSteps().emplace_back(step);
|
||||
}
|
||||
|
||||
void AddStopStep(std::function<void()> step)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
getStopSteps().emplace_back(step);
|
||||
}
|
||||
|
||||
void RunStartSteps()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
for (const auto &step : getStartSteps()) {
|
||||
step();
|
||||
}
|
||||
}
|
||||
|
||||
void RunStopSteps()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
for (const auto &step : getStopSteps()) {
|
||||
step();
|
||||
}
|
||||
}
|
||||
|
||||
void StopPlugin()
|
||||
{
|
||||
GetSwitcher()->Stop();
|
||||
|
||||
@@ -11,7 +11,7 @@ EXPORT void LoadPluginSettings(obs_data_t *);
|
||||
EXPORT void AddSaveStep(std::function<void(obs_data_t *)>);
|
||||
EXPORT void AddLoadStep(std::function<void(obs_data_t *)>);
|
||||
EXPORT void AddPostLoadStep(std::function<void()>);
|
||||
EXPORT void AddIntervalResetStep(std::function<void()>, bool lock = true);
|
||||
EXPORT void AddIntervalResetStep(std::function<void()>);
|
||||
EXPORT void RunPostLoadSteps();
|
||||
|
||||
EXPORT void AddPluginInitStep(std::function<void()>);
|
||||
@@ -25,6 +25,11 @@ EXPORT void StopPlugin();
|
||||
EXPORT void StartPlugin();
|
||||
EXPORT bool PluginIsRunning();
|
||||
EXPORT int GetIntervalValue();
|
||||
void AddStartStep(std::function<void()>);
|
||||
void AddStopStep(std::function<void()>);
|
||||
void RunStartSteps();
|
||||
void RunStopSteps();
|
||||
void RunIntervalResetSteps();
|
||||
|
||||
enum class NoMatchBehavior { NO_SWITCH = 0, SWITCH = 1, RANDOM_SWITCH = 2 };
|
||||
EXPORT void SetPluginNoMatchBehavior(NoMatchBehavior);
|
||||
|
||||
@@ -92,7 +92,10 @@ RegexConfigWidget::RegexConfigWidget(QWidget *parent, bool showEnable)
|
||||
_openSettings(new QToolButton()),
|
||||
_enable(new QPushButton())
|
||||
{
|
||||
SetButtonIcon(_openSettings, ":/settings/images/settings/general.svg");
|
||||
SetButtonIcon(_openSettings,
|
||||
GetThemeTypeName() == "Light"
|
||||
? ":/settings/images/settings/general.svg"
|
||||
: "theme:Dark/settings/general.svg");
|
||||
_openSettings->setToolTip(
|
||||
obs_module_text("AdvSceneSwitcher.regex.configure"));
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ void ResizingPlainTextEdit::AddHeightForScrollBar(bool addHeight)
|
||||
return;
|
||||
}
|
||||
|
||||
_hScrollBarAddedHeight = verticalScrollBar()->height();
|
||||
_hScrollBarAddedHeight = horizontalScrollBar()->height();
|
||||
setFixedHeight(height() + _hScrollBarAddedHeight);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
#include "resource-table-hotkey-handler.hpp"
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QWidget>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace advss {
|
||||
|
||||
void RegisterHotkeyFunction(QWidget *widget, Qt::Key key,
|
||||
std::function<void()> func)
|
||||
{
|
||||
ResourceTabHotkeyHandler::Instance()->RegisterHandler(widget, key,
|
||||
func);
|
||||
}
|
||||
|
||||
void DeregisterHotkeyFunctions(QWidget *widget)
|
||||
{
|
||||
ResourceTabHotkeyHandler::Instance()->Deregister(widget);
|
||||
}
|
||||
|
||||
ResourceTabHotkeyHandler *ResourceTabHotkeyHandler::Instance()
|
||||
{
|
||||
static ResourceTabHotkeyHandler handler;
|
||||
return &handler;
|
||||
}
|
||||
|
||||
void ResourceTabHotkeyHandler::RegisterHandler(QWidget *widget, Qt::Key key,
|
||||
std::function<void()> func)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
_callbacks.emplace(widget, CallbackData{key, func});
|
||||
widget->installEventFilter(this);
|
||||
}
|
||||
|
||||
void ResourceTabHotkeyHandler::Deregister(QWidget *widget)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
_callbacks.erase(widget);
|
||||
}
|
||||
|
||||
bool ResourceTabHotkeyHandler::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() != QEvent::KeyPress) {
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
auto pressedKey = keyEvent->key();
|
||||
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
auto it = _callbacks.find(obj);
|
||||
if (it == _callbacks.end()) {
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
auto current = it;
|
||||
while (current != _callbacks.end() && current->first == it->first) {
|
||||
auto &[_, cbData] = *current;
|
||||
if (pressedKey != cbData.key) {
|
||||
++current;
|
||||
continue;
|
||||
}
|
||||
cbData.func();
|
||||
++current;
|
||||
continue;
|
||||
}
|
||||
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
} // 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