mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 04:36:21 -05:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6932de866d | ||
|
|
00db0cf7c4 | ||
|
|
e9baf27ca2 | ||
|
|
b1a5db0c9c | ||
|
|
8f3b868fd9 | ||
|
|
b3bf89840b | ||
|
|
84f7d0d214 | ||
|
|
e1164c4fa3 | ||
|
|
4534b23bad | ||
|
|
5d6a693f36 | ||
|
|
a82662c8f4 | ||
|
|
602675b3b3 | ||
|
|
9551519cb9 | ||
|
|
badce063eb | ||
|
|
10d45c67d6 | ||
|
|
0b77ef5081 | ||
|
|
8f54e71e61 | ||
|
|
16136b8741 | ||
|
|
02d5051974 | ||
|
|
078d62fa18 | ||
|
|
8aa6a7df2c | ||
|
|
1494b1db6c | ||
|
|
b4b3dc5a2b | ||
|
|
ee41a8d58b | ||
|
|
5f2237ac2a | ||
|
|
6fb76e7e07 | ||
|
|
ba094372a9 | ||
|
|
0c886c8679 | ||
|
|
d9f05d3f7b | ||
|
|
c99b5f1feb | ||
|
|
a3b3cf9818 | ||
|
|
ca3bbf5660 | ||
|
|
18524761a6 | ||
|
|
85222aed33 | ||
|
|
84132f7c37 | ||
|
|
ead664763f | ||
|
|
a2fa16f2d7 | ||
|
|
75edcffac9 | ||
|
|
dd5bcf425a | ||
|
|
de32e1b18e | ||
|
|
1d412a818d | ||
|
|
c8e5b561ef | ||
|
|
a1702dc798 | ||
|
|
ae571583fc | ||
|
|
c4f70657d9 | ||
|
|
7901a988af | ||
|
|
d2b70bbc6b | ||
|
|
4d22a539f0 | ||
|
|
4e561320f7 | ||
|
|
0dfa4fe2c0 | ||
|
|
4cac4584f3 | ||
|
|
d20a975c4f | ||
|
|
756d7bbd3c | ||
|
|
395a18fa4c | ||
|
|
2ea00d94c5 | ||
|
|
058e941a46 | ||
|
|
ea4a951554 | ||
|
|
3c355ac6fe | ||
|
|
37606e274c | ||
|
|
3e8d6e103a | ||
|
|
4cae420ade | ||
|
|
b27a11931a | ||
|
|
92616bed6b | ||
|
|
b3f38851b6 |
@@ -22,7 +22,7 @@ runs:
|
||||
- name: Setup cmake
|
||||
uses: jwlawson/actions-setup-cmake@v1.13
|
||||
with:
|
||||
cmake-version: '3.24.x'
|
||||
cmake-version: '3.x.x'
|
||||
|
||||
- name: Restore cached dependencies
|
||||
id: restore-cache
|
||||
|
||||
44
.github/scripts/.build-deps.zsh
vendored
44
.github/scripts/.build-deps.zsh
vendored
@@ -394,8 +394,11 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
|
||||
popd
|
||||
|
||||
pushd ${advss_dep_path}
|
||||
log_info "Prepare openssl ..."
|
||||
rm -rf ${advss_dep_path}/openssl ${advss_dep_path}/openssl_build
|
||||
mkdir ${advss_dep_path}/openssl_build
|
||||
pushd ${advss_dep_path}/openssl_build
|
||||
|
||||
rm -rf openssl
|
||||
git clone https://github.com/openssl/openssl.git --branch openssl-3.1.2 --depth 1
|
||||
mv openssl openssl_x86
|
||||
@@ -403,25 +406,27 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
|
||||
log_info "Building openssl x86 ..."
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.9
|
||||
cd openssl_x86
|
||||
./Configure darwin64-x86_64-cc shared
|
||||
make
|
||||
pushd openssl_x86
|
||||
./Configure darwin64-x86_64-cc no-shared no-module no-zlib --prefix=${advss_dep_path}
|
||||
make -j$(nproc)
|
||||
popd
|
||||
|
||||
log_info "Building openssl arm ..."
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.15
|
||||
cd ../openssl_arm
|
||||
./Configure enable-rc5 zlib darwin64-arm64-cc no-asm
|
||||
make
|
||||
pushd openssl_arm
|
||||
./Configure enable-rc5 darwin64-arm64-cc no-shared no-module no-asm no-zlib --prefix=${advss_dep_path}
|
||||
make -j$(nproc)
|
||||
|
||||
log_info "Install openssl ..."
|
||||
make install
|
||||
popd
|
||||
|
||||
log_info "Combine arm and x86 openssl binaries ..."
|
||||
cd ..
|
||||
mkdir openssl-combined
|
||||
lipo -create openssl_x86/libcrypto.a openssl_arm/libcrypto.a -output openssl-combined/libcrypto.a
|
||||
lipo -create openssl_x86/libssl.a openssl_arm/libssl.a -output openssl-combined/libssl.a
|
||||
lipo -create openssl_x86/libcrypto.a openssl_arm/libcrypto.a -output ${advss_dep_path}/lib/libcrypto.a
|
||||
lipo -create openssl_x86/libssl.a openssl_arm/libssl.a -output ${advss_dep_path}/lib/libssl.a
|
||||
|
||||
log_info "Clean up openssl dir ..."
|
||||
mv openssl_x86 openssl
|
||||
rm -rf openssl_arm
|
||||
rm -rf openssl_x86 openssl_arm
|
||||
popd
|
||||
|
||||
pushd ${project_root}/deps/libusb
|
||||
@@ -439,14 +444,16 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
mkdir ${project_root}/deps/libusb/out_x86
|
||||
./autogen.sh
|
||||
./configure --host=x86_64-apple-darwin --prefix=${advss_dep_path}
|
||||
make && make install
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
log_info "Configure libusb arm ..."
|
||||
make clean
|
||||
rm -r ${project_root}/deps/libusb/out_x86
|
||||
mkdir ${project_root}/deps/libusb/out_x86
|
||||
./configure --host=aarch64-apple-darwin --prefix=${project_root}/deps/libusb/out_x86
|
||||
make && make install
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
log_info "Building libusb arm ..."
|
||||
make clean
|
||||
@@ -459,7 +466,8 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.15
|
||||
mkdir ${project_root}/deps/libusb/out_arm
|
||||
./configure --host=aarch64-apple-darwin --prefix=${project_root}/deps/libusb/out_arm
|
||||
make && make install
|
||||
make -j$(nproc)
|
||||
make install
|
||||
|
||||
log_info "Combine arm and x86 libusb binaries ..."
|
||||
lipo -create ${project_root}/deps/libusb/out_x86/lib/libusb-1.0.0.dylib \
|
||||
@@ -491,8 +499,8 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
|
||||
-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
|
||||
-DPAHO_WITH_SSL=ON
|
||||
-DOPENSSL_USE_STATIC_LIBS=ON
|
||||
)
|
||||
|
||||
pushd ${mqtt_dir}
|
||||
|
||||
6
.github/scripts/.build.zsh
vendored
6
.github/scripts/.build.zsh
vendored
@@ -253,12 +253,8 @@ ${_usage_host:-}"
|
||||
macos-*)
|
||||
if (( ${+CI} )) typeset -gx NSUnbufferedIO=YES
|
||||
|
||||
local openssl_lib_dir="${advss_deps_path}/openssl-combined/"
|
||||
local openssl_include_dir="${advss_deps_path}/openssl/include"
|
||||
|
||||
cmake_args+=(
|
||||
-DOPENSSL_INCLUDE_DIR="${openssl_include_dir}"
|
||||
-DOPENSSL_LIBRARIES="${openssl_lib_dir}/libcrypto.a;${openssl_lib_dir}/libssl.a"
|
||||
-DCMAKE_PREFIX_PATH="${advss_deps_path}"
|
||||
--preset ${_preset}
|
||||
)
|
||||
|
||||
|
||||
3
.github/scripts/.package.zsh
vendored
3
.github/scripts/.package.zsh
vendored
@@ -258,6 +258,9 @@ ${_usage_host:-}"
|
||||
pushd ${project_root}
|
||||
cmake --build build_${target##*-} --config ${config} -t package ${cmake_args}
|
||||
|
||||
# Mark certain deps as optional
|
||||
build-aux/CI/linux/demote-deps.sh ${project_root}/release/*.deb Recommends '(mqtt)|(opencv)|(tesseract)|(usb)|(x11)'
|
||||
|
||||
if [ ! -e ${project_root}/release/${output_name}.deb ]; then
|
||||
mv ${project_root}/release/*.deb ${project_root}/release/${output_name}.deb
|
||||
mv ${project_root}/release/*.ddeb ${project_root}/release/${output_name}.ddeb
|
||||
|
||||
18
.github/scripts/Build-Deps-Windows.ps1
vendored
18
.github/scripts/Build-Deps-Windows.ps1
vendored
@@ -209,7 +209,9 @@ function Build {
|
||||
$msbuildExe = vswhere -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe | select-object -first 1
|
||||
|
||||
if ($msbuildExe) {
|
||||
$env:CL="/wd5287"
|
||||
Invoke-External $msbuildExe "${LibusbPath}/msvc/libusb.sln" /property:Configuration=Release /property:Platform=x64
|
||||
Remove-Item Env:CL
|
||||
|
||||
$libusbBuildResultDirectory = "${LibusbPath}/build/v143/x64/Release"
|
||||
if (-not (Test-Path -Path $libusbBuildResultDirectory)) {
|
||||
@@ -232,8 +234,24 @@ function Build {
|
||||
"-DCMAKE_PREFIX_PATH:PATH=${OBSDepPath}"
|
||||
"-DCMAKE_INSTALL_PREFIX:PATH=${ADVSSDepPath}"
|
||||
"-DPAHO_WITH_MQTT_C=ON"
|
||||
"-DPAHO_WITH_SSL=ON"
|
||||
)
|
||||
|
||||
# Try to find OpenSSL installed via winget
|
||||
$pf64 = Join-Path $Env:ProgramFiles "OpenSSL-Win64"
|
||||
$pf = Join-Path $Env:ProgramFiles "OpenSSL"
|
||||
$possibleDirs = @($pf64, $pf)
|
||||
$opensslDir = $possibleDirs | Where-Object { Test-Path (Join-Path $_ "include\openssl\ssl.h") } | Select-Object -First 1
|
||||
|
||||
if ($opensslDir) {
|
||||
Write-Host "Detected OpenSSL at: $opensslDir"
|
||||
$MqttCmakeArgs += "-DOPENSSL_ROOT_DIR=$opensslDir"
|
||||
$MqttCmakeArgs += "-DOPENSSL_CRYPTO_LIBRARY=$opensslDir\lib\VC\x64\MD\libcrypto.lib"
|
||||
$MqttCmakeArgs += "-DOPENSSL_SSL_LIBRARY=$opensslDir\lib\VC\x64\MD\libssl.lib"
|
||||
} else {
|
||||
Write-Warning "OpenSSL not found - maybe cmake will find it ..."
|
||||
}
|
||||
|
||||
Log-Information "Configuring paho.mqtt.cpp..."
|
||||
Invoke-External cmake -S ${MqttPath} -B ${MqttBuildPath} @MqttCmakeArgs
|
||||
|
||||
|
||||
4
.github/scripts/utils.zsh/check_macos
vendored
4
.github/scripts/utils.zsh/check_macos
vendored
@@ -18,5 +18,7 @@ if (( ! ${+commands[brew]} )) {
|
||||
}
|
||||
|
||||
brew bundle --file ${SCRIPT_HOME}/.Brewfile
|
||||
rehash
|
||||
# Workaround to make sure locally built openssl is picked up by cmake
|
||||
brew uninstall --ignore-dependencies openssl@3 || true
|
||||
rehash || true
|
||||
log_group
|
||||
|
||||
1
.github/scripts/utils.zsh/setup_ccache
vendored
1
.github/scripts/utils.zsh/setup_ccache
vendored
@@ -10,7 +10,6 @@ if (( ${+commands[ccache]} )) {
|
||||
|
||||
typeset -gx CCACHE_CONFIGPATH="${project_root}/.ccache.conf"
|
||||
|
||||
ccache --set-config=run_second_cpp=true
|
||||
ccache --set-config=direct_mode=true
|
||||
ccache --set-config=inode_cache=true
|
||||
ccache --set-config=compiler_check=content
|
||||
|
||||
1
.github/scripts/utils.zsh/setup_linux
vendored
1
.github/scripts/utils.zsh/setup_linux
vendored
@@ -41,6 +41,7 @@ if (( ! (${skips[(Ie)all]} + ${skips[(Ie)deps]}) )) {
|
||||
sudo apt-get install ${apt_args} \
|
||||
build-essential \
|
||||
libgles2-mesa-dev \
|
||||
libsimde-dev \
|
||||
obs-studio
|
||||
|
||||
local -a _qt_packages=()
|
||||
|
||||
10
.github/workflows/build-project.yaml
vendored
10
.github/workflows/build-project.yaml
vendored
@@ -6,7 +6,7 @@ on:
|
||||
description: "Project name detected by parsing build spec file"
|
||||
value: ${{ jobs.check-event.outputs.pluginName }}
|
||||
env:
|
||||
DEP_DIR: .deps/advss-build-dependencies
|
||||
DEP_DIR: .deps/advss-build-dependencies-3
|
||||
jobs:
|
||||
check-event:
|
||||
name: Check GitHub Event Data 🔎
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
macos-build:
|
||||
name: Build for macOS 🍏
|
||||
runs-on: macos-14
|
||||
runs-on: macos-15
|
||||
needs: check-event
|
||||
defaults:
|
||||
run:
|
||||
@@ -107,8 +107,8 @@ jobs:
|
||||
print "pluginName=${product_name}" >> $GITHUB_OUTPUT
|
||||
print "pluginVersion=${git_tag}" >> $GITHUB_OUTPUT
|
||||
|
||||
print '::group::Enable Xcode 15.2'
|
||||
sudo xcode-select --switch /Applications/Xcode_15.2.app/Contents/Developer
|
||||
print '::group::Enable Xcode 16.1'
|
||||
sudo xcode-select --switch /Applications/Xcode_16.1.0.app/Contents/Developer
|
||||
print '::endgroup::'
|
||||
|
||||
- uses: actions/cache@v4
|
||||
@@ -213,7 +213,7 @@ jobs:
|
||||
- name: Set up CMake 🏗️
|
||||
uses: jwlawson/actions-setup-cmake@v1.13
|
||||
with:
|
||||
cmake-version: '3.24.x'
|
||||
cmake-version: '3.x.x'
|
||||
|
||||
- name: Set up Homebrew 🍺
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
|
||||
@@ -34,6 +34,11 @@ include(cmake/common/get_git_revision_description.cmake)
|
||||
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
|
||||
git_describe(GIT_TAG)
|
||||
|
||||
# Helper for OpenSSL
|
||||
if(OS_WINDOWS)
|
||||
include(cmake/windows/wingetssl.cmake)
|
||||
endif()
|
||||
|
||||
if(${GIT_TAG} STREQUAL "GIT-NOTFOUND")
|
||||
set(GIT_TAG ${PROJECT_VERSION})
|
||||
endif()
|
||||
@@ -123,6 +128,10 @@ target_sources(
|
||||
lib/macro/macro-condition.hpp
|
||||
lib/macro/macro-dock.cpp
|
||||
lib/macro/macro-dock.hpp
|
||||
lib/macro/macro-dock-settings.hpp
|
||||
lib/macro/macro-dock-settings.cpp
|
||||
lib/macro/macro-dock-window.cpp
|
||||
lib/macro/macro-dock-window.hpp
|
||||
lib/macro/macro-edit.cpp
|
||||
lib/macro/macro-edit.hpp
|
||||
lib/macro/macro-export-import-dialog.cpp
|
||||
@@ -143,12 +152,15 @@ target_sources(
|
||||
lib/macro/macro-segment-list.hpp
|
||||
lib/macro/macro-segment-selection.cpp
|
||||
lib/macro/macro-segment-selection.hpp
|
||||
lib/macro/macro-segment-unknown.hpp
|
||||
lib/macro/macro-segment.cpp
|
||||
lib/macro/macro-segment.hpp
|
||||
lib/macro/macro-selection.cpp
|
||||
lib/macro/macro-selection.hpp
|
||||
lib/macro/macro-settings.cpp
|
||||
lib/macro/macro-settings.hpp
|
||||
lib/macro/macro-signals.cpp
|
||||
lib/macro/macro-signals.hpp
|
||||
lib/macro/macro-tab.cpp
|
||||
lib/macro/macro-tree.cpp
|
||||
lib/macro/macro-tree.hpp
|
||||
@@ -166,6 +178,8 @@ target_sources(
|
||||
lib/utils/auto-update-tooltip-label.hpp
|
||||
lib/utils/backup.cpp
|
||||
lib/utils/backup.hpp
|
||||
lib/utils/canvas-helpers.cpp
|
||||
lib/utils/canvas-helpers.hpp
|
||||
lib/utils/condition-logic.cpp
|
||||
lib/utils/condition-logic.hpp
|
||||
lib/utils/curl-helper.cpp
|
||||
|
||||
126
build-aux/CI/linux/demote-deps.sh
Executable file
126
build-aux/CI/linux/demote-deps.sh
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env bash
|
||||
# Usage: demote_deps.sh <in.deb> [Recommends|Suggests] [regex]
|
||||
# Example: demote_deps.sh build/advanced-scene-switcher_1.31.0_amd64.deb Recommends 'opencv'
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $0 <in.deb> [Recommends|Suggests] [regex]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IN_DEB="$1"
|
||||
DEST_FIELD="${2:-Recommends}" # Recommends or Suggests
|
||||
MATCH_REGEX="${3:-opencv}" # regex to match packages to demote
|
||||
|
||||
echo "Demoting dependencies matching '${MATCH_REGEX}' to ${DEST_FIELD}"
|
||||
|
||||
TMPDIR="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMPDIR"' EXIT
|
||||
|
||||
dpkg-deb -R "$IN_DEB" "$TMPDIR"
|
||||
CONTROL="$TMPDIR/DEBIAN/control"
|
||||
|
||||
# Read a field (single line value), handling continuation lines starting with a space.
|
||||
get_field() {
|
||||
local key="$1"
|
||||
awk -v key="$key" '
|
||||
BEGIN { val=""; collecting=0 }
|
||||
$0 ~ "^" key ":" {
|
||||
collecting=1
|
||||
sub("^" key ":[[:space:]]*", "", $0)
|
||||
val=$0
|
||||
next
|
||||
}
|
||||
collecting==1 {
|
||||
if ($0 ~ "^[[:space:]]") {
|
||||
sub("^[[:space:]]+", "", $0)
|
||||
val = val " " $0
|
||||
next
|
||||
} else {
|
||||
collecting=0
|
||||
}
|
||||
}
|
||||
END { print val }
|
||||
' "$CONTROL"
|
||||
}
|
||||
|
||||
# Split a comma-separated list into lines, trimming whitespace
|
||||
split_csv() {
|
||||
tr ',' '\n' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//' | sed '/^$/d'
|
||||
}
|
||||
|
||||
# Join with ", "
|
||||
join_csv() {
|
||||
awk 'BEGIN{first=1}{ if(!first) printf(", "); printf("%s",$0); first=0 } END{print ""}'
|
||||
}
|
||||
|
||||
# Deduplicate while preserving order
|
||||
dedup() {
|
||||
awk '!seen[$0]++'
|
||||
}
|
||||
|
||||
DEPENDS_VAL="$(get_field Depends)"
|
||||
EXIST_DEST_VAL="$(get_field "$DEST_FIELD")"
|
||||
|
||||
# Separate opencv-matching vs the rest (preserve tokens exactly)
|
||||
mapfile -t DEPENDS_ARR < <(printf "%s\n" "$DEPENDS_VAL" | split_csv)
|
||||
declare -a MOVED=()
|
||||
declare -a KEPT=()
|
||||
for item in "${DEPENDS_ARR[@]}"; do
|
||||
# Skip empty just in case
|
||||
[[ -z "$item" ]] && continue
|
||||
if [[ "$item" =~ $MATCH_REGEX ]]; then
|
||||
MOVED+=("$item")
|
||||
else
|
||||
KEPT+=("$item")
|
||||
fi
|
||||
done
|
||||
|
||||
# Merge with existing dest field
|
||||
if [[ -n "$EXIST_DEST_VAL" ]]; then
|
||||
mapfile -t EXIST_DEST_ARR < <(printf "%s\n" "$EXIST_DEST_VAL" | split_csv)
|
||||
MOVED+=("${EXIST_DEST_ARR[@]}")
|
||||
fi
|
||||
|
||||
# De-duplicate
|
||||
mapfile -t MOVED < <(printf "%s\n" "${MOVED[@]:-}" | sed '/^$/d' | dedup)
|
||||
mapfile -t KEPT < <(printf "%s\n" "${KEPT[@]:-}" | sed '/^$/d' | dedup)
|
||||
|
||||
# Rebuild values
|
||||
NEW_DEPENDS="$(printf "%s\n" "${KEPT[@]:-}" | join_csv || true)"
|
||||
NEW_DEST="$(printf "%s\n" "${MOVED[@]:-}" | join_csv || true)"
|
||||
|
||||
# Write a cleaned control (remove existing Depends/Recommends/Suggests incl. continuations)
|
||||
awk '
|
||||
BEGIN { skip=0 }
|
||||
{
|
||||
if ($0 ~ "^(Depends|Recommends|Suggests):") { skip=1; next }
|
||||
if (skip==1) {
|
||||
if ($0 ~ "^[[:space:]]") { next } else { skip=0 }
|
||||
}
|
||||
print
|
||||
}
|
||||
' "$CONTROL" > "$CONTROL.clean"
|
||||
|
||||
# Append the rebuilt fields
|
||||
{
|
||||
cat "$CONTROL.clean"
|
||||
if [[ -n "$NEW_DEPENDS" ]]; then
|
||||
echo "Depends: $NEW_DEPENDS"
|
||||
fi
|
||||
if [[ -n "$NEW_DEST" ]]; then
|
||||
echo "$DEST_FIELD: $NEW_DEST"
|
||||
fi
|
||||
} > "$CONTROL.new"
|
||||
|
||||
# Clean up empty lines
|
||||
sed -i '/^[[:space:]]*$/d' "$CONTROL.new"
|
||||
|
||||
mv "$CONTROL.new" "$CONTROL"
|
||||
rm -f "$CONTROL.clean"
|
||||
|
||||
# Repack
|
||||
rm -f "${IN_DEB}"
|
||||
OUT_DEB="${IN_DEB}"
|
||||
dpkg-deb -b "$TMPDIR" "$OUT_DEB" >/dev/null
|
||||
echo "$OUT_DEB"
|
||||
@@ -1,33 +1,33 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"obs-studio": {
|
||||
"version": "30.1.2",
|
||||
"version": "31.1.1",
|
||||
"baseUrl": "https://github.com/obsproject/obs-studio/archive/refs/tags",
|
||||
"label": "OBS sources",
|
||||
"hashes": {
|
||||
"macos": "490bae1c392b3b344b0270afd8cb887da4bc50bd92c0c426e96713c1ccb9701a",
|
||||
"windows-x64": "c2dd03fa7fd01fad5beafce8f7156da11f9ed9a588373fd40b44a06f4c03b867"
|
||||
"macos": "39751f067bacc13d44b116c5138491b5f1391f91516d3d590d874edd21292291",
|
||||
"windows-x64": "2c8427c10b55ac6d68008df2e9a3e82f4647aaad18f105e30d4713c2de678ccf"
|
||||
}
|
||||
},
|
||||
"prebuilt": {
|
||||
"version": "2024-03-19",
|
||||
"version": "2025-07-11",
|
||||
"baseUrl": "https://github.com/obsproject/obs-deps/releases/download",
|
||||
"label": "Pre-Built obs-deps",
|
||||
"hashes": {
|
||||
"macos": "2e9bfb55a5e0e4c1086fa1fda4cf268debfead473089df2aaea80e1c7a3ca7ff",
|
||||
"windows-x64": "6e86068371526a967e805f6f9903f9407adb683c21820db5f07da8f30d11e998"
|
||||
"macos": "495687e63383d1a287684b6e2e9bfe246bb8f156fe265926afb1a325af1edd2a",
|
||||
"windows-x64": "c8c642c1070dc31ce9a0f1e4cef5bb992f4bff4882255788b5da12129e85caa7"
|
||||
}
|
||||
},
|
||||
"qt6": {
|
||||
"version": "2024-03-19",
|
||||
"version": "2025-07-11",
|
||||
"baseUrl": "https://github.com/obsproject/obs-deps/releases/download",
|
||||
"label": "Pre-Built Qt6",
|
||||
"hashes": {
|
||||
"macos": "694f1e639c017e3b1f456f735330dc5afae287cbea85757101af1368de3142c8",
|
||||
"windows-x64": "72d1df34a0ef7413a681d5fcc88cae81da60adc03dcd23ef17862ab170bcc0dd"
|
||||
"macos": "d3f5f04b6ea486e032530bdf0187cbda9a54e0a49621a4c8ba984c5023998867",
|
||||
"windows-x64": "0e76bf0555dd5382838850b748d3dcfab44a1e1058441309ab54e1a65b156d0a"
|
||||
},
|
||||
"debugSymbols": {
|
||||
"windows-x64": "fbddd1f659c360f2291911ac5709b67b6f8182e6bca519d24712e4f6fd3cc865"
|
||||
"windows-x64": "11b7be92cf66a273299b8f3515c07a5cfb61614b59a4e67f7fc5ecba5e2bdf21"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -65,17 +65,16 @@ function(_setup_obs_studio)
|
||||
|
||||
if(OS_WINDOWS)
|
||||
set(_cmake_generator "${CMAKE_GENERATOR}")
|
||||
set(_cmake_arch "-A ${arch}")
|
||||
set(_cmake_arch
|
||||
"-A ${arch},version=${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}")
|
||||
set(_cmake_extra
|
||||
"-DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION} -DCMAKE_ENABLE_SCRIPTING=OFF"
|
||||
)
|
||||
set(_cmake_version "2.0.0")
|
||||
elseif(OS_MACOS)
|
||||
set(_cmake_generator "Xcode")
|
||||
set(_cmake_arch "-DCMAKE_OSX_ARCHITECTURES:STRING='arm64;x86_64'")
|
||||
set(_cmake_extra
|
||||
"-DCMAKE_OSX_DEPLOYMENT_TARGET=${CMAKE_OSX_DEPLOYMENT_TARGET}")
|
||||
set(_cmake_version "3.0.0")
|
||||
endif()
|
||||
|
||||
message(STATUS "Configure ${label} (${arch})")
|
||||
@@ -83,32 +82,42 @@ function(_setup_obs_studio)
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}" -S "${dependencies_dir}/${_obs_destination}" -B
|
||||
"${dependencies_dir}/${_obs_destination}/build_${arch}" -G
|
||||
${_cmake_generator} "${_cmake_arch}"
|
||||
-DOBS_CMAKE_VERSION:STRING=${_cmake_version} -DENABLE_PLUGINS:BOOL=OFF
|
||||
-DENABLE_UI:BOOL=OFF -DOBS_VERSION_OVERRIDE:STRING=${_obs_version}
|
||||
${_cmake_generator} "${_cmake_arch}" -DOBS_CMAKE_VERSION:STRING=3.0.0
|
||||
-DENABLE_PLUGINS:BOOL=OFF -DENABLE_FRONTEND:BOOL=OFF
|
||||
-DOBS_VERSION_OVERRIDE:STRING=${_obs_version}
|
||||
"-DCMAKE_PREFIX_PATH='${CMAKE_PREFIX_PATH}'" ${_is_fresh} ${_cmake_extra}
|
||||
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
|
||||
OUTPUT_QUIET)
|
||||
message(STATUS "Configure ${label} (${arch}) - done")
|
||||
|
||||
message(STATUS "Build ${label} (${arch})")
|
||||
message(STATUS "Build ${label} (Debug - ${arch})")
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" --build build_${arch} --target obs-frontend-api
|
||||
--config Debug --parallel
|
||||
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
|
||||
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
|
||||
OUTPUT_QUIET)
|
||||
message(STATUS "Build ${label} (${arch}) - done")
|
||||
message(STATUS "Build ${label} (Debug - ${arch}) - done")
|
||||
|
||||
message(STATUS "Build ${label} (Release - ${arch})")
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" --build build_${arch} --target obs-frontend-api
|
||||
--config Release --parallel
|
||||
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
|
||||
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
|
||||
OUTPUT_QUIET)
|
||||
message(STATUS "Build ${label} (Reelase - ${arch}) - done")
|
||||
|
||||
message(STATUS "Install ${label} (${arch})")
|
||||
if(OS_WINDOWS)
|
||||
set(_cmake_extra "--component obs_libraries")
|
||||
else()
|
||||
set(_cmake_extra "")
|
||||
endif()
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" --install build_${arch} --component Development
|
||||
--config Debug --prefix "${dependencies_dir}" ${_cmake_extra}
|
||||
--config Debug --prefix "${dependencies_dir}"
|
||||
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
|
||||
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
|
||||
OUTPUT_QUIET)
|
||||
execute_process(
|
||||
COMMAND "${CMAKE_COMMAND}" --install build_${arch} --component Development
|
||||
--config Release --prefix "${dependencies_dir}"
|
||||
WORKING_DIRECTORY "${dependencies_dir}/${_obs_destination}"
|
||||
RESULT_VARIABLE _process_result COMMAND_ERROR_IS_FATAL ANY
|
||||
OUTPUT_QUIET)
|
||||
|
||||
@@ -22,6 +22,7 @@ SolidCompression=yes
|
||||
DirExistsWarning=no
|
||||
SetupIconFile=installer.ico
|
||||
UninstallDisplayIcon={app}\data\obs-plugins\advanced-scene-switcher\res\images\logo.ico
|
||||
DisableDirPage=no
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
78
cmake/windows/wingetssl.cmake
Normal file
78
cmake/windows/wingetssl.cmake
Normal file
@@ -0,0 +1,78 @@
|
||||
# ---------------------------------------------------------------------------
|
||||
# Detects OpenSSL installed via winget or other common Windows locations,
|
||||
# without requiring the user to manually set OPENSSL_ROOT_DIR.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
if(WIN32 AND (NOT OpenSSL_FOUND))
|
||||
|
||||
set(_openssl_roots
|
||||
"$ENV{ProgramFiles}/OpenSSL-Win64" "$ENV{ProgramFiles}/OpenSSL"
|
||||
"$ENV{ProgramW6432}/OpenSSL-Win64")
|
||||
|
||||
set(_openssl_lib_suffixes "lib/VC/x64/MD" "lib/VC/x64/MDd" "lib/VC/x64/MT"
|
||||
"lib/VC/x64/MTd" "lib")
|
||||
|
||||
# Determine which configuration we're building
|
||||
if(CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||
set(_is_debug TRUE)
|
||||
else()
|
||||
set(_is_debug FALSE)
|
||||
endif()
|
||||
|
||||
# Determine which runtime we use Default to /MD (shared CRT)
|
||||
set(_crt_kind "MD")
|
||||
if(MSVC)
|
||||
if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "MultiThreaded")
|
||||
if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "Debug")
|
||||
set(_crt_kind "MTd")
|
||||
else()
|
||||
set(_crt_kind "MT")
|
||||
endif()
|
||||
else()
|
||||
if(_is_debug)
|
||||
set(_crt_kind "MDd")
|
||||
else()
|
||||
set(_crt_kind "MD")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Looking for OpenSSL built with CRT variant: ${_crt_kind}")
|
||||
|
||||
# Try to find the root and corresponding lib path
|
||||
foreach(_root ${_openssl_roots})
|
||||
if(EXISTS "${_root}/include/openssl/ssl.h")
|
||||
foreach(_suffix ${_openssl_lib_suffixes})
|
||||
if(_suffix MATCHES "${_crt_kind}$"
|
||||
AND EXISTS "${_root}/${_suffix}/libcrypto.lib")
|
||||
set(OPENSSL_ROOT_DIR
|
||||
"${_root}"
|
||||
CACHE PATH "Path to OpenSSL root")
|
||||
set(OPENSSL_CRYPTO_LIBRARY
|
||||
"${_root}/${_suffix}/libcrypto.lib"
|
||||
CACHE FILEPATH "OpenSSL crypto lib")
|
||||
set(OPENSSL_SSL_LIBRARY
|
||||
"${_root}/${_suffix}/libssl.lib"
|
||||
CACHE FILEPATH "OpenSSL ssl lib")
|
||||
set(OPENSSL_INCLUDE_DIR
|
||||
"${_root}/include"
|
||||
CACHE PATH "OpenSSL include dir")
|
||||
set(OpenSSL_FOUND
|
||||
TRUE
|
||||
CACHE BOOL "Whether OpenSSL was found")
|
||||
message(STATUS "Found OpenSSL at: ${_root}/${_suffix}")
|
||||
return()
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
if(OpenSSL_FOUND)
|
||||
break()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(NOT OpenSSL_FOUND)
|
||||
message(WARNING "Could not auto-detect OpenSSL under Program Files. "
|
||||
"Might have to set OPENSSL_ROOT_DIR manually.")
|
||||
endif()
|
||||
|
||||
endif()
|
||||
@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Aktiviere den Szenenwe
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Aktiviere den Szenenwechsler nicht"
|
||||
AdvSceneSwitcher.generalTab.status.start="Start"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Stop"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Starte auotmatischen den Szenenwechsler beim:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Starte auotmatischen den Szenenwechsler beim:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Niemals"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Aufnehmen"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Streamen"
|
||||
@@ -383,8 +383,6 @@ AdvSceneSwitcher.condition.variable.type.greaterThanVariable="ist größer als d
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Szene wechseln"
|
||||
AdvSceneSwitcher.action.scene.entry="Wechsle{{sceneTypes}}Szene zu{{scenes}}mittels{{transitions}}mit einer Dauer von{{duration}}Sekunden"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Wechsle{{sceneTypes}}Szene zu{{scenes}}mittels{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Warten, bis der Übergang zur Zielszene abgeschlossen ist"
|
||||
AdvSceneSwitcher.action.wait="Warten"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fixe"
|
||||
@@ -466,7 +464,7 @@ AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenw
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="Einstellungen importieren aus"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Hinweis: Die Aktion wird ignoriert, solange das Einstellungsfenster geöffnet ist."
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Virtuelle Kamera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Virtuelle Kamera stoppen"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Virtuelle Kamera starten"
|
||||
|
||||
@@ -4,7 +4,7 @@ AdvSceneSwitcher.windowTitle="Advanced Scene Switcher"
|
||||
# General Tab
|
||||
AdvSceneSwitcher.generalTab.title="General"
|
||||
AdvSceneSwitcher.generalTab.status="Status"
|
||||
AdvSceneSwitcher.generalTab.status.hotkeytips="Hotkeys can be defined in the OBS settings"
|
||||
AdvSceneSwitcher.generalTab.status.hotkeytips="Start/stop hotkeys can be defined in the OBS settings"
|
||||
AdvSceneSwitcher.generalTab.status.currentStatus="Advanced Scene Switcher is:"
|
||||
AdvSceneSwitcher.generalTab.status.onStartup="On startup of OBS:"
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="Start the scene switcher if it was running"
|
||||
@@ -12,11 +12,12 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Always start the scene
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Do not start the scene switcher"
|
||||
AdvSceneSwitcher.generalTab.status.start="Start"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Stop"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Automatically start the scene switcher when:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Automatically start the scene switcher when:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Never"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Recording"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Streaming"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming="Recording or Streaming"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.scene="Automatically start the scene switcher on scene:"
|
||||
AdvSceneSwitcher.generalTab.status.checkInterval="Check conditions every"
|
||||
AdvSceneSwitcher.generalTab.status.checkIntervalTooLow="⚠️ Conflict with macro \"%1\"!"
|
||||
AdvSceneSwitcher.generalTab.status.checkIntervalTooLow.tooltip="Macro \"%1\" won't be able to check its condition at the desired interval of %2.\nEither change the condition check value on the General tab or in the settings of macro \"%3\"."
|
||||
@@ -231,6 +232,8 @@ AdvSceneSwitcher.macroTab.pauseStateSaveBehavior.persist="The state the macro wa
|
||||
AdvSceneSwitcher.macroTab.pauseStateSaveBehavior.pause="Paused"
|
||||
AdvSceneSwitcher.macroTab.pauseStateSaveBehavior.unpause="Unpaused"
|
||||
AdvSceneSwitcher.macroTab.currentRegisterDock="Register dock widget to control the pause state of selected macro or run it manually"
|
||||
AdvSceneSwitcher.macroTab.currentIsStandaloneDock="Is standalone dock"
|
||||
AdvSceneSwitcher.macroTab.currentDockWindowName="Add to macro dock with name:"
|
||||
AdvSceneSwitcher.macroTab.currentDockAddRunButton="Add button to run the macro"
|
||||
AdvSceneSwitcher.macroTab.currentDockAddPauseButton="Add button to pause or unpause the macro"
|
||||
AdvSceneSwitcher.macroTab.currentDockAddStatusLabel="Add status label"
|
||||
@@ -323,6 +326,7 @@ AdvSceneSwitcher.condition.scene.type.previousPattern="Previous scene matches"
|
||||
AdvSceneSwitcher.condition.scene.type.previewPattern="Preview scene matches"
|
||||
AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="During transition check for transition target scene"
|
||||
AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="During transition check for transition source scene"
|
||||
AdvSceneSwitcher.condition.scene.canvasNotSupported="This check is not supported for the currently selected canvas \"%1\""
|
||||
AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
|
||||
AdvSceneSwitcher.condition.window="Window"
|
||||
@@ -338,6 +342,9 @@ AdvSceneSwitcher.condition.file="File"
|
||||
AdvSceneSwitcher.condition.file.type.match="matches"
|
||||
AdvSceneSwitcher.condition.file.type.contentChange="content changed"
|
||||
AdvSceneSwitcher.condition.file.type.dateChange="modification date changed"
|
||||
AdvSceneSwitcher.condition.file.type.exists="exists"
|
||||
AdvSceneSwitcher.condition.file.type.isFile="is a file"
|
||||
AdvSceneSwitcher.condition.file.type.isFolder="is a folder"
|
||||
AdvSceneSwitcher.condition.file.remote="Remote file"
|
||||
AdvSceneSwitcher.condition.file.local="Local file"
|
||||
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}{{useRegex}}"
|
||||
@@ -487,6 +494,7 @@ AdvSceneSwitcher.condition.macro.type.multiState="Multiple macro condition state
|
||||
AdvSceneSwitcher.condition.macro.type.actionDisabled="Macro action disabled"
|
||||
AdvSceneSwitcher.condition.macro.type.actionEnabled="Macro action enabled"
|
||||
AdvSceneSwitcher.condition.macro.type.paused="Macro is paused"
|
||||
AdvSceneSwitcher.condition.macro.type.actionsPerformed="Macro actions were executed"
|
||||
AdvSceneSwitcher.condition.macro.type.selection="{{types}}"
|
||||
AdvSceneSwitcher.condition.macro.count.type.below="Less than"
|
||||
AdvSceneSwitcher.condition.macro.count.type.above="More than"
|
||||
@@ -503,6 +511,7 @@ AdvSceneSwitcher.condition.macro.count.entry.line2="Current count:{{currentCount
|
||||
AdvSceneSwitcher.condition.macro.actionState.disabled.entry="Action{{actionIndex}}of{{macros}}is disabled"
|
||||
AdvSceneSwitcher.condition.macro.actionState.enabled.entry="Action{{actionIndex}}of{{macros}}is enabled"
|
||||
AdvSceneSwitcher.condition.macro.paused.entry="Macro{{macros}}is paused"
|
||||
AdvSceneSwitcher.condition.macro.actionsPerformed.entry="The actions of macro{{macros}}were performed"
|
||||
AdvSceneSwitcher.condition.source="Source"
|
||||
AdvSceneSwitcher.condition.source.type.active="Is active"
|
||||
AdvSceneSwitcher.condition.source.type.showing="Is showing"
|
||||
@@ -699,6 +708,7 @@ AdvSceneSwitcher.condition.twitch.type.event.channel.raid.outbound="Raided someo
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.raid.inbound="Raid to your channel occured"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.shoutout.outbound="Shoutout to someone's channel given"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.shoutout.inbound="Shoutout to your channel received"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.commercial.start="Commercial break started"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.poll.start="Poll started"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.poll.progress="Poll votes changed (progress)"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.poll.end="Poll ended"
|
||||
@@ -814,12 +824,21 @@ AdvSceneSwitcher.condition.script="Script"
|
||||
# Macro Actions
|
||||
AdvSceneSwitcher.action.unknown="Unknown action"
|
||||
AdvSceneSwitcher.action.scene="Switch scene"
|
||||
AdvSceneSwitcher.action.scene.action.fixed="Scene with name"
|
||||
AdvSceneSwitcher.action.scene.action.sceneListNext="Next scene in scene list"
|
||||
AdvSceneSwitcher.action.scene.action.sceneListPrevious="Previous scene in scene list"
|
||||
AdvSceneSwitcher.action.scene.action.sceneListIndex="Scene in scene list at position"
|
||||
AdvSceneSwitcher.action.scene.type.program="Program"
|
||||
AdvSceneSwitcher.action.scene.type.preview="Preview"
|
||||
AdvSceneSwitcher.action.scene.entry="Switch{{sceneTypes}}scene to{{scenes}}using{{transitions}}with a duration of{{duration}}seconds"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Switch{{sceneTypes}}scene to{{scenes}}using{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.entry.preview="Switch{{sceneTypes}}scene to{{scenes}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.fixed="Switch{{sceneTypes}}to{{actions}}{{scenes}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.list="Switch{{sceneTypes}}to{{actions}}on{{canvas}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.list.noCanvasSelection="Switch{{sceneTypes}}to{{actions}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.listIndex="Switch{{sceneTypes}}to{{actions}}{{index}}on{{canvas}}{{sceneNameAtIndex}}"
|
||||
AdvSceneSwitcher.action.scene.layout.action.listIndex.noCanvasSelection="Switch{{sceneTypes}}to{{actions}}{{index}}{{sceneNameAtIndex}}"
|
||||
AdvSceneSwitcher.action.scene.layout.transition="Use transition{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.layout.transitionWithDuration="Use transition{{transitions}}with a duration of{{duration}}seconds"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Wait until transition to target scene is complete"
|
||||
AdvSceneSwitcher.action.scene.canvasNotSupported="Not supported by the currently selected canvas \"%1\""
|
||||
AdvSceneSwitcher.action.wait="Wait"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fixed"
|
||||
AdvSceneSwitcher.action.wait.type.random="random"
|
||||
@@ -978,7 +997,11 @@ AdvSceneSwitcher.action.pluginState.type.import="Import settings from"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Note: Action will be ignored while settings window is opened."
|
||||
AdvSceneSwitcher.action.pluginState.type.terminate="Shut down OBS"
|
||||
AdvSceneSwitcher.action.pluginState.terminateConfirm="OBS will be shut down automatically in 10 seconds!\nDo you want to continue shutting down OBS?"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.type.enableMacroHighlighting="Enable macro highlighting"
|
||||
AdvSceneSwitcher.action.pluginState.type.disableMacroHighlighting="Disable macro highlighting"
|
||||
AdvSceneSwitcher.action.pluginState.type.toggleMacroHighlighting="Toggle macro highlighting"
|
||||
AdvSceneSwitcher.action.pluginState.confirmShutdown="Ask for shutdown confirmation"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Virtual camera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Stop virtual camera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Start virtual camera"
|
||||
@@ -1089,7 +1112,7 @@ AdvSceneSwitcher.action.websocket.api.genericWebsocket="Generic websocket messag
|
||||
AdvSceneSwitcher.action.websocket.type.request="Request"
|
||||
AdvSceneSwitcher.action.websocket.type.event="Event"
|
||||
AdvSceneSwitcher.action.websocket.settingsConflictGeneric="Possible settings conflict: Generic websocket message selection with connection which follows the OBS protocol!"
|
||||
AdvSceneSwitcher.action.websocket.settingsConflictOBS="Possible settings conflict: Connection selected which only supports generic websockte messages while message type requires OBS protocol!"
|
||||
AdvSceneSwitcher.action.websocket.settingsConflictOBS="Possible settings conflict: Connection selected which only supports generic websocket messages while message type requires OBS protocol!"
|
||||
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.request="Send{{api}}of type{{type}}via{{connection}}"
|
||||
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.event="Send{{api}}of type{{type}}to connected clients"
|
||||
AdvSceneSwitcher.action.websocket.entry.generic="Send{{api}}via{{connection}}"
|
||||
@@ -1198,6 +1221,8 @@ AdvSceneSwitcher.action.sceneLock.entry="On{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.twitch="Twitch"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.title.set="Set stream title"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.category.set="Set stream category"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.tags.set="Set stream tags"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.language.set="Set stream language"
|
||||
AdvSceneSwitcher.action.twitch.type.raid.start="Start raid"
|
||||
AdvSceneSwitcher.action.twitch.type.commercial.start="Start commercial"
|
||||
AdvSceneSwitcher.action.twitch.type.marker.create="Create stream marker"
|
||||
@@ -1225,6 +1250,58 @@ AdvSceneSwitcher.action.twitch.announcement.orange="Orange"
|
||||
AdvSceneSwitcher.action.twitch.announcement.purple="Purple"
|
||||
AdvSceneSwitcher.action.twitch.user.getInfo.queryType.id="User Id"
|
||||
AdvSceneSwitcher.action.twitch.user.getInfo.queryType.login="User login"
|
||||
AdvSceneSwitcher.action.twitch.tags.add="Add Channel Tag"
|
||||
AdvSceneSwitcher.action.twitch.tags.getCurrent="Get current channel tags"
|
||||
AdvSceneSwitcher.action.twitch.tags.invalid="Invalid Tag"
|
||||
AdvSceneSwitcher.action.twitch.tags.invalid.info="Tags must be 1–%1 characters long, contain only letters or numbers, and have no spaces or special characters."
|
||||
AdvSceneSwitcher.action.twitch.tags.duplicate="Duplicate Tag"
|
||||
AdvSceneSwitcher.action.twitch.tags.duplicate.info="This tag is already in the list."
|
||||
AdvSceneSwitcher.action.twitch.tags.limit="Tag Limit Reached"
|
||||
AdvSceneSwitcher.action.twitch.tags.limit.info="You can only have up to %1 tags."
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.contentClassification.set="Set content classification labels"
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.debatedSocialIssuesAndPolitics="Discussions or debates about politics or sensitive social issues such as elections, civic integrity, military conflict, and civil rights."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.drugsIntoxication="Excessive tobacco glorification or promotion, any marijuana consumption/use, legal drug and alcohol induced intoxication, discussions of illegal drugs."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.sexualThemes="Content that focuses on sexualized activities, sexual topics, or experiences."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.violentGraphic="Simulations and/or depictions of realistic violence, gore, extreme injury, or death."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.gambling="Participating in or promoting online or in-person gambling, poker, or fantasy sports that involve the exchange of real money."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.profanityVulgarity="Prolonged and repeated use of obscenities, profanities, and vulgarities, especially as a regular part of speech."
|
||||
AdvSceneSwitcher.action.twitch.contentClassification.getCurrent="Get current content classification labels"
|
||||
AdvSceneSwitcher.action.twitch.language.english="English"
|
||||
AdvSceneSwitcher.action.twitch.language.indonesian="Bahasa Indonesia"
|
||||
AdvSceneSwitcher.action.twitch.language.catalan="Català"
|
||||
AdvSceneSwitcher.action.twitch.language.danish="Dansk"
|
||||
AdvSceneSwitcher.action.twitch.language.german="Deutsch"
|
||||
AdvSceneSwitcher.action.twitch.language.spanish="Español"
|
||||
AdvSceneSwitcher.action.twitch.language.french="Français"
|
||||
AdvSceneSwitcher.action.twitch.language.italian="Italiano"
|
||||
AdvSceneSwitcher.action.twitch.language.hungarian="Magyar"
|
||||
AdvSceneSwitcher.action.twitch.language.dutch="Nederlands"
|
||||
AdvSceneSwitcher.action.twitch.language.norwegian="Norsk"
|
||||
AdvSceneSwitcher.action.twitch.language.polish="Polski"
|
||||
AdvSceneSwitcher.action.twitch.language.portuguese="Português"
|
||||
AdvSceneSwitcher.action.twitch.language.romanian="Română"
|
||||
AdvSceneSwitcher.action.twitch.language.slovak="Slovenčina"
|
||||
AdvSceneSwitcher.action.twitch.language.finnish="Suomi"
|
||||
AdvSceneSwitcher.action.twitch.language.swedish="Svenska"
|
||||
AdvSceneSwitcher.action.twitch.language.tagalog="Tagalog"
|
||||
AdvSceneSwitcher.action.twitch.language.vietnamese="Tiếng Việt"
|
||||
AdvSceneSwitcher.action.twitch.language.turkish="Türkçe"
|
||||
AdvSceneSwitcher.action.twitch.language.czech="Čeština"
|
||||
AdvSceneSwitcher.action.twitch.language.greek="Ελληνικά"
|
||||
AdvSceneSwitcher.action.twitch.language.bulgarian="Български"
|
||||
AdvSceneSwitcher.action.twitch.language.russian="Русский"
|
||||
AdvSceneSwitcher.action.twitch.language.ukrainian="Українська"
|
||||
AdvSceneSwitcher.action.twitch.language.arabic="العربية"
|
||||
AdvSceneSwitcher.action.twitch.language.malay="بهاس ملايو"
|
||||
AdvSceneSwitcher.action.twitch.language.hindi="मानक हिन्दी"
|
||||
AdvSceneSwitcher.action.twitch.language.thai="ภาษาไทย"
|
||||
AdvSceneSwitcher.action.twitch.language.chinese="中文"
|
||||
AdvSceneSwitcher.action.twitch.language.japanese="日本語"
|
||||
AdvSceneSwitcher.action.twitch.language.cantonese="粵語"
|
||||
AdvSceneSwitcher.action.twitch.language.korean="한국어"
|
||||
AdvSceneSwitcher.action.twitch.language.asl="American Sign Language"
|
||||
AdvSceneSwitcher.action.twitch.language.other="Other"
|
||||
AdvSceneSwitcher.action.twitch.language.getCurrent="Get current language"
|
||||
AdvSceneSwitcher.action.clipboard="Clipboard"
|
||||
AdvSceneSwitcher.action.clipboard.type.copy.text="Copy text"
|
||||
AdvSceneSwitcher.action.clipboard.type.copy.image="Copy image"
|
||||
@@ -1264,6 +1341,9 @@ AdvSceneSwitcher.action.obsSetting.action.setBaseCanvasX="Set base resolution X
|
||||
AdvSceneSwitcher.action.obsSetting.action.setBaseCanvasY="Set base resolution Y value"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setOutputCanvasX="Set output resolution X value"
|
||||
AdvSceneSwitcher.action.obsSetting.action.setOutputCanvasY="Set output resolution Y value"
|
||||
AdvSceneSwitcher.action.obsSetting.action.enablePreview="Enable preview"
|
||||
AdvSceneSwitcher.action.obsSetting.action.disablePreview="Disable preview"
|
||||
AdvSceneSwitcher.action.obsSetting.action.togglePreview="Toggle preview enable"
|
||||
AdvSceneSwitcher.action.obsSetting.getCurrentValue="Get current value"
|
||||
AdvSceneSwitcher.action.obsSettings.layout="{{actions}}{{fpsType}}{{fpsIntValue}}{{fpsStringValue}}{{canvasSizeValue}}{{getCurrentValue}}"
|
||||
AdvSceneSwitcher.action.script="Script"
|
||||
@@ -1434,6 +1514,13 @@ AdvSceneSwitcher.mqttConnection.name="Name:"
|
||||
AdvSceneSwitcher.mqttConnection.address="Address:"
|
||||
AdvSceneSwitcher.mqttConnection.username="Username:"
|
||||
AdvSceneSwitcher.mqttConnection.password="Password:"
|
||||
AdvSceneSwitcher.mqttConnection.trustStore="Trust store:"
|
||||
AdvSceneSwitcher.mqttConnection.trustStore.help="The file in PEM format containing the public digital certificates trusted by the client."
|
||||
AdvSceneSwitcher.mqttConnection.keyStore="Key store:"
|
||||
AdvSceneSwitcher.mqttConnection.keyStore.help="The file in PEM format containing the public certificate chain of the client.\nIt may also include the client's private key."
|
||||
AdvSceneSwitcher.mqttConnection.privateKey="Private key:"
|
||||
AdvSceneSwitcher.mqttConnection.privateKey.help="If not included in the key store, this is the file in PEM format containing the client's private key."
|
||||
AdvSceneSwitcher.mqttConnection.verifyServerCert="Verify server certificate"
|
||||
AdvSceneSwitcher.mqttConnection.reconnect="Reconnect automatically:"
|
||||
AdvSceneSwitcher.mqttConnection.reconnectDelay="Automatically reconnect after:"
|
||||
AdvSceneSwitcher.mqttConnection.connectOnStart="Connect on startup:"
|
||||
@@ -1479,6 +1566,7 @@ AdvSceneSwitcher.twitchToken.bits.read="Read channel's Bits information."
|
||||
AdvSceneSwitcher.twitchToken.channel.raids.manage="Manage channel's raids."
|
||||
AdvSceneSwitcher.twitchToken.moderator.shoutouts.read="Read channel's shoutouts."
|
||||
AdvSceneSwitcher.twitchToken.moderator.shoutouts.manage="Manage channel's shoutouts."
|
||||
AdvSceneSwitcher.twitchToken.channel.ads.read="Read the ads schedule and details on your channel."
|
||||
AdvSceneSwitcher.twitchToken.channel.polls.read="Read channel's polls' state."
|
||||
AdvSceneSwitcher.twitchToken.channel.polls.manage="Manage channel's polls."
|
||||
AdvSceneSwitcher.twitchToken.channel.predictions.read="Read channel's predictions' state."
|
||||
@@ -1540,6 +1628,9 @@ AdvSceneSwitcher.script.language.select="--select language--"
|
||||
AdvSceneSwitcher.script.language.layout="Script language:{{language}}"
|
||||
AdvSceneSwitcher.script.file.open="Open"
|
||||
AdvSceneSwitcher.script.file.open.failed="Could not open script file!"
|
||||
AdvSceneSwitcher.script.file.warning.notFound="Warning: The given file path was not found!"
|
||||
AdvSceneSwitcher.script.file.warning.openFail="Warning: Could not open the script file!"
|
||||
AdvSceneSwitcher.script.file.warning.loadMissing="Warning: The script is missing a 'script_load' function!"
|
||||
AdvSceneSwitcher.script.file.layout="Script file:{{path}}{{open}}"
|
||||
|
||||
AdvSceneSwitcher.tempVar.select="--select value--"
|
||||
@@ -1991,6 +2082,18 @@ AdvSceneSwitcher.tempVar.twitch.offline_image_url.user.getInfo="Offline image UR
|
||||
AdvSceneSwitcher.tempVar.twitch.created_at.user.getInfo="Account creation date"
|
||||
AdvSceneSwitcher.tempVar.twitch.created_at.user.getInfo.description="The UTC date and time that the user's account was created. The timestamp is in RFC3339 format."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.duration_seconds.commercial="Duration"
|
||||
AdvSceneSwitcher.tempVar.twitch.duration_seconds.commercial.description="Length in seconds of the mid-roll ad break requested."
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.commercial="Started at"
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.commercial.description="The UTC timestamp of when the ad break began, in RFC3339 format. Note that there is potential delay between this event, when the streamer requested the ad break, and when the viewers will see ads."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_automatic.commercial="Was automatic"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_automatic.commercial.description="Indicates if the ad was automatically scheduled via Ads Manager"
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_id.commercial="Requester user ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_id.commercial.description="The ID of the user that requested the ad. For automatic ads, this will be the ID of the broadcaster."
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_login.commercial="Requester user login"
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_login.commercial.description="The login of the user that requested the ad."
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_name.commercial="Requester user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.requester_user_name.commercial.description="The display name of the user that requested the ad."
|
||||
|
||||
AdvSceneSwitcher.tempVar.audio.output_volume="Output volume"
|
||||
AdvSceneSwitcher.tempVar.audio.output_volume.description="The volume the audio source is outputting."
|
||||
@@ -2009,6 +2112,7 @@ AdvSceneSwitcher.tempVar.clipboard.mimeType.all.description="All MIME types of t
|
||||
AdvSceneSwitcher.tempVar.scene.current="Current scene"
|
||||
AdvSceneSwitcher.tempVar.scene.previous="Previous scene"
|
||||
AdvSceneSwitcher.tempVar.scene.preview="Preview scene"
|
||||
AdvSceneSwitcher.tempVar.scene.position="Position in scenes list"
|
||||
|
||||
AdvSceneSwitcher.tempVar.window.window="Window title"
|
||||
AdvSceneSwitcher.tempVar.window.window.description="The window title of the matching window."
|
||||
@@ -2092,6 +2196,19 @@ AdvSceneSwitcher.tempVar.clipboard.text.description="The text contained in the c
|
||||
|
||||
AdvSceneSwitcher.tempVar.file.content="File content"
|
||||
AdvSceneSwitcher.tempVar.file.date="File modification date"
|
||||
AdvSceneSwitcher.tempVar.file.basename="File basename"
|
||||
AdvSceneSwitcher.tempVar.file.basename.description="Returns the base name of the file without the path.\nThe base name consists of all characters in the file up to (but not including) the first '.' character."
|
||||
AdvSceneSwitcher.tempVar.file.basenameComplete="File basename (complete)"
|
||||
AdvSceneSwitcher.tempVar.file.basenameComplete.description="Returns the complete base name of the file without the path.\nThe complete base name consists of all characters in the file up to (but not including) the last '.' character."
|
||||
AdvSceneSwitcher.tempVar.file.suffix="File suffix"
|
||||
AdvSceneSwitcher.tempVar.file.suffix.description="Returns the suffix (extension) of the file.\nThe suffix consists of all characters in the file after (but not including) the last '.'."
|
||||
AdvSceneSwitcher.tempVar.file.suffixComplete="File suffix (complete)"
|
||||
AdvSceneSwitcher.tempVar.file.suffixComplete.description="Returns the complete suffix (extension) of the file.\nThe complete suffix consists of all characters in the file after (but not including) the first '.'."
|
||||
AdvSceneSwitcher.tempVar.file.filename="File name"
|
||||
AdvSceneSwitcher.tempVar.file.absoluteFilePath="Absolute file path"
|
||||
AdvSceneSwitcher.tempVar.file.absolutePath="Absolute path"
|
||||
AdvSceneSwitcher.tempVar.file.isAbsolutePath="Path is absolute"
|
||||
|
||||
|
||||
AdvSceneSwitcher.tempVar.folder.newFiles="New files"
|
||||
AdvSceneSwitcher.tempVar.folder.changedFiles="Changed files"
|
||||
@@ -2125,6 +2242,8 @@ AdvSceneSwitcher.tempVar.usb.serialNumber="Serial Number"
|
||||
AdvSceneSwitcher.tempVar.transform.setting="Setting value"
|
||||
AdvSceneSwitcher.tempVar.transform.settings="Settings string"
|
||||
|
||||
AdvSceneSwitcher.tempVar.media.source="Source"
|
||||
AdvSceneSwitcher.tempVar.media.source.description="The name of the source which matched.\nIf multiple sources matched the last one is returned."
|
||||
AdvSceneSwitcher.tempVar.media.state="State"
|
||||
AdvSceneSwitcher.tempVar.media.state.description="The current media state represented as an integer value:\n0 being 'None'\n1 being 'Playing'\n2 being 'Opening'\n3 being 'Buffering'\n4 being 'Paused'\n5 being 'Stopped'\n6 being 'Ended'\n7 being 'Error'"
|
||||
AdvSceneSwitcher.tempVar.media.time="Current time"
|
||||
@@ -2190,6 +2309,7 @@ AdvSceneSwitcher.tempVar.cursor.x="Cursor position (X)"
|
||||
AdvSceneSwitcher.tempVar.cursor.y="Cursor position (Y)"
|
||||
|
||||
AdvSceneSwitcher.selectScene="--select scene--"
|
||||
AdvSceneSwitcher.selectCanvas="--select canvas--"
|
||||
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
||||
AdvSceneSwitcher.selectCurrentScene="Current Scene"
|
||||
AdvSceneSwitcher.selectPreviewScene="Preview Scene"
|
||||
@@ -2250,21 +2370,23 @@ AdvSceneSwitcher.setting.transform.width="Width"
|
||||
|
||||
AdvSceneSwitcher.sceneItemSelection.configure="Configure scene item selection type"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Source name"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.layout="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Variable name"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.layout="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Source name matches pattern"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}matching{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}matching{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup="Sources in source group"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.entry="Sources in{{sourceGroups}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.layout="{{nameConflictIndex}}Sources in{{sourceGroups}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="Sources of type"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="Source type{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="Source type{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="Source with index"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="Sources in index range"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Sources from{{index}}to{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="Sources from{{index}}to{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="All sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="All sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="All sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.any="Any source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.any.layout="Any source"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="All"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="Any"
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Siempre iniciar el sel
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="No iniciar el selector de escenas"
|
||||
AdvSceneSwitcher.generalTab.status.start="Iniciar"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Detener"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Iniciar automáticamente el selector de escenas cuando:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Iniciar automáticamente el selector de escenas cuando:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Nunca"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Grabando"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Emitiendo"
|
||||
@@ -311,7 +311,6 @@ AdvSceneSwitcher.condition.stats.entry="{{stats}} esta {{condition}} {{value}}"
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Cambiar escena"
|
||||
AdvSceneSwitcher.action.scene.entry="Cambiar a la{{sceneTypes}}escena{{scenes}}usando{{transitions}}con una duración de{{duration}} segundos"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Espere hasta que se complete la transición a la escena de destino"
|
||||
AdvSceneSwitcher.action.wait="Esperar"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fijo"
|
||||
@@ -383,7 +382,7 @@ AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced S
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="Importar configuración desde"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Nota: la acción se ignorará mientras se abra la ventana de configuración."
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Cámara virtual"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Detener cámara virtual"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Iniciar cámara virtual"
|
||||
|
||||
@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Toujours démarrer le
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Ne pas démarrer le sélecteur de scène"
|
||||
AdvSceneSwitcher.generalTab.status.start="Démarrer"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Arrêter"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Démarrer automatiquement le sélecteur de scène lorsque :"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Démarrer automatiquement le sélecteur de scène lorsque :"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Jamais"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Enregistrement"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Diffusion en continu"
|
||||
@@ -459,8 +459,6 @@ AdvSceneSwitcher.condition.slideshow.updateInterval.tooltip="Les informations su
|
||||
AdvSceneSwitcher.action.scene="Changer de scène"
|
||||
AdvSceneSwitcher.action.scene.type.program="Programme"
|
||||
AdvSceneSwitcher.action.scene.type.preview="Aperçu"
|
||||
AdvSceneSwitcher.action.scene.entry="Changer la scène{{sceneTypes}}{{scenes}}en utilisant{{transitions}}avec une durée de{{duration}}secondes"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Changer la scène{{sceneTypes}}{{scenes}}en utilisant{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Attendre que la transition vers la scène cible soit terminée"
|
||||
AdvSceneSwitcher.action.wait="Attendre"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fixe"
|
||||
@@ -1107,15 +1105,15 @@ AdvSceneSwitcher.sceneItemSelection.configure="Configurer le type de sélection
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Nom de la source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Nom de la variable"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Le nom de la source correspond au motif"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}correspondant à{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}correspondant à{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="Sources de type"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="{{nameConflictIndex}}Type de source{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="{{nameConflictIndex}}Type de source{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="Source avec index"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}source"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="Sources dans la plage d'index"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Sources de{{index}}à{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="Sources de{{index}}à{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="Toutes les sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="Toutes les sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="Toutes les sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="Tout"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="N'importe lequel"
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="常にシーンスイ
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="シーンスイッチャーを起動しない"
|
||||
AdvSceneSwitcher.generalTab.status.start="起動する"
|
||||
AdvSceneSwitcher.generalTab.status.stop="停止する"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="次の場合にシーンスイッチャーを自動起動する"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="次の場合にシーンスイッチャーを自動起動する"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="自動起動しない"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="録画を開始した時"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="配信を開始した時"
|
||||
@@ -810,9 +810,6 @@ AdvSceneSwitcher.action.unknown="不明なアクション"
|
||||
AdvSceneSwitcher.action.scene="シーン切り替え"
|
||||
AdvSceneSwitcher.action.scene.type.program="プログラム"
|
||||
AdvSceneSwitcher.action.scene.type.preview="プレビュー"
|
||||
AdvSceneSwitcher.action.scene.entry="{{duration}}秒間の{{transitions}}を使用して、{{sceneTypes}}シーンを{{scenes}}に切り替えます"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="{{transitions}}を使用して{{sceneTypes}}シーンを{{scenes}}に切り替える"
|
||||
AdvSceneSwitcher.action.scene.entry.preview="{{sceneTypes}}シーンを{{scenes}}に切り替えます"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="目的のシーンへの遷移が完了するまで待ちます"
|
||||
; AdvSceneSwitcher.action.wait="Wait"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="指定"
|
||||
@@ -1815,7 +1812,7 @@ AdvSceneSwitcher.tempVar.twitch.game_name.description="配信者がプレイし
|
||||
AdvSceneSwitcher.tempVar.twitch.game_id="ゲームID"
|
||||
AdvSceneSwitcher.tempVar.twitch.game_id.description="配信者がプレイしている、または最後にプレイしたゲームを一意に識別するID。配信者がゲームをプレイしたことがない場合、値は空の文字列になります。"
|
||||
AdvSceneSwitcher.tempVar.twitch.delay="ストリーム遅延"
|
||||
AdvSceneSwitcher.tempVar.twitch.delay.description="ブロードキャスターのストリーム遅延設定の値 (秒単位)。\nこのフィールドの値は、1) リクエストでユーザー アクセス トークンが指定されている、2) Broadcastinger_id クエリ パラメーターの ID がアクセス トークンのユーザー ID と一致する場合を除き、デフォルトで 0 に設定されます。 、3) ブロードキャスターがパートナーステータスを持っており、ストリーム遅延値がゼロ以外に設定されている。"
|
||||
AdvSceneSwitcher.tempVar.twitch.delay.description="ブロードキャスターのストリーム遅延設定の値 (秒単位)。\nこのフィールドの値は、1) リクエストでユーザー アクセス トークンが指定されている、2) broadcaster_id クエリ パラメーターの ID がアクセス トークンのユーザー ID と一致する場合を除き、デフォルトで 0 に設定されます。 、3) ブロードキャスターがパートナーステータスを持っており、ストリーム遅延値がゼロ以外に設定されている。"
|
||||
AdvSceneSwitcher.tempVar.twitch.tags="ストリームタグ"
|
||||
AdvSceneSwitcher.tempVar.twitch.tags.description="チャンネルに付けられるタグです。"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_mature="成人向けコンテンツです"
|
||||
@@ -2237,21 +2234,19 @@ AdvSceneSwitcher.setting.transform.width="幅"
|
||||
|
||||
AdvSceneSwitcher.sceneItemSelection.configure="シーン項目選択タイプの設定"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="ソース名"
|
||||
; AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="変数名"
|
||||
; AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="ソース名に一致するパターン"
|
||||
; AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}matching{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup="ソースグループ内のソース数"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.entry="{{sourceGroups}}内のソース数"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.layout="{{nameConflictIndex}}{{sourceGroups}}内のソース数"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="ソースの種類"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="ソースタイプ{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="ソースタイプ{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="ソースインデックス(上から順)"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="ソース{{index}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="ソース{{index}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="複数のソースインデックス(上から順)"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="ソースの{{index}}から{{indexEnd}}まで"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="ソースの{{index}}から{{indexEnd}}まで"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="全てのソース"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="全てのソース"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="全てのソース"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="全て"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="いずれか"
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Sempre iniciar o switc
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Não iniciar o switcher de cenas"
|
||||
AdvSceneSwitcher.generalTab.status.start="Iniciar"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Parar"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Iniciar automaticamente o switcher de cenas quando:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Iniciar automaticamente o switcher de cenas quando:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Nunca"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Gravando"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Transmitindo"
|
||||
@@ -720,9 +720,6 @@ AdvSceneSwitcher.condition.noDevicesFoundWarning="Nenhum dispositivo USB detecta
|
||||
AdvSceneSwitcher.action.scene="Trocar cena"
|
||||
AdvSceneSwitcher.action.scene.type.program="Programa"
|
||||
AdvSceneSwitcher.action.scene.type.preview="Pré-visualização"
|
||||
AdvSceneSwitcher.action.scene.entry="Trocar{{sceneTypes}}cena para{{scenes}}usando{{transitions}}com duração de{{duration}}segundos"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="Trocar{{sceneTypes}}cena para{{scenes}}usando{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.entry.preview="Trocar{{sceneTypes}}cena para{{scenes}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Aguardar até que a transição para a cena de destino seja concluída"
|
||||
AdvSceneSwitcher.action.wait="Aguardar"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="fixo"
|
||||
@@ -874,7 +871,7 @@ AdvSceneSwitcher.action.pluginState.type.import="Importar configurações de"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Nota: Ação será ignorada enquanto a janela de configurações estiver aberta."
|
||||
AdvSceneSwitcher.action.pluginState.type.terminate="Desligar OBS"
|
||||
AdvSceneSwitcher.action.pluginState.terminateConfirm="O OBS será desligado automaticamente em 10 segundos!\nDeseja continuar com o desligamento do OBS?"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Câmera virtual"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Parar câmera virtual"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Iniciar câmera virtual"
|
||||
@@ -1851,19 +1848,19 @@ AdvSceneSwitcher.setting.transform.width="Largura"
|
||||
|
||||
AdvSceneSwitcher.sceneItemSelection.configure="Configurar tipo de seleção de item de cena"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Nome da fonte"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.layout="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Nome da variável"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.layout="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Nome da fonte corresponde ao padrão"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}correspondendo{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}correspondendo{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="Fontes do tipo"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="Tipo de fonte{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="Tipo de fonte{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="Fonte com índice"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}fonte"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}fonte"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="Fontes no intervalo de índices"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Fontes de{{index}}para{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="Fontes de{{index}}para{{indexEnd}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="Todas as fontes"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="Todas as fontes"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="Todas as fontes"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="Todas"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="Qualquer"
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Всегда запу
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Не запускать переключатель сцен"
|
||||
AdvSceneSwitcher.generalTab.status.start="Старт"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Стоп"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Автоматически запускать переключатель сцен, когда:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Автоматически запускать переключатель сцен, когда:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Никогда"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Запись"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Вещание"
|
||||
@@ -114,7 +114,6 @@ AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Переключить сцену"
|
||||
AdvSceneSwitcher.action.scene.entry="Перейти к сцене{{sceneTypes}}{{scenes}}используя{{transitions}}с продолжительностью{{duration}}секунд"
|
||||
AdvSceneSwitcher.action.wait="Подождать"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="фиксированный"
|
||||
AdvSceneSwitcher.action.wait.type.random="случайный"
|
||||
|
||||
@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Her zaman sahne deği
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Sahne değiştiriciyi başlatma"
|
||||
AdvSceneSwitcher.generalTab.status.start="Başlat"
|
||||
AdvSceneSwitcher.generalTab.status.stop="Durdur"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="Aşağıdaki durumlarda sahne değiştiriciyi otomatik olarak başlatın:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="Aşağıdaki durumlarda sahne değiştiriciyi otomatik olarak başlatın:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="Asla"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="Kayıt"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Yayın"
|
||||
@@ -249,7 +249,6 @@ AdvSceneSwitcher.condition.openvr.entry.line3="HMD mevcut {{xPos}} x {{yPos}} x
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Sahne Degistirici"
|
||||
AdvSceneSwitcher.action.scene.entry="Sahneyi{{sceneTypes}}{{scenes}}kullanarak{{transitions}}süresi olan{{duration}}saniye"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Hedef sahneye geçiş tamamlanana kadar bekleyin"
|
||||
AdvSceneSwitcher.action.wait="Bekle"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="sabit"
|
||||
@@ -312,7 +311,7 @@ AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisi
|
||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:"
|
||||
AdvSceneSwitcher.action.pluginState.type.import="Ayarları şuradan içe aktar:"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="Not: Ayarlar penceresi açılırken eylem göz ardı edilecektir."
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="Sanal Kamera"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="Sanal Kamerayı Durdur"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="Sanal Kamerayı Başlat"
|
||||
|
||||
@@ -12,7 +12,7 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="总是自动启动"
|
||||
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="不要启动"
|
||||
AdvSceneSwitcher.generalTab.status.start="启动"
|
||||
AdvSceneSwitcher.generalTab.status.stop="停止"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart="在以下情况下自动启动场景切换器:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.startup="在以下情况下自动启动场景切换器:"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.never="从不"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.recording="录制"
|
||||
AdvSceneSwitcher.generalTab.status.autoStart.streaming="直播"
|
||||
@@ -698,7 +698,7 @@ AdvSceneSwitcher.condition.twitch.type.event.channel.user.moderator.deletion="
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.live="开始直播"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.playlist="开始播放列表"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.watchParty="开始观看派对"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.premiere="开始首播
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.premiere="开始首播"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.rerun="开始重播"
|
||||
AdvSceneSwitcher.condition.twitch.type.polling.channel.live="当前正在直播"
|
||||
AdvSceneSwitcher.condition.twitch.type.polling.channel.title="当前为头衔赛"
|
||||
@@ -779,9 +779,6 @@ AdvSceneSwitcher.action.unknown="未知操作"
|
||||
AdvSceneSwitcher.action.scene="切换场景"
|
||||
AdvSceneSwitcher.action.scene.type.program="程序"
|
||||
AdvSceneSwitcher.action.scene.type.preview="预览"
|
||||
AdvSceneSwitcher.action.scene.entry="切换到场景{{sceneTypes}}{{scenes}}使用{{transitions}}时长{{duration}}秒"
|
||||
AdvSceneSwitcher.action.scene.entry.noDuration="切换到场景{{sceneTypes}}{{scenes}}使用{{transitions}}"
|
||||
AdvSceneSwitcher.action.scene.entry.preview="将{{sceneTypes}}场景切换到{{scenes}}"
|
||||
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="等待转场到目标场景的动画完成"
|
||||
AdvSceneSwitcher.action.wait="等待"
|
||||
AdvSceneSwitcher.action.wait.type.fixed="固定"
|
||||
@@ -933,7 +930,7 @@ AdvSceneSwitcher.action.pluginState.type.import="导入设置"
|
||||
AdvSceneSwitcher.action.pluginState.importWarning="注意:当设置窗口打开时,操作将被忽略."
|
||||
AdvSceneSwitcher.action.pluginState.type.terminate="关闭OBS"
|
||||
AdvSceneSwitcher.action.pluginState.terminateConfirm="OBS将在10秒后自动关闭!\n你想继续关闭OBS吗?"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
|
||||
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}"
|
||||
AdvSceneSwitcher.action.virtualCamera="虚拟摄像机"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.stop="停止虚拟摄像机"
|
||||
AdvSceneSwitcher.action.virtualCamera.type.start="启动虚拟摄像机"
|
||||
@@ -2095,21 +2092,19 @@ AdvSceneSwitcher.setting.transform.width="宽度"
|
||||
|
||||
AdvSceneSwitcher.sceneItemSelection.configure="配置场景项目选择类型"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="源名称"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="变量名称"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="源名称与匹配相符"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}匹配{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.layout="{{nameConflictIndex}}匹配{{pattern}}{{regex}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup="源分组中的来源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.entry="{{sourceGroups}}中的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.layout="{{nameConflictIndex}}{{sourceGroups}}中的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType="源类型"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.entry="源类型{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.sourceType.layout="源类型{{nameConflictIndex}}{{sourceTypes}}"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index="附有索引的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.index.layout="{{index}}源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange="索引范围内的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="从{{index}}到{{indexEnd}}的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.indexRange.layout="从{{index}}到{{indexEnd}}的源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all="所有源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.entry="所有源"
|
||||
AdvSceneSwitcher.sceneItemSelection.type.all.layout="所有源"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="全部"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="任何"
|
||||
|
||||
@@ -2133,9 +2128,9 @@ AdvSceneSwitcher.unit.weeks="周"
|
||||
AdvSceneSwitcher.unit.months="月"
|
||||
AdvSceneSwitcher.unit.years="年"
|
||||
AdvSceneSwitcher.duration.condition.none="没有时间限制"
|
||||
AdvSceneSwitcher.duration.condition.more="时间少于"
|
||||
AdvSceneSwitcher.duration.condition.more="时间大于"
|
||||
AdvSceneSwitcher.duration.condition.equal="时间等于"
|
||||
AdvSceneSwitcher.duration.condition.less="时间大于"
|
||||
AdvSceneSwitcher.duration.condition.less="时间少于"
|
||||
AdvSceneSwitcher.duration.condition.within="最后"
|
||||
|
||||
AdvSceneSwitcher.time.relative="%1 %2 之前"
|
||||
|
||||
2
deps/json
vendored
2
deps/json
vendored
Submodule deps/json updated: bc889afb4c...55f93686c0
2
deps/libusb
vendored
2
deps/libusb
vendored
Submodule deps/libusb updated: d52e355daa...15a7ebb4d4
@@ -87,6 +87,40 @@
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="autoStartEvent"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.status.autoStart.startup</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_33">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.status.checkInterval</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="checkIntervalTooLowWarning">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="startupBehavior"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QWidget" name="placeholder3" native="true"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QWidget" name="placeholder" native="true"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_64">
|
||||
<property name="text">
|
||||
@@ -94,16 +128,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="startupBehavior"/>
|
||||
<item row="2" column="1">
|
||||
<widget class="QWidget" name="placeholder2" native="true"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QWidget" name="placeholder" native="true"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.status.autoStart</string>
|
||||
<string>AdvSceneSwitcher.generalTab.status.hotkeytips</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -130,36 +161,25 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_13">
|
||||
<widget class="QCheckBox" name="autoStartSceneEnable">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.status.hotkeytips</string>
|
||||
<string>AdvSceneSwitcher.generalTab.status.autoStart.scene</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_33">
|
||||
<item row="5" column="1">
|
||||
<layout class="QHBoxLayout" name="autoStartSceneLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.generalTab.status.checkInterval</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="advss::SceneSelectionWidget" name="autoStartScene" native="true"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="checkIntervalTooLowWarning">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="advss::VariableLineEdit" name="autoStartSceneName"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="advss::RegexConfigWidget" name="autoStartSceneNameRegex" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QWidget" name="placeholder2" native="true"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QWidget" name="placeholder3" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -469,16 +489,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="noMatchSwitchScene">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<widget class="advss::SceneSelectionWidget" name="noMatchSwitchScene">
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -4124,6 +4135,23 @@
|
||||
<header>macro-edit.hpp</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>advss::SceneSelectionWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>scene-selection.hpp</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>advss::VariableLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>variable-line-edit.hpp</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>advss::RegexConfigWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>regex-config.hpp</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>tabWidget</tabstop>
|
||||
@@ -4131,6 +4159,10 @@
|
||||
<tabstop>checkInterval</tabstop>
|
||||
<tabstop>startupBehavior</tabstop>
|
||||
<tabstop>autoStartEvent</tabstop>
|
||||
<tabstop>autoStartSceneEnable</tabstop>
|
||||
<tabstop>autoStartScene</tabstop>
|
||||
<tabstop>autoStartSceneName</tabstop>
|
||||
<tabstop>autoStartSceneNameRegex</tabstop>
|
||||
<tabstop>logLevel</tabstop>
|
||||
<tabstop>saveWindowGeo</tabstop>
|
||||
<tabstop>showTrayNotifications</tabstop>
|
||||
|
||||
@@ -538,6 +538,7 @@ static void handleSceneChange()
|
||||
}
|
||||
|
||||
switcher->checkDefaultSceneTransitions();
|
||||
switcher->CheckAutoStart();
|
||||
}
|
||||
|
||||
static void setLiveTime()
|
||||
@@ -552,18 +553,28 @@ static void resetLiveTime()
|
||||
|
||||
static void checkAutoStartRecording()
|
||||
{
|
||||
if (switcher->obsIsShuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (switcher->autoStartEvent == SwitcherData::AutoStart::RECORDING ||
|
||||
switcher->autoStartEvent ==
|
||||
SwitcherData::AutoStart::RECORINDG_OR_STREAMING)
|
||||
SwitcherData::AutoStart::RECORINDG_OR_STREAMING) {
|
||||
switcher->Start();
|
||||
}
|
||||
}
|
||||
|
||||
static void checkAutoStartStreaming()
|
||||
{
|
||||
if (switcher->obsIsShuttingDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (switcher->autoStartEvent == SwitcherData::AutoStart::STREAMING ||
|
||||
switcher->autoStartEvent ==
|
||||
SwitcherData::AutoStart::RECORINDG_OR_STREAMING)
|
||||
SwitcherData::AutoStart::RECORINDG_OR_STREAMING) {
|
||||
switcher->Start();
|
||||
}
|
||||
}
|
||||
|
||||
static void handleTransitionEnd()
|
||||
|
||||
@@ -45,7 +45,6 @@ protected:
|
||||
/* --- Begin of general tab section --- */
|
||||
public:
|
||||
void SetupGeneralTab();
|
||||
void UpdateNonMatchingScene(const QString &name);
|
||||
void SetDeprecationWarnings();
|
||||
|
||||
public slots:
|
||||
@@ -58,7 +57,6 @@ public slots:
|
||||
void on_startupBehavior_currentIndexChanged(int index);
|
||||
void on_logLevel_currentIndexChanged(int index);
|
||||
void on_autoStartEvent_currentIndexChanged(int index);
|
||||
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
|
||||
void on_checkInterval_valueChanged(int value);
|
||||
void on_tabWidget_currentChanged(int index);
|
||||
void on_exportSettings_clicked();
|
||||
@@ -120,18 +118,6 @@ public slots:
|
||||
void HighlightOnChange() const;
|
||||
void on_macroSettings_clicked();
|
||||
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void MacroSegmentOrderChanged();
|
||||
void SegmentTempVarsChanged(MacroSegment *);
|
||||
void HighlightMacrosChanged(bool value);
|
||||
|
||||
void ConnectionAdded(const QString &);
|
||||
void ConnectionRenamed(const QString &oldName, const QString &newName);
|
||||
void ConnectionRemoved(const QString &);
|
||||
|
||||
private:
|
||||
bool ResolveMacroImportNameConflict(std::shared_ptr<Macro> &);
|
||||
|
||||
|
||||
182
lib/general.cpp
182
lib/general.cpp
@@ -3,6 +3,7 @@
|
||||
#include "filter-combo-box.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-settings.hpp"
|
||||
#include "path-helpers.hpp"
|
||||
#include "selection-helpers.hpp"
|
||||
#include "source-helpers.hpp"
|
||||
@@ -25,15 +26,6 @@ void AdvSceneSwitcher::reject()
|
||||
close();
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::UpdateNonMatchingScene(const QString &name)
|
||||
{
|
||||
OBSSourceAutoRelease scene =
|
||||
obs_get_source_by_name(name.toUtf8().constData());
|
||||
OBSWeakSourceAutoRelease ws = obs_source_get_weak_source(scene);
|
||||
|
||||
switcher->nonMatchingScene = ws;
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
|
||||
{
|
||||
if (loading) {
|
||||
@@ -55,7 +47,6 @@ void AdvSceneSwitcher::on_noMatchSwitch_clicked()
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = NoMatchBehavior::SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||
ui->randomDisabledWarning->setVisible(true);
|
||||
}
|
||||
|
||||
@@ -131,17 +122,6 @@ void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
|
||||
switcher->autoStartEvent = static_cast<SwitcherData::AutoStart>(index);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
|
||||
const QString &text)
|
||||
{
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
UpdateNonMatchingScene(text);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
|
||||
{
|
||||
if (loading) {
|
||||
@@ -451,16 +431,14 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
||||
}
|
||||
|
||||
// New post load steps to be declared during load
|
||||
postLoadSteps.clear();
|
||||
ClearPostLoadSteps();
|
||||
|
||||
// Needs to be loaded before any entries which might rely on scene group
|
||||
// selections to be available.
|
||||
loadSceneGroups(obj);
|
||||
LoadVariables(obj);
|
||||
|
||||
for (const auto &func : loadSteps) {
|
||||
func(obj);
|
||||
}
|
||||
RunLoadSteps(obj);
|
||||
|
||||
LoadMacros(obj);
|
||||
LoadGlobalMacroSettings(obj);
|
||||
@@ -516,18 +494,16 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
|
||||
SaveUISettings(obj);
|
||||
SaveVersion(obj, g_GIT_SHA1);
|
||||
|
||||
for (const auto &func : saveSteps) {
|
||||
func(obj);
|
||||
}
|
||||
RunSaveSteps(obj);
|
||||
}
|
||||
|
||||
void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
|
||||
{
|
||||
obs_data_set_int(obj, "interval", interval);
|
||||
|
||||
std::string nonMatchingSceneName = GetWeakSourceName(nonMatchingScene);
|
||||
obs_data_set_string(obj, "non_matching_scene",
|
||||
nonMatchingSceneName.c_str());
|
||||
OBSDataAutoRelease noMatchScene = obs_data_create();
|
||||
nonMatchingScene.Save(noMatchScene);
|
||||
obs_data_set_obj(obj, "noMatchScene", noMatchScene);
|
||||
obs_data_set_int(obj, "switch_if_not_matching",
|
||||
static_cast<int>(switchIfNotMatching));
|
||||
noMatchDelay.Save(obj, "noMatchDelay");
|
||||
@@ -540,8 +516,13 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
|
||||
obs_data_set_int(obj, "startup_behavior",
|
||||
static_cast<int>(startupBehavior));
|
||||
|
||||
obs_data_set_int(obj, "autoStartEvent",
|
||||
static_cast<int>(autoStartEvent));
|
||||
OBSDataAutoRelease autoStart = obs_data_create();
|
||||
obs_data_set_int(autoStart, "event", static_cast<int>(autoStartEvent));
|
||||
obs_data_set_bool(autoStart, "useAutoStartScene", useAutoStartScene);
|
||||
autoStartScene.Save(autoStart);
|
||||
autoStartSceneName.Save(autoStart, "name");
|
||||
autoStartSceneRegex.Save(autoStart);
|
||||
obs_data_set_obj(obj, "autoStart", autoStart);
|
||||
|
||||
SaveLogLevel(obj);
|
||||
|
||||
@@ -576,9 +557,14 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
||||
static_cast<int>(NoMatchBehavior::NO_SWITCH));
|
||||
switchIfNotMatching = static_cast<NoMatchBehavior>(
|
||||
obs_data_get_int(obj, "switch_if_not_matching"));
|
||||
std::string nonMatchingSceneName =
|
||||
obs_data_get_string(obj, "non_matching_scene");
|
||||
nonMatchingScene = GetWeakSourceByName(nonMatchingSceneName.c_str());
|
||||
|
||||
if (obs_data_has_user_value(obj, "noMatchScene")) {
|
||||
OBSDataAutoRelease noMatchScene =
|
||||
obs_data_get_obj(obj, "noMatchScene");
|
||||
nonMatchingScene.Load(noMatchScene);
|
||||
} else {
|
||||
nonMatchingScene.Load(obj, "non_matching_scene");
|
||||
}
|
||||
noMatchDelay.Load(obj, "noMatchDelay");
|
||||
|
||||
cooldown.Load(obj, "cooldown");
|
||||
@@ -599,8 +585,15 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
||||
stop = true;
|
||||
}
|
||||
|
||||
autoStartEvent =
|
||||
static_cast<AutoStart>(obs_data_get_int(obj, "autoStartEvent"));
|
||||
OBSDataAutoRelease autoStart = obs_data_get_obj(obj, "autoStart");
|
||||
autoStartEvent = static_cast<AutoStart>(
|
||||
obs_data_has_user_value(obj, "autoStart")
|
||||
? obs_data_get_int(autoStart, "event")
|
||||
: obs_data_get_int(obj, "autoStartEvent"));
|
||||
useAutoStartScene = obs_data_get_bool(autoStart, "useAutoStartScene");
|
||||
autoStartScene.Load(autoStart);
|
||||
autoStartSceneName.Load(autoStart, "name");
|
||||
autoStartSceneRegex.Load(autoStart);
|
||||
|
||||
LoadLogLevel(obj);
|
||||
|
||||
@@ -680,10 +673,10 @@ void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||
return;
|
||||
}
|
||||
|
||||
if (switchIfNotMatching == NoMatchBehavior::SWITCH &&
|
||||
nonMatchingScene) {
|
||||
auto noMatchScene = nonMatchingScene.GetScene(false);
|
||||
if (switchIfNotMatching == NoMatchBehavior::SWITCH && noMatchScene) {
|
||||
match = true;
|
||||
scene = nonMatchingScene;
|
||||
scene = noMatchScene;
|
||||
transition = nullptr;
|
||||
}
|
||||
if (switchIfNotMatching == NoMatchBehavior::RANDOM_SWITCH) {
|
||||
@@ -691,6 +684,27 @@ void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::CheckAutoStart()
|
||||
{
|
||||
if (!useAutoStartScene) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool shouldStartPlugin = false;
|
||||
if (autoStartSceneRegex.Enabled()) {
|
||||
const auto currentSceneName = GetWeakSourceName(currentScene);
|
||||
shouldStartPlugin = autoStartSceneRegex.Matches(
|
||||
currentSceneName, autoStartSceneName);
|
||||
} else {
|
||||
shouldStartPlugin = autoStartScene.GetScene(false) ==
|
||||
currentScene;
|
||||
}
|
||||
|
||||
if (shouldStartPlugin) {
|
||||
Start();
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::checkSwitchCooldown(bool &match)
|
||||
{
|
||||
if (!match || !enableCooldown) {
|
||||
@@ -833,7 +847,7 @@ static void setupGeneralTabInactiveWarning(QTabWidget *tabs)
|
||||
inactiveTimer->start();
|
||||
}
|
||||
|
||||
void advss::AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
|
||||
void AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
|
||||
{
|
||||
auto macro = GetMacroWithInvalidConditionInterval();
|
||||
if (!macro) {
|
||||
@@ -857,8 +871,6 @@ void advss::AdvSceneSwitcher::SetCheckIntervalTooLowVisibility() const
|
||||
|
||||
void AdvSceneSwitcher::SetupGeneralTab()
|
||||
{
|
||||
PopulateSceneSelection(ui->noMatchSwitchScene, false);
|
||||
|
||||
if (switcher->switchIfNotMatching == NoMatchBehavior::SWITCH) {
|
||||
ui->noMatchSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
@@ -870,8 +882,17 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
||||
ui->noMatchRandomSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
}
|
||||
ui->noMatchSwitchScene->setCurrentText(
|
||||
GetWeakSourceName(switcher->nonMatchingScene).c_str());
|
||||
ui->noMatchSwitchScene->SetScene(switcher->nonMatchingScene);
|
||||
ui->noMatchSwitchScene->LockToMainCanvas();
|
||||
|
||||
connect(ui->noMatchSwitchScene, &SceneSelectionWidget::SceneChanged,
|
||||
this, [this](const SceneSelection &scene) {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->nonMatchingScene = scene;
|
||||
});
|
||||
|
||||
DurationSelection *noMatchDelay = new DurationSelection();
|
||||
noMatchDelay->SetDuration(switcher->noMatchDelay);
|
||||
@@ -922,6 +943,75 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
||||
populateAutoStartEventSelection(ui->autoStartEvent);
|
||||
ui->autoStartEvent->setCurrentIndex(
|
||||
static_cast<int>(switcher->autoStartEvent));
|
||||
ui->autoStartSceneEnable->setChecked(switcher->useAutoStartScene);
|
||||
ui->autoStartScene->SetScene(switcher->autoStartScene);
|
||||
ui->autoStartScene->LockToMainCanvas();
|
||||
ui->autoStartSceneName->setText(switcher->autoStartSceneName);
|
||||
ui->autoStartSceneNameRegex->SetRegexConfig(
|
||||
switcher->autoStartSceneRegex);
|
||||
|
||||
const auto setupAutoStartSceneLayoutVisibility = [this](bool useRegex) {
|
||||
ui->autoStartSceneName->setVisible(useRegex);
|
||||
ui->autoStartScene->setVisible(!useRegex);
|
||||
if (useRegex) {
|
||||
RemoveStretchIfPresent(ui->autoStartSceneLayout);
|
||||
} else {
|
||||
AddStretchIfNecessary(ui->autoStartSceneLayout);
|
||||
}
|
||||
};
|
||||
setupAutoStartSceneLayoutVisibility(
|
||||
switcher->autoStartSceneRegex.Enabled());
|
||||
|
||||
const auto setupAutoStartSceneWidgetState =
|
||||
[this](bool useAutoStartScene) {
|
||||
ui->autoStartScene->setEnabled(useAutoStartScene);
|
||||
ui->autoStartSceneName->setEnabled(useAutoStartScene);
|
||||
ui->autoStartSceneNameRegex->setEnabled(
|
||||
useAutoStartScene);
|
||||
};
|
||||
setupAutoStartSceneWidgetState(switcher->useAutoStartScene);
|
||||
|
||||
connect(ui->autoStartSceneEnable, &QCheckBox::stateChanged, this,
|
||||
[this, setupAutoStartSceneWidgetState](int enabled) {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->useAutoStartScene = enabled;
|
||||
setupAutoStartSceneWidgetState(enabled);
|
||||
});
|
||||
|
||||
connect(ui->autoStartScene, &SceneSelectionWidget::SceneChanged, this,
|
||||
[this](const SceneSelection &scene) {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->autoStartScene = scene;
|
||||
switcher->CheckAutoStart();
|
||||
});
|
||||
connect(ui->autoStartSceneName, &VariableLineEdit::editingFinished,
|
||||
this, [this]() {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->autoStartSceneName =
|
||||
ui->autoStartSceneName->text().toStdString();
|
||||
switcher->CheckAutoStart();
|
||||
});
|
||||
connect(ui->autoStartSceneNameRegex,
|
||||
&RegexConfigWidget::RegexConfigChanged, this,
|
||||
[this, setupAutoStartSceneLayoutVisibility](
|
||||
const RegexConfig ®ex) {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->autoStartSceneRegex = regex;
|
||||
setupAutoStartSceneLayoutVisibility(regex.Enabled());
|
||||
switcher->CheckAutoStart();
|
||||
});
|
||||
|
||||
// Set up status control
|
||||
auto statusControl = new StatusControl(this, true);
|
||||
|
||||
@@ -1,25 +1,11 @@
|
||||
#include "macro-action-factory.hpp"
|
||||
#include "macro-segment-unknown.hpp"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace advss {
|
||||
|
||||
namespace {
|
||||
|
||||
class MacroActionUnknown : public MacroAction {
|
||||
public:
|
||||
MacroActionUnknown(Macro *m) : MacroAction(m) {}
|
||||
std::shared_ptr<MacroAction> Copy() const
|
||||
{
|
||||
return std::make_shared<MacroActionUnknown>(GetMacro());
|
||||
}
|
||||
bool PerformAction() { return true; };
|
||||
bool Save(obs_data_t *obj) const { return MacroAction::Save(obj); };
|
||||
bool Load(obs_data_t *obj) { return MacroAction::Load(obj); };
|
||||
std::string GetId() const { return "unknown"; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
using MacroActionUnknown = MacroSegmentUnknown<MacroAction>;
|
||||
|
||||
static std::recursive_mutex mutex;
|
||||
|
||||
@@ -49,9 +35,10 @@ bool MacroActionFactory::Deregister(const std::string &id)
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::shared_ptr<MacroAction> createUnknownAction(Macro *m)
|
||||
static std::shared_ptr<MacroAction> createUnknownAction(Macro *m,
|
||||
const std::string &id)
|
||||
{
|
||||
return std::make_shared<MacroActionUnknown>(m);
|
||||
return std::make_shared<MacroActionUnknown>(m, id);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
|
||||
@@ -62,12 +49,7 @@ std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
|
||||
return it->second._create(m);
|
||||
}
|
||||
|
||||
return createUnknownAction(m);
|
||||
}
|
||||
|
||||
static QWidget *createUnknownActionWidget()
|
||||
{
|
||||
return new QLabel(obs_module_text("AdvSceneSwitcher.action.unknown"));
|
||||
return createUnknownAction(m, id);
|
||||
}
|
||||
|
||||
QWidget *MacroActionFactory::CreateWidget(const std::string &id,
|
||||
@@ -79,7 +61,7 @@ QWidget *MacroActionFactory::CreateWidget(const std::string &id,
|
||||
return it->second._createWidget(parent, action);
|
||||
}
|
||||
|
||||
return createUnknownActionWidget();
|
||||
return CreateUnknownSegmentWidget(true);
|
||||
}
|
||||
|
||||
std::string MacroActionFactory::GetActionName(const std::string &id)
|
||||
|
||||
@@ -139,7 +139,6 @@ bool MacroActionMacro::Load(obs_data_t *obj)
|
||||
OBSDataAutoRelease nestedMacroData =
|
||||
obs_data_get_obj(obj, "nestedMacro");
|
||||
_nestedMacro->Load(nestedMacroData);
|
||||
_nestedMacro->PostLoad();
|
||||
}
|
||||
|
||||
_customWidgetHeight = obs_data_get_int(obj, "customWidgetHeight");
|
||||
@@ -152,6 +151,7 @@ bool MacroActionMacro::PostLoad()
|
||||
MacroRefAction::PostLoad();
|
||||
MacroAction::PostLoad();
|
||||
_runOptions.macro.PostLoad();
|
||||
_nestedMacro->PostLoad();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -167,7 +167,17 @@ std::shared_ptr<MacroAction> MacroActionMacro::Create(Macro *m)
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionMacro::Copy() const
|
||||
{
|
||||
return std::make_shared<MacroActionMacro>(*this);
|
||||
auto copy = std::make_shared<MacroActionMacro>(*this);
|
||||
|
||||
// Create a new nested macro
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
_nestedMacro->Save(data);
|
||||
|
||||
copy->_nestedMacro = std::make_shared<Macro>();
|
||||
copy->_nestedMacro->Load(data);
|
||||
copy->_nestedMacro->PostLoad();
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
void MacroActionMacro::ResolveVariablesToFixedValues()
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#include "macro-action-variable.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "help-icon.hpp"
|
||||
#include "json-helpers.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "non-modal-dialog.hpp"
|
||||
#include "source-helpers.hpp"
|
||||
@@ -480,7 +481,7 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
_inputPlaceholder.Save(obj, "inputPlaceholder");
|
||||
_envVariableName.Save(obj, "environmentVariableName");
|
||||
_scene.Save(obj);
|
||||
_tempVar.Save(obj);
|
||||
_tempVar.Save(obj, GetMacro());
|
||||
_sceneItemIndex.Save(obj, "sceneItemIndex");
|
||||
obs_data_set_int(obj, "direction", static_cast<int>(_direction));
|
||||
_stringLength.Save(obj, "stringLength");
|
||||
@@ -828,7 +829,10 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
this)),
|
||||
_randomLayout(new QVBoxLayout()),
|
||||
_jsonQuery(new VariableLineEdit(this)),
|
||||
_jsonQueryHelp(new QLabel(this)),
|
||||
_jsonQueryHelp(new HelpIcon(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.queryJson.info"),
|
||||
this)),
|
||||
_jsonIndex(new VariableSpinBox(this)),
|
||||
_entryLayout(new QHBoxLayout())
|
||||
{
|
||||
@@ -859,14 +863,6 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_randomNumberStart->setMaximum(9999999999);
|
||||
_randomNumberEnd->setMinimum(-9999999999);
|
||||
_randomNumberEnd->setMaximum(9999999999);
|
||||
const QString path = GetThemeTypeName() == "Light"
|
||||
? ":/res/images/help.svg"
|
||||
: ":/res/images/help_light.svg";
|
||||
const QIcon icon(path);
|
||||
const QPixmap pixmap = icon.pixmap(QSize(16, 16));
|
||||
_jsonQueryHelp->setPixmap(pixmap);
|
||||
_jsonQueryHelp->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.queryJson.info"));
|
||||
_jsonIndex->setMaximum(999);
|
||||
|
||||
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
||||
@@ -884,8 +880,8 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
QWidget::connect(_segmentIdx,
|
||||
SIGNAL(SelectionChanged(const IntVariable &)), this,
|
||||
SLOT(SegmentIndexChanged(const IntVariable &)));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroSegmentOrderChanged()), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(SegmentOrderChanged()), this,
|
||||
SLOT(MacroSegmentOrderChanged()));
|
||||
QWidget::connect(
|
||||
_subStringStart,
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "macro-segment-unknown.hpp"
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace advss {
|
||||
|
||||
namespace {
|
||||
|
||||
class MacroConditionUnknown : public MacroCondition {
|
||||
public:
|
||||
MacroConditionUnknown(Macro *m) : MacroCondition(m) {}
|
||||
bool CheckCondition() { return false; }
|
||||
bool Save(obs_data_t *obj) const { return MacroCondition::Save(obj); };
|
||||
bool Load(obs_data_t *obj) { return MacroCondition::Load(obj); };
|
||||
std::string GetId() const { return "unknown"; }
|
||||
};
|
||||
|
||||
} // namespace
|
||||
using MacroConditionUnknown = MacroSegmentUnknown<MacroCondition>;
|
||||
|
||||
static std::recursive_mutex mutex;
|
||||
|
||||
@@ -46,9 +36,10 @@ bool MacroConditionFactory::Deregister(const std::string &id)
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::shared_ptr<MacroCondition> createUnknownCondition(Macro *m)
|
||||
static std::shared_ptr<MacroCondition>
|
||||
createUnknownCondition(Macro *m, const std::string &id)
|
||||
{
|
||||
return std::make_shared<MacroConditionUnknown>(m);
|
||||
return std::make_shared<MacroConditionUnknown>(m, id);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroCondition>
|
||||
@@ -58,13 +49,7 @@ MacroConditionFactory::Create(const std::string &id, Macro *m)
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._create(m);
|
||||
}
|
||||
return createUnknownCondition(m);
|
||||
}
|
||||
|
||||
static QWidget *createUnknownConditionWidget()
|
||||
{
|
||||
return new QLabel(
|
||||
obs_module_text("AdvSceneSwitcher.condition.unknown"));
|
||||
return createUnknownCondition(m, id);
|
||||
}
|
||||
|
||||
QWidget *
|
||||
@@ -75,7 +60,7 @@ MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._createWidget(parent, cond);
|
||||
}
|
||||
return createUnknownConditionWidget();
|
||||
return CreateUnknownSegmentWidget(false);
|
||||
}
|
||||
|
||||
std::string MacroConditionFactory::GetConditionName(const std::string &id)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "macro-condition-macro.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "macro.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -26,6 +27,8 @@ const static std::map<MacroConditionMacro::Type, std::string>
|
||||
"AdvSceneSwitcher.condition.macro.type.actionEnabled"},
|
||||
{MacroConditionMacro::Type::PAUSED,
|
||||
"AdvSceneSwitcher.condition.macro.type.paused"},
|
||||
{MacroConditionMacro::Type::ACTIONS_PERFORMED,
|
||||
"AdvSceneSwitcher.condition.macro.type.actionsPerformed"},
|
||||
};
|
||||
|
||||
const static std::map<MacroConditionMacro::CounterCondition, std::string>
|
||||
@@ -121,6 +124,16 @@ bool MacroConditionMacro::CheckPauseState()
|
||||
return macro->Paused();
|
||||
}
|
||||
|
||||
bool MacroConditionMacro::CheckActionsPerformed()
|
||||
{
|
||||
auto macro = _macro.GetMacro();
|
||||
if (!macro) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return macro->WasExecutedSince(macro->LastConditionCheckTime());
|
||||
}
|
||||
|
||||
bool MacroConditionMacro::CheckCountCondition()
|
||||
{
|
||||
auto macro = _macro.GetMacro();
|
||||
@@ -158,6 +171,8 @@ bool MacroConditionMacro::CheckCondition()
|
||||
return CheckActionStateCondition();
|
||||
case Type::PAUSED:
|
||||
return CheckPauseState();
|
||||
case Type::ACTIONS_PERFORMED:
|
||||
return CheckActionsPerformed();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -307,7 +322,8 @@ MacroConditionMacroEdit::MacroConditionMacroEdit(
|
||||
|
||||
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
|
||||
this, SLOT(MacroChanged(const QString &)));
|
||||
QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Remove(const QString &)), this,
|
||||
SLOT(MacroRemove(const QString &)));
|
||||
QWidget::connect(_types, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(TypeChanged(int)));
|
||||
@@ -414,6 +430,9 @@ void MacroConditionMacroEdit::SetupWidgets()
|
||||
case MacroConditionMacro::Type::PAUSED:
|
||||
SetupPauseWidgets();
|
||||
break;
|
||||
case MacroConditionMacro::Type::ACTIONS_PERFORMED:
|
||||
SetupActionsPerformedWidgets();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -472,6 +491,14 @@ void MacroConditionMacroEdit::SetupPauseWidgets()
|
||||
_settingsLine1, {{"{{macros}}", _macros}});
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::SetupActionsPerformedWidgets()
|
||||
{
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.macro.actionsPerformed.entry"),
|
||||
_settingsLine1, {{"{{macros}}", _macros}});
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::SetWidgetVisibility()
|
||||
{
|
||||
_macros->setVisible(
|
||||
@@ -481,7 +508,9 @@ void MacroConditionMacroEdit::SetWidgetVisibility()
|
||||
MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_ENABLED ||
|
||||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED);
|
||||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTIONS_PERFORMED);
|
||||
_counterConditions->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::COUNT);
|
||||
_count->setVisible(_entryData->GetType() ==
|
||||
|
||||
@@ -39,6 +39,7 @@ public:
|
||||
ACTION_DISABLED,
|
||||
ACTION_ENABLED,
|
||||
PAUSED,
|
||||
ACTIONS_PERFORMED,
|
||||
};
|
||||
void SetType(Type);
|
||||
Type GetType() const { return _type; }
|
||||
@@ -66,6 +67,7 @@ private:
|
||||
bool CheckMultiStateCondition();
|
||||
bool CheckActionStateCondition();
|
||||
bool CheckPauseState();
|
||||
bool CheckActionsPerformed();
|
||||
|
||||
void SetupTempVars();
|
||||
|
||||
@@ -134,6 +136,7 @@ private:
|
||||
void SetupCountWidgets();
|
||||
void SetupActionStateWidgets(bool enable);
|
||||
void SetupPauseWidgets();
|
||||
void SetupActionsPerformedWidgets();
|
||||
void SetWidgetVisibility();
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
@@ -154,7 +154,7 @@ bool MacroConditionTempVar::CheckCondition()
|
||||
bool MacroConditionTempVar::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
_tempVar.Save(obj);
|
||||
_tempVar.Save(obj, GetMacro());
|
||||
obs_data_set_string(obj, "variableName",
|
||||
GetWeakVariableName(_variable2).c_str());
|
||||
_strValue.Save(obj, "strValue");
|
||||
|
||||
394
lib/macro/macro-dock-settings.cpp
Normal file
394
lib/macro/macro-dock-settings.cpp
Normal file
@@ -0,0 +1,394 @@
|
||||
#include "macro-dock-settings.hpp"
|
||||
#include "macro-dock.hpp"
|
||||
#include "macro-dock-window.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
#include <util/platform.h>
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(30, 0, 0)
|
||||
#include <QDockWidget>
|
||||
|
||||
namespace {
|
||||
|
||||
struct DockMapEntry {
|
||||
QAction *action = nullptr;
|
||||
QWidget *dock = nullptr;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static std::unordered_map<const char *, DockMapEntry> dockIds;
|
||||
static std::mutex dockMutex;
|
||||
|
||||
static bool obs_frontend_add_dock_by_id(const char *id, const char *title,
|
||||
QWidget *widget)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(dockMutex);
|
||||
if (dockIds.count(id) > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
widget->setObjectName(id);
|
||||
|
||||
auto dock = new QDockWidget();
|
||||
dock->setWindowTitle(title);
|
||||
dock->setWidget(widget);
|
||||
dock->setFloating(true);
|
||||
dock->setVisible(false);
|
||||
dock->setFeatures(QDockWidget::DockWidgetClosable |
|
||||
QDockWidget::DockWidgetMovable |
|
||||
QDockWidget::DockWidgetFloatable);
|
||||
|
||||
auto action = static_cast<QAction *>(obs_frontend_add_dock(dock));
|
||||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
dockIds[id] = {action, dock};
|
||||
return true;
|
||||
}
|
||||
|
||||
static void obs_frontend_remove_dock(const char *id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(dockMutex);
|
||||
auto it = dockIds.find(id);
|
||||
if (it == dockIds.end()) {
|
||||
return;
|
||||
}
|
||||
it->second.action->deleteLater();
|
||||
it->second.dock->deleteLater();
|
||||
dockIds.erase(it);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace advss {
|
||||
|
||||
MacroDockSettings::MacroDockSettings(Macro *macro) : _macro(macro) {}
|
||||
|
||||
MacroDockSettings::~MacroDockSettings()
|
||||
{
|
||||
// Keep the dock widgets in case of shutdown so they can be restored by
|
||||
// OBS on startup
|
||||
if (!OBSIsShuttingDown()) {
|
||||
RemoveDock();
|
||||
}
|
||||
}
|
||||
|
||||
void MacroDockSettings::Save(obs_data_t *obj, bool saveForCopy) const
|
||||
{
|
||||
OBSDataAutoRelease dockSettings = obs_data_create();
|
||||
obs_data_set_bool(dockSettings, "register", _registerDock);
|
||||
obs_data_set_bool(dockSettings, "standaloneDock", _standaloneDock);
|
||||
obs_data_set_string(dockSettings, "dockWindow", _dockWindow.c_str());
|
||||
obs_data_set_bool(dockSettings, "hasRunButton", _hasRunButton);
|
||||
obs_data_set_bool(dockSettings, "hasPauseButton", _hasPauseButton);
|
||||
obs_data_set_bool(dockSettings, "hasStatusLabel", _hasStatusLabel);
|
||||
obs_data_set_bool(dockSettings, "highlightIfConditionsTrue",
|
||||
_highlight);
|
||||
_runButtonText.Save(dockSettings, "runButtonText");
|
||||
_pauseButtonText.Save(dockSettings, "pauseButtonText");
|
||||
_unpauseButtonText.Save(dockSettings, "unpauseButtonText");
|
||||
_conditionsTrueStatusText.Save(dockSettings,
|
||||
"conditionsTrueStatusText");
|
||||
_conditionsFalseStatusText.Save(dockSettings,
|
||||
"conditionsFalseStatusText");
|
||||
if (saveForCopy) {
|
||||
auto uuid = GenerateId();
|
||||
obs_data_set_string(dockSettings, "dockId", uuid.c_str());
|
||||
|
||||
} else {
|
||||
obs_data_set_string(dockSettings, "dockId", _id.c_str());
|
||||
}
|
||||
obs_data_set_int(dockSettings, "version", 1);
|
||||
obs_data_set_obj(obj, "dockSettings", dockSettings);
|
||||
}
|
||||
|
||||
void MacroDockSettings::Load(obs_data_t *obj)
|
||||
{
|
||||
OBSDataAutoRelease dockSettings = obs_data_get_obj(obj, "dockSettings");
|
||||
if (!dockSettings) {
|
||||
// TODO: Remove this fallback
|
||||
_hasRunButton = obs_data_get_bool(obj, "dockHasRunButton");
|
||||
_hasPauseButton = obs_data_get_bool(obj, "dockHasPauseButton");
|
||||
_registerDock = obs_data_get_bool(obj, "registerDock");
|
||||
ResetDockIfEnabled();
|
||||
return;
|
||||
}
|
||||
|
||||
_macroName = _macro->Name();
|
||||
if (!obs_data_has_user_value(dockSettings, "version")) {
|
||||
assert(_macro);
|
||||
_id = std::string("ADVSS-") + _macroName;
|
||||
} else {
|
||||
_id = obs_data_get_string(dockSettings, "dockId");
|
||||
}
|
||||
|
||||
_registerDock = obs_data_get_bool(dockSettings, "register");
|
||||
|
||||
// TODO: remove these default settings in a future version
|
||||
obs_data_set_default_bool(dockSettings, "standaloneDock", true);
|
||||
obs_data_set_default_string(dockSettings, "dockWindow", "Dock");
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "runButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.run"));
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "pauseButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.pause"));
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "unpauseButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.unpause"));
|
||||
_standaloneDock = obs_data_get_bool(dockSettings, "standaloneDock");
|
||||
_dockWindow = obs_data_get_string(dockSettings, "dockWindow");
|
||||
_runButtonText.Load(dockSettings, "runButtonText");
|
||||
_pauseButtonText.Load(dockSettings, "pauseButtonText");
|
||||
_unpauseButtonText.Load(dockSettings, "unpauseButtonText");
|
||||
_conditionsTrueStatusText.Load(dockSettings,
|
||||
"conditionsTrueStatusText");
|
||||
_conditionsFalseStatusText.Load(dockSettings,
|
||||
"conditionsFalseStatusText");
|
||||
if (_registerDock) {
|
||||
_hasRunButton = obs_data_get_bool(dockSettings, "hasRunButton");
|
||||
_hasPauseButton =
|
||||
obs_data_get_bool(dockSettings, "hasPauseButton");
|
||||
_hasStatusLabel =
|
||||
obs_data_get_bool(dockSettings, "hasStatusLabel");
|
||||
_highlight = obs_data_get_bool(dockSettings,
|
||||
"highlightIfConditionsTrue");
|
||||
}
|
||||
|
||||
ResetDockIfEnabled();
|
||||
}
|
||||
|
||||
void MacroDockSettings::EnableDock(bool enable)
|
||||
{
|
||||
// Only apply "on change" to avoid recreation of the dock widget
|
||||
if (_registerDock == enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveDock();
|
||||
|
||||
if (!enable) {
|
||||
_registerDock = enable;
|
||||
return;
|
||||
}
|
||||
|
||||
assert(_macro);
|
||||
_macroName = _macro->Name();
|
||||
_dock = new MacroDock(GetWeakMacroByName(_macroName.c_str()),
|
||||
_runButtonText, _pauseButtonText,
|
||||
_unpauseButtonText, _conditionsTrueStatusText,
|
||||
_conditionsFalseStatusText, _highlight);
|
||||
|
||||
if (!_standaloneDock) {
|
||||
auto window = GetDockWindowByName(_dockWindow);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
window->AddMacroDock(_dock, QString::fromStdString(_macroName));
|
||||
_registerDock = enable;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obs_frontend_add_dock_by_id(_id.c_str(), _macroName.c_str(),
|
||||
_dock)) {
|
||||
blog(LOG_INFO, "failed to add macro dock for macro %s",
|
||||
_macroName.c_str());
|
||||
_dock->deleteLater();
|
||||
_dock = nullptr;
|
||||
_registerDock = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_registerDock = enable;
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetIsStandaloneDock(bool value)
|
||||
{
|
||||
if (_standaloneDock == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveDock();
|
||||
_standaloneDock = value;
|
||||
ResetDockIfEnabled();
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetDockWindowName(const std::string &name)
|
||||
{
|
||||
if (_dockWindow == name) {
|
||||
return;
|
||||
}
|
||||
|
||||
RemoveDock();
|
||||
_dockWindow = name;
|
||||
ResetDockIfEnabled();
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetHasRunButton(bool value)
|
||||
{
|
||||
_hasRunButton = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->ShowRunButton(value);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetHasPauseButton(bool value)
|
||||
{
|
||||
_hasPauseButton = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->ShowPauseButton(value);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetHasStatusLabel(bool value)
|
||||
{
|
||||
_hasStatusLabel = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->ShowStatusLabel(value);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetHighlightEnable(bool value)
|
||||
{
|
||||
_highlight = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->EnableHighlight(value);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetRunButtonText(const std::string &text)
|
||||
{
|
||||
_runButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetRunButtonText(text);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetPauseButtonText(const std::string &text)
|
||||
{
|
||||
_pauseButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetPauseButtonText(text);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetUnpauseButtonText(const std::string &text)
|
||||
{
|
||||
_unpauseButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetUnpauseButtonText(text);
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetConditionsTrueStatusText(const std::string &text)
|
||||
{
|
||||
_conditionsTrueStatusText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetConditionsTrueText(text);
|
||||
}
|
||||
|
||||
StringVariable MacroDockSettings::ConditionsTrueStatusText() const
|
||||
{
|
||||
return _conditionsTrueStatusText;
|
||||
}
|
||||
|
||||
void MacroDockSettings::SetConditionsFalseStatusText(const std::string &text)
|
||||
{
|
||||
_conditionsFalseStatusText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dock->SetConditionsFalseText(text);
|
||||
}
|
||||
|
||||
StringVariable MacroDockSettings::ConditionsFalseStatusText() const
|
||||
{
|
||||
return _conditionsFalseStatusText;
|
||||
}
|
||||
|
||||
void MacroDockSettings::HandleMacroNameChange()
|
||||
{
|
||||
const auto newName = _macro->Name();
|
||||
|
||||
if (!_standaloneDock) {
|
||||
auto window = GetDockWindowByName(_dockWindow);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
|
||||
window->RenameMacro(_macroName, newName);
|
||||
_macroName = newName;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_macroName != newName) {
|
||||
RemoveDock();
|
||||
_id = GenerateId();
|
||||
_macroName = newName;
|
||||
}
|
||||
|
||||
ResetDockIfEnabled();
|
||||
}
|
||||
|
||||
void MacroDockSettings::ResetDockIfEnabled()
|
||||
{
|
||||
if (_registerDock) {
|
||||
_registerDock = false;
|
||||
EnableDock(true);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroDockSettings::RemoveDock()
|
||||
{
|
||||
if (_standaloneDock) {
|
||||
obs_frontend_remove_dock(_id.c_str());
|
||||
_dock = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
auto window = GetDockWindowByName(_dockWindow);
|
||||
if (window) {
|
||||
window->RemoveMacroDock(_dock);
|
||||
}
|
||||
|
||||
if (_dock) {
|
||||
_dock = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string MacroDockSettings::GenerateId()
|
||||
{
|
||||
#if LIBOBS_API_VER > MAKE_SEMANTIC_VERSION(30, 0, 0)
|
||||
auto uuid = os_generate_uuid();
|
||||
auto id = std::string("advss-macro-dock-") + std::string(uuid);
|
||||
bfree(uuid);
|
||||
return id;
|
||||
|
||||
#else
|
||||
static std::atomic_int16_t idCounter = 0;
|
||||
return std::to_string(++idCounter);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
76
lib/macro/macro-dock-settings.hpp
Normal file
76
lib/macro/macro-dock-settings.hpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "variable-string.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
class Macro;
|
||||
class MacroDock;
|
||||
|
||||
class MacroDockSettings {
|
||||
public:
|
||||
MacroDockSettings(Macro *macro);
|
||||
~MacroDockSettings();
|
||||
|
||||
void Save(obs_data_t *obj, bool saveForCopy) const;
|
||||
void Load(obs_data_t *obj);
|
||||
|
||||
void EnableDock(bool);
|
||||
bool DockEnabled() const { return _registerDock; }
|
||||
|
||||
bool IsStandaloneDock() const { return _standaloneDock; }
|
||||
void SetIsStandaloneDock(bool value);
|
||||
std::string DockWindowName() const { return _dockWindow; }
|
||||
void SetDockWindowName(const std::string &name);
|
||||
|
||||
void SetHasRunButton(bool value);
|
||||
bool HasRunButton() const { return _hasRunButton; }
|
||||
void SetHasPauseButton(bool value);
|
||||
bool HasPauseButton() const { return _hasPauseButton; }
|
||||
void SetHasStatusLabel(bool value);
|
||||
bool HasStatusLabel() const { return _hasStatusLabel; }
|
||||
void SetHighlightEnable(bool value);
|
||||
bool HighlightEnabled() const { return _highlight; }
|
||||
StringVariable RunButtonText() const { return _runButtonText; }
|
||||
void SetRunButtonText(const std::string &text);
|
||||
StringVariable PauseButtonText() const { return _pauseButtonText; }
|
||||
void SetPauseButtonText(const std::string &text);
|
||||
StringVariable UnpauseButtonText() const { return _unpauseButtonText; }
|
||||
void SetUnpauseButtonText(const std::string &text);
|
||||
void SetConditionsTrueStatusText(const std::string &text);
|
||||
StringVariable ConditionsTrueStatusText() const;
|
||||
void SetConditionsFalseStatusText(const std::string &text);
|
||||
StringVariable ConditionsFalseStatusText() const;
|
||||
|
||||
void HandleMacroNameChange();
|
||||
|
||||
private:
|
||||
void ResetDockIfEnabled();
|
||||
void RemoveDock();
|
||||
static std::string GenerateId();
|
||||
|
||||
bool _registerDock = false;
|
||||
bool _standaloneDock = true;
|
||||
std::string _dockWindow = "Dock";
|
||||
bool _hasRunButton = true;
|
||||
bool _hasPauseButton = true;
|
||||
bool _hasStatusLabel = false;
|
||||
bool _highlight = false;
|
||||
StringVariable _runButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.run");
|
||||
StringVariable _pauseButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.pause");
|
||||
StringVariable _unpauseButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.unpause");
|
||||
StringVariable _conditionsTrueStatusText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.true");
|
||||
StringVariable _conditionsFalseStatusText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.false");
|
||||
std::string _id = GenerateId();
|
||||
std::string _macroName = "";
|
||||
|
||||
Macro *_macro = nullptr;
|
||||
MacroDock *_dock = nullptr;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
170
lib/macro/macro-dock-window.cpp
Normal file
170
lib/macro/macro-dock-window.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
#include "macro-dock-window.hpp"
|
||||
#include "log-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QLayout>
|
||||
#include <mutex>
|
||||
|
||||
namespace advss {
|
||||
|
||||
static std::unordered_map<std::string, MacroDockWindow *> windows;
|
||||
static std::unordered_map<std::string, QByteArray> windowGeometries;
|
||||
static std::mutex mutex;
|
||||
|
||||
static void saveDocks(obs_data_t *obj)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
OBSDataArrayAutoRelease array = obs_data_array_create();
|
||||
for (const auto &[name, window] : windows) {
|
||||
OBSDataAutoRelease dockData = obs_data_create();
|
||||
obs_data_set_string(dockData, "name", name.c_str());
|
||||
obs_data_set_string(dockData, "geometry",
|
||||
window->GetWindow()
|
||||
->saveState()
|
||||
.toBase64()
|
||||
.toStdString()
|
||||
.c_str());
|
||||
obs_data_array_push_back(array, dockData);
|
||||
}
|
||||
obs_data_set_array(data, "docks", array);
|
||||
obs_data_set_obj(obj, "dockWindows", data);
|
||||
}
|
||||
|
||||
static void restoreDockGeometry()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
for (const auto &[name, dock] : windows) {
|
||||
const auto it = windowGeometries.find(name);
|
||||
if (it == windowGeometries.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dock->GetWindow()->restoreState(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
static void loadDocks(obs_data_t *obj)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
windowGeometries.clear();
|
||||
OBSDataAutoRelease data = obs_data_get_obj(obj, "dockWindows");
|
||||
OBSDataArrayAutoRelease array = obs_data_get_array(data, "docks");
|
||||
auto size = obs_data_array_count(array);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
OBSDataAutoRelease dockData = obs_data_array_item(array, i);
|
||||
const auto name = obs_data_get_string(dockData, "name");
|
||||
const auto geometry = QByteArray::fromBase64(
|
||||
obs_data_get_string(dockData, "geometry"));
|
||||
windowGeometries[name] = geometry;
|
||||
}
|
||||
AddPostLoadStep(restoreDockGeometry);
|
||||
}
|
||||
|
||||
[[maybe_unused]] static bool _ = []() {
|
||||
AddPluginInitStep([]() {
|
||||
AddSaveStep(saveDocks);
|
||||
AddLoadStep(loadDocks);
|
||||
});
|
||||
return true;
|
||||
}();
|
||||
|
||||
MacroDockWindow::MacroDockWindow(const std::string &name)
|
||||
: QFrame(),
|
||||
_name(name),
|
||||
_window(new QMainWindow())
|
||||
{
|
||||
setFrameShape(QFrame::StyledPanel);
|
||||
setFrameShadow(QFrame::Sunken);
|
||||
_window->setDockNestingEnabled(true);
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->addWidget(_window);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
QWidget *MacroDockWindow::AddMacroDock(QWidget *widget, const QString &title)
|
||||
{
|
||||
auto dock = new QDockWidget();
|
||||
dock->setWindowTitle(title);
|
||||
dock->setWidget(widget);
|
||||
dock->setVisible(true);
|
||||
dock->setFeatures(QDockWidget::DockWidgetMovable);
|
||||
dock->setObjectName(title);
|
||||
_window->addDockWidget(Qt::RightDockWidgetArea, dock);
|
||||
return dock;
|
||||
}
|
||||
|
||||
void MacroDockWindow::RenameMacro(const std::string &oldName,
|
||||
const std::string &newName)
|
||||
{
|
||||
auto docks = _window->findChildren<QDockWidget *>();
|
||||
for (const auto dock : docks) {
|
||||
if (dock->windowTitle() == QString::fromStdString(oldName)) {
|
||||
dock->setWindowTitle(QString::fromStdString(newName));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MacroDockWindow::RemoveMacroDock(QWidget *widget)
|
||||
{
|
||||
bool removedDock = false;
|
||||
auto docks = _window->findChildren<QDockWidget *>();
|
||||
for (const auto dock : docks) {
|
||||
if (dock->widget() == widget) {
|
||||
_window->removeDockWidget(dock);
|
||||
dock->deleteLater();
|
||||
removedDock = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (OBSIsShuttingDown()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool shouldRemoveDockWindow = docks.isEmpty() ||
|
||||
(removedDock && docks.count() == 1);
|
||||
if (!shouldRemoveDockWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
auto it = windows.find(_name);
|
||||
if (it != windows.end()) {
|
||||
windows.erase(it);
|
||||
}
|
||||
|
||||
const auto id = "advss-dock-window-" + _name;
|
||||
obs_frontend_remove_dock(id.c_str());
|
||||
}
|
||||
|
||||
QMainWindow *MacroDockWindow::GetWindow() const
|
||||
{
|
||||
return _window;
|
||||
}
|
||||
|
||||
MacroDockWindow *GetDockWindowByName(const std::string &name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
auto it = windows.find(name);
|
||||
if (it != windows.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto window = new MacroDockWindow(name);
|
||||
const auto id = "advss-dock-window-" + name;
|
||||
if (!obs_frontend_add_dock_by_id(id.c_str(), name.c_str(), window)) {
|
||||
blog(LOG_INFO, "failed to add macro dock window '%s'",
|
||||
id.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
windows[name] = window;
|
||||
return window;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
29
lib/macro/macro-dock-window.hpp
Normal file
29
lib/macro/macro-dock-window.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include <QFrame>
|
||||
#include <QMainWindow>
|
||||
#include <QWidget>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MacroDockWindow : public QFrame {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroDockWindow(const std::string &name);
|
||||
QWidget *AddMacroDock(QWidget *, const QString &title);
|
||||
void RenameMacro(const std::string &oldName,
|
||||
const std::string &newName);
|
||||
void RemoveMacroDock(QWidget *);
|
||||
QMainWindow *GetWindow() const;
|
||||
|
||||
private:
|
||||
std::string _name;
|
||||
QMainWindow *_window;
|
||||
};
|
||||
|
||||
MacroDockWindow *GetDockWindowByName(const std::string &name);
|
||||
|
||||
} // namespace advss
|
||||
@@ -30,9 +30,10 @@ MacroDock::MacroDock(std::weak_ptr<Macro> m,
|
||||
|
||||
auto macro = _macro.lock();
|
||||
if (macro) {
|
||||
_run->setVisible(macro->DockHasRunButton());
|
||||
_pauseToggle->setVisible(macro->DockHasPauseButton());
|
||||
_statusText->setVisible(macro->DockHasStatusLabel());
|
||||
const auto &settings = macro->GetDockSettings();
|
||||
_run->setVisible(settings.HasRunButton());
|
||||
_pauseToggle->setVisible(settings.HasPauseButton());
|
||||
_statusText->setVisible(settings.HasStatusLabel());
|
||||
}
|
||||
|
||||
QWidget::connect(_run, SIGNAL(clicked()), this, SLOT(RunClicked()));
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "macro-segment-copy-paste.hpp"
|
||||
#include "macro-segment-list.hpp"
|
||||
#include "macro-settings.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
#include "name-dialog.hpp"
|
||||
#include "path-helpers.hpp"
|
||||
@@ -66,6 +67,8 @@ setupToolBar(const std::initializer_list<std::initializer_list<QWidget *>>
|
||||
MacroEdit::MacroEdit(QWidget *parent, QStringList helpMsg)
|
||||
: ui(new Ui_MacroEdit)
|
||||
{
|
||||
setParent(parent);
|
||||
|
||||
if (helpMsg.size() != 3) {
|
||||
helpMsg << "AdvSceneSwitcher.macroTab.editConditionHelp"
|
||||
<< "AdvSceneSwitcher.macroTab.editActionHelp"
|
||||
@@ -106,6 +109,16 @@ MacroEdit::MacroEdit(QWidget *parent, QStringList helpMsg)
|
||||
connect(ui->conditionsList, &QWidget::customContextMenuRequested, this,
|
||||
&MacroEdit::ShowMacroConditionsContextMenu);
|
||||
|
||||
connect(this, &MacroEdit::MacroAdded, MacroSignalManager::Instance(),
|
||||
&MacroSignalManager::Add);
|
||||
connect(this, &MacroEdit::MacroRemoved, MacroSignalManager::Instance(),
|
||||
&MacroSignalManager::Remove);
|
||||
connect(this, &MacroEdit::MacroRenamed, MacroSignalManager::Instance(),
|
||||
&MacroSignalManager::Rename);
|
||||
connect(this, &MacroEdit::MacroSegmentOrderChanged,
|
||||
MacroSignalManager::Instance(),
|
||||
&MacroSignalManager::SegmentOrderChanged);
|
||||
|
||||
// Set action and condition toolbars
|
||||
const std::string pathPrefix =
|
||||
GetDataFilePath("res/images/" + GetThemeTypeName());
|
||||
@@ -236,6 +249,11 @@ void MacroEdit::SetMacro(const std::shared_ptr<Macro> ¯o)
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Macro> MacroEdit::GetMacro() const
|
||||
{
|
||||
return _currentMacro;
|
||||
}
|
||||
|
||||
void MacroEdit::ClearSegmentWidgetCacheFor(Macro *macro) const
|
||||
{
|
||||
ui->conditionsList->ClearWidgetsFromCacheFor(macro);
|
||||
|
||||
@@ -17,6 +17,7 @@ class MacroEdit : public QWidget {
|
||||
public:
|
||||
MacroEdit(QWidget *parent, QStringList helpMsg = {});
|
||||
void SetMacro(const std::shared_ptr<Macro> &);
|
||||
std::shared_ptr<Macro> GetMacro() const;
|
||||
void ClearSegmentWidgetCacheFor(Macro *) const;
|
||||
void SetControlsDisabled(bool disable) const;
|
||||
void HighlightAction(int idx, QColor color = QColor(Qt::green)) const;
|
||||
@@ -108,7 +109,6 @@ signals:
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void MacroSegmentOrderChanged();
|
||||
void SegmentTempVarsChanged(MacroSegment *);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "macro-list.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-selection.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
|
||||
@@ -10,12 +11,11 @@ MacroList::MacroList(QWidget *parent, bool allowDuplicates, bool reorder)
|
||||
: ListEditor(parent, reorder),
|
||||
_allowDuplicates(allowDuplicates)
|
||||
{
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroRenamed(const QString &, const QString &)),
|
||||
this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Rename(const QString &, const QString &)), this,
|
||||
SLOT(MacroRename(const QString &, const QString &)));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroRemoved(const QString &)), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Remove(const QString &)), this,
|
||||
SLOT(MacroRemove(const QString &)));
|
||||
UpdateListSize();
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-segment.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
@@ -31,8 +32,8 @@ MacroSegmentSelection::MacroSegmentSelection(QWidget *parent, Type type,
|
||||
_index,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(IndexChanged(const NumberVariable<int> &)));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroSegmentOrderChanged()), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(SegmentOrderChanged()), this,
|
||||
SLOT(MacroSegmentOrderChanged()));
|
||||
|
||||
auto layout = new QHBoxLayout;
|
||||
|
||||
74
lib/macro/macro-segment-unknown.hpp
Normal file
74
lib/macro/macro-segment-unknown.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
#include "macro-action.hpp"
|
||||
#include "macro-condition.hpp"
|
||||
|
||||
#include <obs.hpp>
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
namespace advss {
|
||||
|
||||
// Retains the settings and ID of the macro segment even if they can't be
|
||||
// interpreted correctly right now.
|
||||
//
|
||||
// As soon as a version of the plugin supporting the original ID is running it
|
||||
// will take over again
|
||||
template<typename T> class MacroSegmentUnknown : public T {
|
||||
public:
|
||||
MacroSegmentUnknown(Macro *macro, const std::string &originalId);
|
||||
bool CheckCondition() { return false; }
|
||||
std::shared_ptr<MacroAction> Copy() const;
|
||||
bool PerformAction() { return true; };
|
||||
bool Save(obs_data_t *data) const;
|
||||
bool Load(obs_data_t *data);
|
||||
std::string GetId() const { return "unknown"; }
|
||||
|
||||
private:
|
||||
std::string _id;
|
||||
OBSData _settings;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline MacroSegmentUnknown<T>::MacroSegmentUnknown(
|
||||
Macro *macro, const std::string &originalId)
|
||||
: T(macro),
|
||||
_id(originalId),
|
||||
_settings(obs_data_create())
|
||||
{
|
||||
obs_data_release(_settings);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline std::shared_ptr<MacroAction> MacroSegmentUnknown<T>::Copy() const
|
||||
{
|
||||
if constexpr (std::is_same_v<T, MacroAction>) {
|
||||
return std::make_shared<MacroSegmentUnknown<T>>(
|
||||
MacroAction::GetMacro(), _id);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool MacroSegmentUnknown<T>::Save(obs_data_t *data) const
|
||||
{
|
||||
T::Save(data);
|
||||
obs_data_apply(data, _settings);
|
||||
obs_data_set_string(_settings, "id", _id.c_str());
|
||||
return true;
|
||||
};
|
||||
|
||||
template<typename T> inline bool MacroSegmentUnknown<T>::Load(obs_data_t *data)
|
||||
{
|
||||
T::Load(data);
|
||||
obs_data_apply(_settings, data);
|
||||
return true;
|
||||
};
|
||||
|
||||
inline QWidget *CreateUnknownSegmentWidget(bool isAction)
|
||||
{
|
||||
return new QLabel(obs_module_text(
|
||||
isAction ? "AdvSceneSwitcher.action.unknown"
|
||||
: "AdvSceneSwitcher.condition.unknown"));
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
@@ -256,28 +256,6 @@ MacroSegmentEdit::MacroSegmentEdit(QWidget *parent)
|
||||
|
||||
QWidget::connect(_section, &Section::Collapsed, this,
|
||||
&MacroSegmentEdit::Collapsed);
|
||||
// Macro signals
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroAdded(const QString &)), this,
|
||||
SIGNAL(MacroAdded(const QString &)));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroRemoved(const QString &)), this,
|
||||
SIGNAL(MacroRemoved(const QString &)));
|
||||
QWidget::connect(
|
||||
GetSettingsWindow(),
|
||||
SIGNAL(MacroRenamed(const QString &, const QString &)), this,
|
||||
SIGNAL(MacroRenamed(const QString &, const QString &)));
|
||||
// Scene group signals
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(SceneGroupAdded(const QString &)), this,
|
||||
SIGNAL(SceneGroupAdded(const QString &)));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(SceneGroupRemoved(const QString &)), this,
|
||||
SIGNAL(SceneGroupRemoved(const QString &)));
|
||||
QWidget::connect(
|
||||
GetSettingsWindow(),
|
||||
SIGNAL(SceneGroupRenamed(const QString &, const QString)), this,
|
||||
SIGNAL(SceneGroupRenamed(const QString &, const QString)));
|
||||
|
||||
auto frameLayout = new QGridLayout;
|
||||
frameLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
@@ -113,13 +113,6 @@ public slots:
|
||||
|
||||
protected slots:
|
||||
void Collapsed(bool) const;
|
||||
signals:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void SceneGroupAdded(const QString &name);
|
||||
void SceneGroupRemoved(const QString &name);
|
||||
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
||||
|
||||
protected:
|
||||
void SetDisableEffect(bool);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
@@ -20,15 +21,14 @@ MacroSelection::MacroSelection(QWidget *parent)
|
||||
addItem(QString::fromStdString(m->Name()));
|
||||
}
|
||||
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroAdded(const QString &)), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Add(const QString &)), this,
|
||||
SLOT(MacroAdd(const QString &)));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroRemoved(const QString &)), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Remove(const QString &)), this,
|
||||
SLOT(MacroRemove(const QString &)));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroRenamed(const QString &, const QString &)),
|
||||
this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Rename(const QString &, const QString &)), this,
|
||||
SLOT(MacroRename(const QString &, const QString &)));
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +94,9 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
_currentInputs(new MacroInputSelection()),
|
||||
_currentMacroRegisterDock(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentRegisterDock"))),
|
||||
_currentMacroIsStandaloneDock(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentIsStandaloneDock"))),
|
||||
_currentMacroDockWindowName(new QLineEdit(this)),
|
||||
_currentMacroDockAddRunButton(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentDockAddRunButton"))),
|
||||
_currentMacroDockAddPauseButton(new QCheckBox(obs_module_text(
|
||||
@@ -198,6 +201,15 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
int row = 0;
|
||||
_dockLayout->addWidget(_currentMacroRegisterDock, row, 1, 1, 2);
|
||||
row++;
|
||||
_dockLayout->addWidget(_currentMacroIsStandaloneDock, row, 1, 1, 2);
|
||||
row++;
|
||||
_dockLayout->addWidget(
|
||||
new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.macroTab.currentDockWindowName")),
|
||||
row, 1);
|
||||
_dockLayout->addWidget(_currentMacroDockWindowName, row, 2);
|
||||
_dockWindowNameRow = row;
|
||||
row++;
|
||||
_dockLayout->addWidget(_currentMacroDockAddRunButton, row, 1, 1, 2);
|
||||
row++;
|
||||
_dockLayout->addWidget(
|
||||
@@ -252,6 +264,8 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
|
||||
connect(_currentMacroRegisterDock, &QCheckBox::stateChanged, this,
|
||||
&MacroSettingsDialog::DockEnableChanged);
|
||||
connect(_currentMacroIsStandaloneDock, &QCheckBox::stateChanged, this,
|
||||
&MacroSettingsDialog::IsStandaloneDockChanged);
|
||||
connect(_currentMacroDockAddRunButton, &QCheckBox::stateChanged, this,
|
||||
&MacroSettingsDialog::RunButtonEnableChanged);
|
||||
connect(_currentMacroDockAddPauseButton, &QCheckBox::stateChanged, this,
|
||||
@@ -329,55 +343,37 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent,
|
||||
_currentSkipOnStartup->setChecked(macro->SkipExecOnStart());
|
||||
_currentStopActionsIfNotDone->setChecked(macro->StopActionsIfNotDone());
|
||||
_currentInputs->SetInputs(macro->GetInputVariables());
|
||||
const bool dockEnabled = macro->DockEnabled();
|
||||
const auto &dockSettings = macro->GetDockSettings();
|
||||
const bool dockEnabled = dockSettings.DockEnabled();
|
||||
_currentMacroRegisterDock->setChecked(dockEnabled);
|
||||
_currentMacroDockAddRunButton->setChecked(macro->DockHasRunButton());
|
||||
_currentMacroIsStandaloneDock->setChecked(
|
||||
dockSettings.IsStandaloneDock());
|
||||
_currentMacroDockWindowName->setText(
|
||||
QString::fromStdString(dockSettings.DockWindowName()));
|
||||
_currentMacroDockAddRunButton->setChecked(dockSettings.HasRunButton());
|
||||
_currentMacroDockAddPauseButton->setChecked(
|
||||
macro->DockHasPauseButton());
|
||||
dockSettings.HasPauseButton());
|
||||
_currentMacroDockAddStatusLabel->setChecked(
|
||||
macro->DockHasStatusLabel());
|
||||
dockSettings.HasStatusLabel());
|
||||
_currentMacroDockHighlightIfConditionsTrue->setChecked(
|
||||
macro->DockHighlightEnabled());
|
||||
_runButtonText->setText(macro->RunButtonText());
|
||||
_pauseButtonText->setText(macro->PauseButtonText());
|
||||
_unpauseButtonText->setText(macro->UnpauseButtonText());
|
||||
_conditionsTrueStatusText->setText(macro->ConditionsTrueStatusText());
|
||||
_conditionsFalseStatusText->setText(macro->ConditionsFalseStatusText());
|
||||
dockSettings.HighlightEnabled());
|
||||
_runButtonText->setText(dockSettings.RunButtonText());
|
||||
_pauseButtonText->setText(dockSettings.PauseButtonText());
|
||||
_unpauseButtonText->setText(dockSettings.UnpauseButtonText());
|
||||
_conditionsTrueStatusText->setText(
|
||||
dockSettings.ConditionsTrueStatusText());
|
||||
_conditionsFalseStatusText->setText(
|
||||
dockSettings.ConditionsFalseStatusText());
|
||||
|
||||
_currentMacroDockAddRunButton->setVisible(dockEnabled);
|
||||
_currentMacroDockAddPauseButton->setVisible(dockEnabled);
|
||||
_currentMacroDockAddStatusLabel->setVisible(dockEnabled);
|
||||
_currentMacroDockHighlightIfConditionsTrue->setVisible(dockEnabled);
|
||||
SetGridLayoutRowVisible(_dockLayout, _runButtonTextRow,
|
||||
dockEnabled && macro->DockHasRunButton());
|
||||
SetGridLayoutRowVisible(_dockLayout, _pauseButtonTextRow,
|
||||
dockEnabled && macro->DockHasPauseButton());
|
||||
SetGridLayoutRowVisible(_dockLayout, _unpauseButtonTextRow,
|
||||
dockEnabled && macro->DockHasPauseButton());
|
||||
SetGridLayoutRowVisible(_dockLayout, _conditionsTrueTextRow,
|
||||
dockEnabled && macro->DockHasStatusLabel());
|
||||
SetGridLayoutRowVisible(_dockLayout, _conditionsFalseTextRow,
|
||||
dockEnabled && macro->DockHasStatusLabel());
|
||||
DockEnableChanged(dockEnabled);
|
||||
MinimizeSizeOfColumn(_dockLayout, 0);
|
||||
Resize();
|
||||
|
||||
// Try to set sensible initial size for the dialog window
|
||||
QSize contentSize = contentWidget->sizeHint();
|
||||
resize(contentSize.width() + layout->contentsMargins().left() +
|
||||
layout->contentsMargins().right() +
|
||||
dialogLayout->contentsMargins().left() +
|
||||
dialogLayout->contentsMargins().right() +
|
||||
scrollArea->verticalScrollBar()->sizeHint().width() + 20,
|
||||
contentSize.height() + dialogLayout->spacing() +
|
||||
buttonbox->sizeHint().height() +
|
||||
dialogLayout->contentsMargins().top() +
|
||||
dialogLayout->contentsMargins().bottom() +
|
||||
scrollArea->horizontalScrollBar()->sizeHint().height() +
|
||||
20);
|
||||
Resize();
|
||||
}
|
||||
|
||||
void MacroSettingsDialog::DockEnableChanged(int enabled)
|
||||
{
|
||||
_currentMacroIsStandaloneDock->setVisible(enabled);
|
||||
_currentMacroDockAddRunButton->setVisible(enabled);
|
||||
_currentMacroDockAddPauseButton->setVisible(enabled);
|
||||
_currentMacroDockAddStatusLabel->setVisible(enabled);
|
||||
@@ -401,6 +397,12 @@ void MacroSettingsDialog::DockEnableChanged(int enabled)
|
||||
Resize();
|
||||
}
|
||||
|
||||
void MacroSettingsDialog::IsStandaloneDockChanged(int enabled)
|
||||
{
|
||||
SetGridLayoutRowVisible(_dockLayout, _dockWindowNameRow, !enabled);
|
||||
Resize();
|
||||
}
|
||||
|
||||
void MacroSettingsDialog::RunButtonEnableChanged(int enabled)
|
||||
{
|
||||
SetGridLayoutRowVisible(_dockLayout, _runButtonTextRow, enabled);
|
||||
@@ -479,29 +481,29 @@ bool MacroSettingsDialog::AskForSettings(QWidget *parent,
|
||||
macro->SetStopActionsIfNotDone(
|
||||
dialog._currentStopActionsIfNotDone->isChecked());
|
||||
|
||||
// Only apply "on change" to avoid recreation of the dock widget
|
||||
const bool enableDock = dialog._currentMacroRegisterDock->isChecked();
|
||||
if (macro->DockEnabled() != enableDock) {
|
||||
macro->EnableDock(
|
||||
dialog._currentMacroRegisterDock->isChecked());
|
||||
}
|
||||
|
||||
macro->SetDockHasRunButton(
|
||||
auto &dockSettings = macro->GetDockSettings();
|
||||
dockSettings.EnableDock(dialog._currentMacroRegisterDock->isChecked());
|
||||
dockSettings.SetIsStandaloneDock(
|
||||
dialog._currentMacroIsStandaloneDock->isChecked());
|
||||
dockSettings.SetDockWindowName(
|
||||
dialog._currentMacroDockWindowName->text().toStdString());
|
||||
dockSettings.SetHasRunButton(
|
||||
dialog._currentMacroDockAddRunButton->isChecked());
|
||||
macro->SetDockHasPauseButton(
|
||||
dockSettings.SetHasPauseButton(
|
||||
dialog._currentMacroDockAddPauseButton->isChecked());
|
||||
macro->SetDockHasStatusLabel(
|
||||
dockSettings.SetHasStatusLabel(
|
||||
dialog._currentMacroDockAddStatusLabel->isChecked());
|
||||
macro->SetHighlightEnable(
|
||||
dockSettings.SetHighlightEnable(
|
||||
dialog._currentMacroDockHighlightIfConditionsTrue->isChecked());
|
||||
macro->SetRunButtonText(dialog._runButtonText->text().toStdString());
|
||||
macro->SetPauseButtonText(
|
||||
dockSettings.SetRunButtonText(
|
||||
dialog._runButtonText->text().toStdString());
|
||||
dockSettings.SetPauseButtonText(
|
||||
dialog._pauseButtonText->text().toStdString());
|
||||
macro->SetUnpauseButtonText(
|
||||
dockSettings.SetUnpauseButtonText(
|
||||
dialog._unpauseButtonText->text().toStdString());
|
||||
macro->SetConditionsTrueStatusText(
|
||||
dockSettings.SetConditionsTrueStatusText(
|
||||
dialog._conditionsTrueStatusText->text().toStdString());
|
||||
macro->SetConditionsFalseStatusText(
|
||||
dockSettings.SetConditionsFalseStatusText(
|
||||
dialog._conditionsFalseStatusText->text().toStdString());
|
||||
macro->SetInputVariables(dialog._currentInputs->GetInputs());
|
||||
return true;
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
Macro *macro);
|
||||
private slots:
|
||||
void DockEnableChanged(int);
|
||||
void IsStandaloneDockChanged(int);
|
||||
void RunButtonEnableChanged(int);
|
||||
void PauseButtonEnableChanged(int);
|
||||
void StatusLabelEnableChanged(int);
|
||||
@@ -69,6 +70,8 @@ private:
|
||||
QCheckBox *_currentStopActionsIfNotDone;
|
||||
MacroInputSelection *_currentInputs;
|
||||
QCheckBox *_currentMacroRegisterDock;
|
||||
QCheckBox *_currentMacroIsStandaloneDock;
|
||||
QLineEdit *_currentMacroDockWindowName;
|
||||
QCheckBox *_currentMacroDockAddRunButton;
|
||||
QCheckBox *_currentMacroDockAddPauseButton;
|
||||
QCheckBox *_currentMacroDockAddStatusLabel;
|
||||
@@ -81,6 +84,7 @@ private:
|
||||
QGroupBox *_dockOptions;
|
||||
QGridLayout *_dockLayout;
|
||||
|
||||
int _dockWindowNameRow = -1;
|
||||
int _runButtonTextRow = -1;
|
||||
int _pauseButtonTextRow = -1;
|
||||
int _unpauseButtonTextRow = -1;
|
||||
|
||||
13
lib/macro/macro-signals.cpp
Normal file
13
lib/macro/macro-signals.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#include "macro-signals.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
MacroSignalManager::MacroSignalManager(QObject *parent) : QObject(parent) {}
|
||||
|
||||
MacroSignalManager *MacroSignalManager::Instance()
|
||||
{
|
||||
static MacroSignalManager manager;
|
||||
return &manager;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
26
lib/macro/macro-signals.hpp
Normal file
26
lib/macro/macro-signals.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
#pragma once
|
||||
#include "export-symbol-helper.hpp"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class ADVSS_EXPORT MacroSignalManager : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static MacroSignalManager *Instance();
|
||||
|
||||
signals:
|
||||
void Rename(const QString &, const QString &);
|
||||
void Add(const QString &);
|
||||
void Remove(const QString &);
|
||||
void SegmentOrderChanged();
|
||||
void HighlightChanged(bool value);
|
||||
|
||||
private:
|
||||
MacroSignalManager(QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "macro-export-import-dialog.hpp"
|
||||
#include "macro-settings.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "macro-tree.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
@@ -115,7 +116,8 @@ void AdvSceneSwitcher::on_macroAdd_clicked()
|
||||
auto selectedMacro = GetSelectedMacro();
|
||||
if (!selectedMacro) {
|
||||
ui->macros->Add(newMacro);
|
||||
emit MacroAdded(QString::fromStdString(name));
|
||||
MacroSignalManager::Instance()->Add(
|
||||
QString::fromStdString(name));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -123,20 +125,22 @@ void AdvSceneSwitcher::on_macroAdd_clicked()
|
||||
ui->macros->ExpandGroup(selectedMacro);
|
||||
Macro::PrepareMoveToGroup(selectedMacro, newMacro);
|
||||
ui->macros->AddToGroup(newMacro, selectedMacro);
|
||||
emit MacroAdded(QString::fromStdString(name));
|
||||
MacroSignalManager::Instance()->Add(
|
||||
QString::fromStdString(name));
|
||||
return;
|
||||
}
|
||||
|
||||
auto selectedMacroGroup = selectedMacro->Parent();
|
||||
if (!selectedMacroGroup) {
|
||||
ui->macros->Add(newMacro, selectedMacro);
|
||||
emit MacroAdded(QString::fromStdString(name));
|
||||
MacroSignalManager::Instance()->Add(
|
||||
QString::fromStdString(name));
|
||||
return;
|
||||
}
|
||||
|
||||
Macro::PrepareMoveToGroup(selectedMacroGroup, newMacro);
|
||||
ui->macros->Add(newMacro, selectedMacro);
|
||||
emit MacroAdded(QString::fromStdString(name));
|
||||
MacroSignalManager::Instance()->Add(QString::fromStdString(name));
|
||||
}
|
||||
|
||||
static void addGroupSubitems(std::vector<std::shared_ptr<Macro>> ¯os,
|
||||
@@ -205,7 +209,7 @@ void AdvSceneSwitcher::RemoveMacro(std::shared_ptr<Macro> ¯o)
|
||||
ui->macros->Remove(macro);
|
||||
MacroSegmentList::SetCachingEnabled(!switcher->disableMacroWidgetCache);
|
||||
|
||||
emit MacroRemoved(name);
|
||||
MacroSignalManager::Instance()->Remove(name);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::RemoveSelectedMacros()
|
||||
@@ -251,7 +255,8 @@ void AdvSceneSwitcher::RenameMacro(std::shared_ptr<Macro> ¯o,
|
||||
auto lock = LockContext();
|
||||
macro->SetName(name.toStdString());
|
||||
}
|
||||
emit MacroRenamed(oldName, name);
|
||||
|
||||
MacroSignalManager::Instance()->Rename(oldName, name);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_macroRemove_clicked()
|
||||
@@ -568,7 +573,8 @@ void AdvSceneSwitcher::on_macroSettings_clicked()
|
||||
}
|
||||
|
||||
GetGlobalMacroSettings() = prop;
|
||||
emit HighlightMacrosChanged(prop._highlightExecuted);
|
||||
MacroSignalManager::Instance()->HighlightChanged(
|
||||
prop._highlightExecuted);
|
||||
|
||||
// Reset highlights to avoid all macro segments being highlighted, which
|
||||
// would have been highlighted at least once since the moment the
|
||||
@@ -751,7 +757,7 @@ void AdvSceneSwitcher::CopyMacro()
|
||||
|
||||
ui->macros->Add(newMacro, macro);
|
||||
disableAddButtonHighlight();
|
||||
emit MacroAdded(QString::fromStdString(name));
|
||||
MacroSignalManager::Instance()->Add(QString::fromStdString(name));
|
||||
}
|
||||
|
||||
bool MacroTabIsInFocus()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "macro-tree.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "path-helpers.hpp"
|
||||
#include "sync-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
@@ -79,10 +80,10 @@ MacroTreeItem::MacroTreeItem(MacroTree *tree, std::shared_ptr<Macro> macroItem,
|
||||
_macro->SetPaused(!val);
|
||||
};
|
||||
connect(_running, &QAbstractButton::clicked, setRunning);
|
||||
connect(_tree->window(), SIGNAL(HighlightMacrosChanged(bool)), this,
|
||||
SLOT(EnableHighlight(bool)));
|
||||
connect(_tree->window(),
|
||||
SIGNAL(MacroRenamed(const QString &, const QString &)), this,
|
||||
connect(MacroSignalManager::Instance(), SIGNAL(HighlightChanged(bool)),
|
||||
this, SLOT(EnableHighlight(bool)));
|
||||
connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Rename(const QString &, const QString &)), this,
|
||||
SLOT(MacroRenamed(const QString &, const QString &)));
|
||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(HighlightIfExecuted()));
|
||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(UpdatePaused()));
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "macro.hpp"
|
||||
#include "macro-action-factory.hpp"
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "macro-dock.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-settings.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
@@ -15,69 +14,12 @@
|
||||
#include <QAction>
|
||||
#include <QMainWindow>
|
||||
#include <unordered_map>
|
||||
#include <util/platform.h>
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(30, 0, 0)
|
||||
#include <QDockWidget>
|
||||
|
||||
namespace {
|
||||
|
||||
struct DockMapEntry {
|
||||
QAction *action = nullptr;
|
||||
QWidget *dock = nullptr;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static std::unordered_map<const char *, DockMapEntry> dockIds;
|
||||
static std::mutex dockMutex;
|
||||
|
||||
static bool obs_frontend_add_dock_by_id(const char *id, const char *title,
|
||||
QWidget *widget)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(dockMutex);
|
||||
if (dockIds.count(id) > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
widget->setObjectName(id);
|
||||
|
||||
auto dock = new QDockWidget();
|
||||
dock->setWindowTitle(title);
|
||||
dock->setWidget(widget);
|
||||
dock->setFloating(true);
|
||||
dock->setVisible(false);
|
||||
dock->setFeatures(QDockWidget::DockWidgetClosable |
|
||||
QDockWidget::DockWidgetMovable |
|
||||
QDockWidget::DockWidgetFloatable);
|
||||
|
||||
auto action = static_cast<QAction *>(obs_frontend_add_dock(dock));
|
||||
if (!action) {
|
||||
return false;
|
||||
}
|
||||
dockIds[id] = {action, dock};
|
||||
return true;
|
||||
}
|
||||
|
||||
static void obs_frontend_remove_dock(const char *id)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(dockMutex);
|
||||
auto it = dockIds.find(id);
|
||||
if (it == dockIds.end()) {
|
||||
return;
|
||||
}
|
||||
it->second.action->deleteLater();
|
||||
it->second.dock->deleteLater();
|
||||
dockIds.erase(it);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace advss {
|
||||
|
||||
static std::deque<std::shared_ptr<Macro>> macros;
|
||||
|
||||
Macro::Macro(const std::string &name)
|
||||
Macro::Macro(const std::string &name) : _dockSettings(this)
|
||||
{
|
||||
SetName(name);
|
||||
}
|
||||
@@ -99,12 +41,6 @@ Macro::~Macro()
|
||||
_die = true;
|
||||
Stop();
|
||||
ClearHotkeys();
|
||||
|
||||
// Keep the dock widgets in case of shutdown so they can be restored by
|
||||
// OBS on startup
|
||||
if (!OBSIsShuttingDown()) {
|
||||
RemoveDock();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Macro>
|
||||
@@ -412,15 +348,9 @@ bool Macro::ShouldRunActions() const
|
||||
|
||||
void Macro::SetName(const std::string &name)
|
||||
{
|
||||
const bool nameChanged = _name == name;
|
||||
_name = name;
|
||||
|
||||
SetHotkeysDesc();
|
||||
|
||||
if (nameChanged) {
|
||||
_dockId = GenerateDockId();
|
||||
}
|
||||
EnableDock(_registerDock);
|
||||
_dockSettings.HandleMacroNameChange();
|
||||
}
|
||||
|
||||
void Macro::ResetTimers()
|
||||
@@ -605,7 +535,7 @@ void Macro::SetInputVariables(const MacroInputVariables &inputVariables)
|
||||
_inputVariables = inputVariables;
|
||||
}
|
||||
|
||||
std::vector<TempVariable> Macro::GetTempVars(MacroSegment *filter) const
|
||||
std::vector<TempVariable> Macro::GetTempVars(const MacroSegment *filter) const
|
||||
{
|
||||
std::vector<TempVariable> res;
|
||||
|
||||
@@ -633,7 +563,7 @@ std::vector<TempVariable> Macro::GetTempVars(MacroSegment *filter) const
|
||||
return ptr.get() == segment;
|
||||
}) != _conditions.end();
|
||||
};
|
||||
auto isAction = [this](MacroSegment *segment) -> bool {
|
||||
auto isAction = [this](const MacroSegment *segment) -> bool {
|
||||
return std::find_if(_actions.begin(), _actions.end(),
|
||||
[segment](
|
||||
const std::shared_ptr<MacroSegment>
|
||||
@@ -641,7 +571,7 @@ std::vector<TempVariable> Macro::GetTempVars(MacroSegment *filter) const
|
||||
return ptr.get() == segment;
|
||||
}) != _actions.end();
|
||||
};
|
||||
auto isElseAction = [this](MacroSegment *segment) -> bool {
|
||||
auto isElseAction = [this](const MacroSegment *segment) -> bool {
|
||||
return std::find_if(_elseActions.begin(), _elseActions.end(),
|
||||
[segment](
|
||||
const std::shared_ptr<MacroSegment>
|
||||
@@ -819,7 +749,7 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const
|
||||
_useCustomConditionCheckInterval);
|
||||
_customConditionCheckInterval.Save(obj, "customConditionCheckInterval");
|
||||
|
||||
SaveDockSettings(obj, saveForCopy);
|
||||
_dockSettings.Save(obj, saveForCopy);
|
||||
|
||||
SaveSplitterPos(_actionConditionSplitterPosition, obj,
|
||||
"macroActionConditionSplitterPosition");
|
||||
@@ -905,7 +835,7 @@ bool Macro::Load(obs_data_t *obj)
|
||||
obs_data_get_bool(obj, "useCustomConditionCheckInterval");
|
||||
_customConditionCheckInterval.Load(obj, "customConditionCheckInterval");
|
||||
|
||||
LoadDockSettings(obj);
|
||||
_dockSettings.Load(obj);
|
||||
|
||||
LoadSplitterPos(_actionConditionSplitterPosition, obj,
|
||||
"macroActionConditionSplitterPosition");
|
||||
@@ -1095,224 +1025,6 @@ bool Macro::PauseHotkeysEnabled() const
|
||||
return _registerHotkeys;
|
||||
}
|
||||
|
||||
void Macro::SaveDockSettings(obs_data_t *obj, bool saveForCopy) const
|
||||
{
|
||||
auto dockSettings = obs_data_create();
|
||||
obs_data_set_bool(dockSettings, "register", _registerDock);
|
||||
obs_data_set_bool(dockSettings, "hasRunButton", _dockHasRunButton);
|
||||
obs_data_set_bool(dockSettings, "hasPauseButton", _dockHasPauseButton);
|
||||
obs_data_set_bool(dockSettings, "hasStatusLabel", _dockHasStatusLabel);
|
||||
obs_data_set_bool(dockSettings, "highlightIfConditionsTrue",
|
||||
_dockHighlight);
|
||||
_runButtonText.Save(dockSettings, "runButtonText");
|
||||
_pauseButtonText.Save(dockSettings, "pauseButtonText");
|
||||
_unpauseButtonText.Save(dockSettings, "unpauseButtonText");
|
||||
_conditionsTrueStatusText.Save(dockSettings,
|
||||
"conditionsTrueStatusText");
|
||||
_conditionsFalseStatusText.Save(dockSettings,
|
||||
"conditionsFalseStatusText");
|
||||
if (saveForCopy) {
|
||||
auto uuid = GenerateDockId();
|
||||
obs_data_set_string(dockSettings, "dockId", uuid.c_str());
|
||||
|
||||
} else {
|
||||
obs_data_set_string(dockSettings, "dockId", _dockId.c_str());
|
||||
}
|
||||
obs_data_set_int(dockSettings, "version", 1);
|
||||
obs_data_set_obj(obj, "dockSettings", dockSettings);
|
||||
obs_data_release(dockSettings);
|
||||
}
|
||||
|
||||
void Macro::LoadDockSettings(obs_data_t *obj)
|
||||
{
|
||||
auto dockSettings = obs_data_get_obj(obj, "dockSettings");
|
||||
if (!dockSettings) {
|
||||
// TODO: Remove this fallback
|
||||
_dockHasRunButton = obs_data_get_bool(obj, "dockHasRunButton");
|
||||
_dockHasPauseButton =
|
||||
obs_data_get_bool(obj, "dockHasPauseButton");
|
||||
EnableDock(obs_data_get_bool(obj, "registerDock"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!obs_data_has_user_value(dockSettings, "version")) {
|
||||
_dockId = std::string("ADVSS-") + _name;
|
||||
} else {
|
||||
_dockId = obs_data_get_string(dockSettings, "dockId");
|
||||
}
|
||||
|
||||
const bool dockEnabled = obs_data_get_bool(dockSettings, "register");
|
||||
|
||||
// TODO: remove these default settings in a future version
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "runButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.run"));
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "pauseButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.pause"));
|
||||
obs_data_set_default_string(
|
||||
dockSettings, "unpauseButtonText",
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.unpause"));
|
||||
_runButtonText.Load(dockSettings, "runButtonText");
|
||||
_pauseButtonText.Load(dockSettings, "pauseButtonText");
|
||||
_unpauseButtonText.Load(dockSettings, "unpauseButtonText");
|
||||
_conditionsTrueStatusText.Load(dockSettings,
|
||||
"conditionsTrueStatusText");
|
||||
_conditionsFalseStatusText.Load(dockSettings,
|
||||
"conditionsFalseStatusText");
|
||||
if (dockEnabled) {
|
||||
_dockHasRunButton =
|
||||
obs_data_get_bool(dockSettings, "hasRunButton");
|
||||
_dockHasPauseButton =
|
||||
obs_data_get_bool(dockSettings, "hasPauseButton");
|
||||
_dockHasStatusLabel =
|
||||
obs_data_get_bool(dockSettings, "hasStatusLabel");
|
||||
_dockHighlight = obs_data_get_bool(dockSettings,
|
||||
"highlightIfConditionsTrue");
|
||||
}
|
||||
EnableDock(dockEnabled);
|
||||
obs_data_release(dockSettings);
|
||||
}
|
||||
|
||||
void Macro::EnableDock(bool value)
|
||||
{
|
||||
// Reset dock regardless
|
||||
RemoveDock();
|
||||
|
||||
if (!value) {
|
||||
_registerDock = value;
|
||||
return;
|
||||
}
|
||||
|
||||
_dock = new MacroDock(GetWeakMacroByName(_name.c_str()), _runButtonText,
|
||||
_pauseButtonText, _unpauseButtonText,
|
||||
_conditionsTrueStatusText,
|
||||
_conditionsFalseStatusText, _dockHighlight);
|
||||
|
||||
if (!obs_frontend_add_dock_by_id(_dockId.c_str(), _name.c_str(),
|
||||
_dock)) {
|
||||
blog(LOG_INFO, "failed to add macro dock for macro %s",
|
||||
_name.c_str());
|
||||
_dock->deleteLater();
|
||||
_dock = nullptr;
|
||||
_registerDock = false;
|
||||
return;
|
||||
}
|
||||
|
||||
_registerDock = value;
|
||||
}
|
||||
|
||||
void Macro::SetDockHasRunButton(bool value)
|
||||
{
|
||||
_dockHasRunButton = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->ShowRunButton(value);
|
||||
}
|
||||
|
||||
void Macro::SetDockHasPauseButton(bool value)
|
||||
{
|
||||
_dockHasPauseButton = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->ShowPauseButton(value);
|
||||
}
|
||||
|
||||
void Macro::SetDockHasStatusLabel(bool value)
|
||||
{
|
||||
_dockHasStatusLabel = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->ShowStatusLabel(value);
|
||||
}
|
||||
|
||||
void Macro::SetHighlightEnable(bool value)
|
||||
{
|
||||
_dockHighlight = value;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->EnableHighlight(value);
|
||||
}
|
||||
|
||||
void Macro::SetRunButtonText(const std::string &text)
|
||||
{
|
||||
_runButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetRunButtonText(text);
|
||||
}
|
||||
|
||||
void Macro::SetPauseButtonText(const std::string &text)
|
||||
{
|
||||
_pauseButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetPauseButtonText(text);
|
||||
}
|
||||
|
||||
void Macro::SetUnpauseButtonText(const std::string &text)
|
||||
{
|
||||
_unpauseButtonText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetUnpauseButtonText(text);
|
||||
}
|
||||
|
||||
void Macro::SetConditionsTrueStatusText(const std::string &text)
|
||||
{
|
||||
_conditionsTrueStatusText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetConditionsTrueText(text);
|
||||
}
|
||||
|
||||
StringVariable Macro::ConditionsTrueStatusText() const
|
||||
{
|
||||
return _conditionsTrueStatusText;
|
||||
}
|
||||
|
||||
void Macro::SetConditionsFalseStatusText(const std::string &text)
|
||||
{
|
||||
_conditionsFalseStatusText = text;
|
||||
if (!_dock) {
|
||||
return;
|
||||
}
|
||||
_dock->SetConditionsFalseText(text);
|
||||
}
|
||||
|
||||
StringVariable Macro::ConditionsFalseStatusText() const
|
||||
{
|
||||
return _conditionsFalseStatusText;
|
||||
}
|
||||
|
||||
void Macro::RemoveDock()
|
||||
{
|
||||
obs_frontend_remove_dock(_dockId.c_str());
|
||||
_dock = nullptr;
|
||||
}
|
||||
|
||||
std::string Macro::GenerateDockId()
|
||||
{
|
||||
#if LIBOBS_API_VER > MAKE_SEMANTIC_VERSION(30, 0, 0)
|
||||
auto uuid = os_generate_uuid();
|
||||
auto id = std::string("advss-macro-dock-") + std::string(uuid);
|
||||
bfree(uuid);
|
||||
return id;
|
||||
|
||||
#else
|
||||
static std::atomic_int16_t idCounter = 0;
|
||||
return std::to_string(++idCounter);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void pauseCB(void *data, obs_hotkey_id, obs_hotkey_t *, bool pressed)
|
||||
{
|
||||
if (pressed) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "macro-action.hpp"
|
||||
#include "macro-condition.hpp"
|
||||
#include "macro-dock-settings.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-input.hpp"
|
||||
#include "macro-ref.hpp"
|
||||
@@ -20,7 +21,6 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MacroDock;
|
||||
class GlobalMacroSettings;
|
||||
|
||||
class Macro {
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
void SetInputVariables(const MacroInputVariables &);
|
||||
|
||||
// Temporary variable helpers
|
||||
std::vector<TempVariable> GetTempVars(MacroSegment *filter) const;
|
||||
std::vector<TempVariable> GetTempVars(const MacroSegment *filter) const;
|
||||
std::optional<const TempVariable>
|
||||
GetTempVar(const MacroSegment *, const std::string &id) const;
|
||||
void InvalidateTempVarValues() const;
|
||||
@@ -147,26 +147,7 @@ public:
|
||||
bool PauseHotkeysEnabled() const;
|
||||
|
||||
// Docks
|
||||
void EnableDock(bool);
|
||||
bool DockEnabled() const { return _registerDock; }
|
||||
void SetDockHasRunButton(bool value);
|
||||
bool DockHasRunButton() const { return _dockHasRunButton; }
|
||||
void SetDockHasPauseButton(bool value);
|
||||
bool DockHasPauseButton() const { return _dockHasPauseButton; }
|
||||
void SetDockHasStatusLabel(bool value);
|
||||
bool DockHasStatusLabel() const { return _dockHasStatusLabel; }
|
||||
void SetHighlightEnable(bool value);
|
||||
bool DockHighlightEnabled() const { return _dockHighlight; }
|
||||
StringVariable RunButtonText() const { return _runButtonText; }
|
||||
void SetRunButtonText(const std::string &text);
|
||||
StringVariable PauseButtonText() const { return _pauseButtonText; }
|
||||
void SetPauseButtonText(const std::string &text);
|
||||
StringVariable UnpauseButtonText() const { return _unpauseButtonText; }
|
||||
void SetUnpauseButtonText(const std::string &text);
|
||||
void SetConditionsTrueStatusText(const std::string &text);
|
||||
StringVariable ConditionsTrueStatusText() const;
|
||||
void SetConditionsFalseStatusText(const std::string &text);
|
||||
StringVariable ConditionsFalseStatusText() const;
|
||||
MacroDockSettings &GetDockSettings() { return _dockSettings; }
|
||||
|
||||
private:
|
||||
void SetupHotkeys();
|
||||
@@ -182,11 +163,6 @@ private:
|
||||
bool RunActions(bool ignorePause);
|
||||
bool RunElseActions(bool ignorePause);
|
||||
|
||||
void SaveDockSettings(obs_data_t *obj, bool saveForCopy) const;
|
||||
void LoadDockSettings(obs_data_t *obj);
|
||||
void RemoveDock();
|
||||
static std::string GenerateDockId();
|
||||
|
||||
std::string _name = "";
|
||||
bool _die = false;
|
||||
bool _stop = false;
|
||||
@@ -236,23 +212,7 @@ private:
|
||||
QList<int> _actionConditionSplitterPosition;
|
||||
QList<int> _elseActionSplitterPosition;
|
||||
|
||||
bool _registerDock = false;
|
||||
bool _dockHasRunButton = true;
|
||||
bool _dockHasPauseButton = true;
|
||||
bool _dockHasStatusLabel = false;
|
||||
bool _dockHighlight = false;
|
||||
StringVariable _runButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.run");
|
||||
StringVariable _pauseButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.pause");
|
||||
StringVariable _unpauseButtonText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.unpause");
|
||||
StringVariable _conditionsTrueStatusText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.true");
|
||||
StringVariable _conditionsFalseStatusText =
|
||||
obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.false");
|
||||
MacroDock *_dock = nullptr;
|
||||
std::string _dockId = GenerateDockId();
|
||||
MacroDockSettings _dockSettings;
|
||||
};
|
||||
|
||||
void LoadMacros(obs_data_t *obj);
|
||||
|
||||
@@ -44,11 +44,6 @@ void SwitcherData::Prune()
|
||||
}
|
||||
}
|
||||
|
||||
if (nonMatchingScene && !WeakSourceValid(nonMatchingScene)) {
|
||||
switchIfNotMatching = NoMatchBehavior::NO_SWITCH;
|
||||
nonMatchingScene = nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < randomSwitches.size(); i++) {
|
||||
RandomSwitch &s = randomSwitches[i];
|
||||
if (!s.valid()) {
|
||||
@@ -168,31 +163,6 @@ void SwitcherData::SaveVersion(obs_data_t *obj,
|
||||
obs_data_set_string(obj, "version", currentVersion.c_str());
|
||||
}
|
||||
|
||||
void SwitcherData::RunPostLoadSteps()
|
||||
{
|
||||
for (const auto &func : postLoadSteps) {
|
||||
func();
|
||||
}
|
||||
postLoadSteps.clear();
|
||||
}
|
||||
|
||||
void SwitcherData::AddSaveStep(std::function<void(obs_data_t *)> function)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
saveSteps.emplace_back(function);
|
||||
}
|
||||
|
||||
void SwitcherData::AddLoadStep(std::function<void(obs_data_t *)> function)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
loadSteps.emplace_back(function);
|
||||
}
|
||||
|
||||
void SwitcherData::AddPostLoadStep(std::function<void()> function)
|
||||
{
|
||||
postLoadSteps.emplace_back(function);
|
||||
}
|
||||
|
||||
static void startHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
|
||||
{
|
||||
if (pressed) {
|
||||
|
||||
@@ -14,10 +14,12 @@
|
||||
#include "switch-sequence.hpp"
|
||||
#include "switch-video.hpp"
|
||||
|
||||
#include "macro-settings.hpp"
|
||||
#include "duration-control.hpp"
|
||||
#include "priority-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "priority-helper.hpp"
|
||||
#include "regex-config.hpp"
|
||||
#include "scene-selection.hpp"
|
||||
#include "variable-string.hpp"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <vector>
|
||||
@@ -57,15 +59,12 @@ public:
|
||||
bool AnySceneTransitionStarted();
|
||||
|
||||
void SetPreconditions();
|
||||
void AddSaveStep(std::function<void(obs_data_t *)>);
|
||||
void AddLoadStep(std::function<void(obs_data_t *)>);
|
||||
void AddPostLoadStep(std::function<void()>);
|
||||
void RunPostLoadSteps();
|
||||
bool CheckForMatch(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||
int &linger, bool &setPreviousSceneAsMatch,
|
||||
bool ¯oMatch);
|
||||
void CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||
OBSWeakSource &transition, int &sleep);
|
||||
void CheckAutoStart();
|
||||
|
||||
/* --- Start of saving / loading section --- */
|
||||
|
||||
@@ -95,10 +94,6 @@ public:
|
||||
bool stop = false;
|
||||
std::condition_variable cv;
|
||||
|
||||
std::vector<std::function<void(obs_data_t *)>> saveSteps;
|
||||
std::vector<std::function<void(obs_data_t *)>> loadSteps;
|
||||
std::vector<std::function<void()>> postLoadSteps;
|
||||
|
||||
bool firstBoot = true;
|
||||
bool transitionActive = false;
|
||||
bool sceneCollectionStop = false;
|
||||
@@ -114,7 +109,7 @@ public:
|
||||
/* --- Start of General tab section --- */
|
||||
|
||||
int interval = default_interval;
|
||||
OBSWeakSource nonMatchingScene;
|
||||
SceneSelection nonMatchingScene;
|
||||
NoMatchBehavior switchIfNotMatching = NoMatchBehavior::NO_SWITCH;
|
||||
Duration noMatchDelay;
|
||||
enum class StartupBehavior { PERSIST = 0, START = 1, STOP = 2 };
|
||||
@@ -126,6 +121,10 @@ public:
|
||||
RECORINDG_OR_STREAMING
|
||||
};
|
||||
AutoStart autoStartEvent = AutoStart::NEVER;
|
||||
bool useAutoStartScene = false;
|
||||
SceneSelection autoStartScene;
|
||||
StringVariable autoStartSceneName;
|
||||
RegexConfig autoStartSceneRegex;
|
||||
bool enableCooldown = false;
|
||||
Duration cooldown;
|
||||
bool showSystemTrayNotifications = false;
|
||||
|
||||
@@ -2,31 +2,31 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
AutoUpdateTooltipLabel::AutoUpdateTooltipLabel(
|
||||
AutoUpdateHelpIcon::AutoUpdateHelpIcon(
|
||||
QWidget *parent, const std::function<QString()> &updateTooltipCallback,
|
||||
int updateIntervalMs)
|
||||
: QLabel(parent),
|
||||
: HelpIcon("", parent),
|
||||
_callback(updateTooltipCallback),
|
||||
_timer(new QTimer(this)),
|
||||
_updateIntervalMs(updateIntervalMs)
|
||||
{
|
||||
connect(_timer, &QTimer::timeout, this,
|
||||
&AutoUpdateTooltipLabel::UpdateTooltip);
|
||||
&AutoUpdateHelpIcon::UpdateTooltip);
|
||||
}
|
||||
|
||||
void AutoUpdateTooltipLabel::enterEvent(QEnterEvent *event)
|
||||
void AutoUpdateHelpIcon::enterEvent(QEnterEvent *event)
|
||||
{
|
||||
_timer->start(_updateIntervalMs);
|
||||
QLabel::enterEvent(event);
|
||||
}
|
||||
|
||||
void AutoUpdateTooltipLabel::leaveEvent(QEvent *event)
|
||||
void AutoUpdateHelpIcon::leaveEvent(QEvent *event)
|
||||
{
|
||||
_timer->stop();
|
||||
QLabel::leaveEvent(event);
|
||||
}
|
||||
|
||||
void AutoUpdateTooltipLabel::UpdateTooltip()
|
||||
void AutoUpdateHelpIcon::UpdateTooltip()
|
||||
{
|
||||
setToolTip(_callback());
|
||||
}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
#pragma once
|
||||
#include "export-symbol-helper.hpp"
|
||||
#include "help-icon.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class ADVSS_EXPORT AutoUpdateTooltipLabel : public QLabel {
|
||||
class ADVSS_EXPORT AutoUpdateHelpIcon : public HelpIcon {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AutoUpdateTooltipLabel(
|
||||
QWidget *parent,
|
||||
const std::function<QString()> &updateTooltipCallback,
|
||||
int updateIntervalMs = 300);
|
||||
AutoUpdateHelpIcon(QWidget *parent,
|
||||
const std::function<QString()> &updateTooltipCallback,
|
||||
int updateIntervalMs = 300);
|
||||
|
||||
protected:
|
||||
void enterEvent(QEnterEvent *event) override;
|
||||
|
||||
296
lib/utils/canvas-helpers.cpp
Normal file
296
lib/utils/canvas-helpers.cpp
Normal file
@@ -0,0 +1,296 @@
|
||||
#include "canvas-helpers.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "scene-group.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "selection-helpers.hpp"
|
||||
#include "source-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "variable.hpp"
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
#include <QLayout>
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
Q_DECLARE_METATYPE(advss::OBSWeakCanvas);
|
||||
#else
|
||||
Q_DECLARE_METATYPE(OBSWeakCanvas);
|
||||
#endif
|
||||
|
||||
namespace advss {
|
||||
|
||||
void CanvasSelection::Populate()
|
||||
{
|
||||
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
static const auto enumCanvases = [](void *listPtr,
|
||||
obs_canvas_t *canvas) -> bool {
|
||||
auto list = static_cast<FilterComboBox *>(listPtr);
|
||||
OBSWeakCanvas weakCanvas = obs_canvas_get_weak_canvas(canvas);
|
||||
obs_weak_canvas_release(weakCanvas);
|
||||
QVariant variant;
|
||||
variant.setValue(weakCanvas);
|
||||
list->addItem(obs_canvas_get_name(canvas), variant);
|
||||
return true;
|
||||
};
|
||||
obs_enum_canvases(enumCanvases, this);
|
||||
#endif
|
||||
}
|
||||
|
||||
CanvasSelection::CanvasSelection(QWidget *parent)
|
||||
: FilterComboBox(parent,
|
||||
obs_module_text("AdvSceneSwitcher.selectScene"))
|
||||
{
|
||||
setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
|
||||
Populate();
|
||||
|
||||
connect(this, &FilterComboBox::currentIndexChanged, this,
|
||||
[this]() { emit CanvasChanged(GetCanvas()); });
|
||||
}
|
||||
|
||||
void CanvasSelection::SetCanvas(const OBSWeakCanvas &canvas)
|
||||
{
|
||||
QVariant variant;
|
||||
variant.setValue(canvas);
|
||||
setCurrentIndex(findData(variant));
|
||||
}
|
||||
|
||||
OBSWeakCanvas CanvasSelection::GetCanvas()
|
||||
{
|
||||
return itemData(currentIndex()).value<OBSWeakCanvas>();
|
||||
}
|
||||
|
||||
int GetCanvasCount()
|
||||
{
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
return 1;
|
||||
#else
|
||||
static const auto enumCanvases = [](void *countPtr,
|
||||
obs_canvas_t *canvas) -> bool {
|
||||
auto count = static_cast<int *>(countPtr);
|
||||
(*count)++;
|
||||
return true;
|
||||
};
|
||||
int count = 0;
|
||||
obs_enum_canvases(enumCanvases, &count);
|
||||
return count;
|
||||
#endif
|
||||
}
|
||||
|
||||
OBSWeakCanvas GetWeakCanvasByName(const char *name)
|
||||
{
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
return OBSWeakCanvas();
|
||||
#else
|
||||
struct Data {
|
||||
OBSWeakCanvas canvas;
|
||||
const std::string name;
|
||||
};
|
||||
|
||||
static const auto enumCanvases = [](void *dataPtr,
|
||||
obs_canvas_t *canvas) -> bool {
|
||||
auto data = static_cast<Data *>(dataPtr);
|
||||
if (data->name != obs_canvas_get_name(canvas)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
data->canvas = obs_canvas_get_weak_canvas(canvas);
|
||||
obs_weak_canvas_release(data->canvas);
|
||||
return false;
|
||||
};
|
||||
Data data{nullptr, name};
|
||||
obs_enum_canvases(enumCanvases, &data);
|
||||
return data.canvas;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string GetWeakCanvasName(const OBSWeakCanvas &weakCanvas)
|
||||
{
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
return "Main";
|
||||
#else
|
||||
OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas);
|
||||
return canvas ? obs_canvas_get_name(canvas) : "";
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IsMainCanvas(obs_weak_canvas_t *weakCanvas)
|
||||
{
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
return true;
|
||||
#else
|
||||
if (!weakCanvas) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas);
|
||||
OBSCanvasAutoRelease main = obs_get_main_canvas();
|
||||
return canvas == main;
|
||||
#endif
|
||||
}
|
||||
|
||||
OBSWeakSource GetActiveCanvasScene(const OBSWeakCanvas &weakCanvas)
|
||||
{
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
OBSCanvasAutoRelease canvas;
|
||||
#else
|
||||
if (!weakCanvas) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas);
|
||||
if (!canvas) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const auto enumCanvasScenes = [](void *scenePtr,
|
||||
obs_source_t *source) -> bool {
|
||||
auto scene = static_cast<OBSWeakSource *>(scenePtr);
|
||||
if (!obs_source_active(source)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*scene = obs_source_get_weak_source(source);
|
||||
obs_weak_source_release(*scene);
|
||||
return false;
|
||||
};
|
||||
|
||||
OBSWeakSource scene;
|
||||
obs_canvas_enum_scenes(canvas, enumCanvasScenes, &scene);
|
||||
return scene;
|
||||
}
|
||||
|
||||
OBSWeakSource GetSceneAtIndex(const OBSWeakCanvas &weakCanvas, int idx)
|
||||
{
|
||||
if (idx < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
OBSCanvas canvas;
|
||||
#else
|
||||
if (!weakCanvas) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OBSCanvas canvas = OBSGetStrongRef(weakCanvas);
|
||||
if (!canvas) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Data {
|
||||
const int idx;
|
||||
int currentIdx;
|
||||
OBSSource scene;
|
||||
};
|
||||
|
||||
static const auto enumCanvasScenes = [](void *dataPtr,
|
||||
obs_source_t *source) -> bool {
|
||||
auto data = static_cast<Data *>(dataPtr);
|
||||
if (data->idx != data->currentIdx) {
|
||||
data->currentIdx++;
|
||||
return true;
|
||||
}
|
||||
|
||||
data->scene = source;
|
||||
return false;
|
||||
};
|
||||
|
||||
Data data{idx, 0, nullptr};
|
||||
obs_canvas_enum_scenes(canvas, enumCanvasScenes, &data);
|
||||
|
||||
return OBSGetWeakRef(data.scene);
|
||||
}
|
||||
|
||||
int GetIndexOfScene(const OBSWeakCanvas &weakCanvas, const OBSWeakSource &scene)
|
||||
{
|
||||
if (!scene) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
OBSCanvas canvas;
|
||||
#else
|
||||
if (!weakCanvas) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
OBSCanvas canvas = OBSGetStrongRef(weakCanvas);
|
||||
if (!canvas) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct Data {
|
||||
int idx;
|
||||
OBSSource scene;
|
||||
};
|
||||
|
||||
static const auto enumCanvasScenes = [](void *dataPtr,
|
||||
obs_source_t *source) -> bool {
|
||||
auto data = static_cast<Data *>(dataPtr);
|
||||
if (source == data->scene) {
|
||||
return false;
|
||||
}
|
||||
|
||||
data->idx++;
|
||||
return true;
|
||||
};
|
||||
|
||||
Data data{0, OBSGetStrongRef(scene)};
|
||||
obs_canvas_enum_scenes(canvas, enumCanvasScenes, &data);
|
||||
|
||||
return data.idx;
|
||||
}
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
|
||||
obs_canvas_t *obs_canvas_get_ref(obs_canvas_t *)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void obs_canvas_release(obs_canvas_t *) {}
|
||||
|
||||
void obs_weak_canvas_addref(obs_weak_canvas_t *) {}
|
||||
|
||||
void obs_weak_canvas_release(obs_weak_canvas_t *) {}
|
||||
|
||||
OBSCanvas OBSGetStrongRef(obs_weak_object_t *weak)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
obs_weak_canvas_t *obs_canvas_get_weak_canvas(obs_canvas_t *)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
obs_canvas_t *obs_weak_canvas_get_canvas(obs_weak_canvas_t *)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void obs_canvas_enum_scenes(obs_canvas_t *,
|
||||
bool (*enum_proc)(void *, obs_source_t *),
|
||||
void *param)
|
||||
{
|
||||
obs_enum_scenes(enum_proc, param);
|
||||
}
|
||||
|
||||
OBSCanvas OBSGetStrongRef(obs_weak_canvas_t *)
|
||||
{
|
||||
return OBSCanvas();
|
||||
}
|
||||
|
||||
obs_canvas_t *obs_get_main_canvas()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace advss
|
||||
61
lib/utils/canvas-helpers.hpp
Normal file
61
lib/utils/canvas-helpers.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include "filter-combo-box.hpp"
|
||||
|
||||
#include <obs.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
class EXPORT obs_canvas_t {};
|
||||
class EXPORT obs_weak_canvas_t {};
|
||||
|
||||
EXPORT obs_canvas_t *obs_canvas_get_ref(obs_canvas_t *);
|
||||
EXPORT void obs_canvas_release(obs_canvas_t *);
|
||||
EXPORT void obs_weak_canvas_addref(obs_weak_canvas_t *);
|
||||
EXPORT void obs_weak_canvas_release(obs_weak_canvas_t *);
|
||||
|
||||
using OBSCanvas =
|
||||
OBSSafeRef<obs_canvas_t *, obs_canvas_get_ref, obs_canvas_release>;
|
||||
using OBSWeakCanvas = OBSRef<obs_weak_canvas_t *, obs_weak_canvas_addref,
|
||||
obs_weak_canvas_release>;
|
||||
using OBSCanvasAutoRelease =
|
||||
OBSRefAutoRelease<obs_canvas_t *, obs_canvas_release>;
|
||||
using OBSWeakCanvasAutoRelease =
|
||||
OBSRefAutoRelease<obs_weak_canvas_t *, obs_weak_canvas_release>;
|
||||
|
||||
EXPORT obs_weak_canvas_t *obs_canvas_get_weak_canvas(obs_canvas_t *);
|
||||
EXPORT obs_canvas_t *obs_weak_canvas_get_canvas(obs_weak_canvas_t *);
|
||||
EXPORT void obs_canvas_enum_scenes(obs_canvas_t *,
|
||||
bool (*enum_proc)(void *, obs_source_t *),
|
||||
void *param);
|
||||
EXPORT OBSCanvas OBSGetStrongRef(obs_weak_canvas_t *);
|
||||
EXPORT OBSWeakCanvas OBSGetWeakRef(obs_canvas_t *);
|
||||
EXPORT obs_canvas_t *obs_get_main_canvas();
|
||||
|
||||
#endif
|
||||
|
||||
EXPORT int GetCanvasCount();
|
||||
EXPORT OBSWeakCanvas GetWeakCanvasByName(const char *name);
|
||||
EXPORT std::string GetWeakCanvasName(const OBSWeakCanvas &canvas);
|
||||
EXPORT bool IsMainCanvas(obs_weak_canvas_t *canvas);
|
||||
EXPORT OBSWeakSource GetActiveCanvasScene(const OBSWeakCanvas &canvas);
|
||||
EXPORT OBSWeakSource GetSceneAtIndex(const OBSWeakCanvas &weakCanvas, int idx);
|
||||
EXPORT int GetIndexOfScene(const OBSWeakCanvas &weakCanvas,
|
||||
const OBSWeakSource &scene);
|
||||
|
||||
class CanvasSelection : public FilterComboBox {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
EXPORT CanvasSelection(QWidget *parent);
|
||||
EXPORT void SetCanvas(const OBSWeakCanvas &);
|
||||
EXPORT OBSWeakCanvas GetCanvas();
|
||||
|
||||
signals:
|
||||
void CanvasChanged(const OBSWeakCanvas &);
|
||||
|
||||
private:
|
||||
void Populate();
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -35,6 +35,11 @@ void FileSelection::SetPath(const QString &path)
|
||||
_filePath->setText(path);
|
||||
}
|
||||
|
||||
QString FileSelection::GetPath() const
|
||||
{
|
||||
return _filePath->text();
|
||||
}
|
||||
|
||||
QString FileSelection::ValidPathOrDesktop(const QString &path)
|
||||
{
|
||||
QFileInfo fileInfo(path);
|
||||
|
||||
@@ -22,6 +22,7 @@ public:
|
||||
QWidget *parent = 0);
|
||||
EXPORT void SetPath(const StringVariable &);
|
||||
EXPORT void SetPath(const QString &);
|
||||
EXPORT QString GetPath() const;
|
||||
EXPORT QPushButton *Button() { return _browseButton; }
|
||||
EXPORT static QString ValidPathOrDesktop(const QString &path);
|
||||
|
||||
|
||||
@@ -84,6 +84,21 @@ void FilterComboBox::setItemText(int index, const QString &text)
|
||||
}
|
||||
}
|
||||
|
||||
QSize FilterComboBox::sizeHint() const
|
||||
{
|
||||
QSize size = QComboBox::sizeHint();
|
||||
|
||||
if (!_filteringEnabled) {
|
||||
return QComboBox::sizeHint();
|
||||
}
|
||||
|
||||
QFontMetrics fm(font());
|
||||
int extra = fm.horizontalAdvance("X") * 2; // Add padding
|
||||
size.setWidth(size.width() + extra);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void FilterComboBox::focusOutEvent(QFocusEvent *event)
|
||||
{
|
||||
// Reset on invalid selection
|
||||
@@ -96,7 +111,7 @@ void FilterComboBox::focusOutEvent(QFocusEvent *event)
|
||||
_lastCompleterHighlightRow = -1;
|
||||
}
|
||||
|
||||
static int findXthOccurance(QComboBox *list, int count, const QString &value)
|
||||
static int findXthOccurrence(QComboBox *list, int count, const QString &value)
|
||||
{
|
||||
if (value.isEmpty() || count < 1) {
|
||||
return -1;
|
||||
@@ -121,7 +136,7 @@ void FilterComboBox::CompleterHighlightChanged(const QModelIndex &index)
|
||||
{
|
||||
_lastCompleterHighlightRow = index.row();
|
||||
const auto text = currentText();
|
||||
int idx = findXthOccurance(this, _lastCompleterHighlightRow, text);
|
||||
int idx = findXthOccurrence(this, _lastCompleterHighlightRow, text);
|
||||
if (idx == -1) {
|
||||
return;
|
||||
}
|
||||
@@ -133,7 +148,7 @@ void FilterComboBox::TextChanged(const QString &text)
|
||||
auto c = completer();
|
||||
const bool completerActive = c->completionCount() > 0;
|
||||
int count = completerActive ? _lastCompleterHighlightRow + 1 : 1;
|
||||
int idx = findXthOccurance(this, count, text);
|
||||
int idx = findXthOccurrence(this, count, text);
|
||||
if (idx == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ public:
|
||||
void setCurrentText(const QString &text);
|
||||
void setItemText(int index, const QString &text);
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
protected:
|
||||
void focusOutEvent(QFocusEvent *event) override;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ class ADVSS_EXPORT ListEditor : public QWidget {
|
||||
|
||||
public:
|
||||
ListEditor(QWidget *parent = nullptr, bool reorder = true);
|
||||
int count() const { return _list->count(); };
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *);
|
||||
|
||||
@@ -45,7 +45,10 @@ NonModalMessageDialog::NonModalMessageDialog(const QString &message, Type type,
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
layout->addWidget(new QLabel(message, this));
|
||||
auto label = new QLabel(message, this);
|
||||
label->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
label->setOpenExternalLinks(true);
|
||||
layout->addWidget(label);
|
||||
|
||||
switch (type) {
|
||||
case Type::INFO: {
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "macro-settings.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
static std::mutex initMutex;
|
||||
static std::mutex postLoadMutex;
|
||||
static std::mutex mutex;
|
||||
|
||||
static std::vector<std::function<void()>> &getPluginInitSteps()
|
||||
{
|
||||
static std::vector<std::function<void()>> steps;
|
||||
@@ -39,7 +45,23 @@ static std::vector<std::function<void()>> &getStopSteps()
|
||||
return steps;
|
||||
}
|
||||
|
||||
static std::mutex mutex;
|
||||
static std::vector<std::function<void(obs_data_t *)>> &getSaveSteps()
|
||||
{
|
||||
static std::vector<std::function<void(obs_data_t *)>> steps;
|
||||
return steps;
|
||||
}
|
||||
|
||||
static std::vector<std::function<void(obs_data_t *)>> &getLoadSteps()
|
||||
{
|
||||
static std::vector<std::function<void(obs_data_t *)>> steps;
|
||||
return steps;
|
||||
}
|
||||
|
||||
static std::vector<std::function<void()>> &getPostLoadSteps()
|
||||
{
|
||||
static std::vector<std::function<void()>> steps;
|
||||
return steps;
|
||||
}
|
||||
|
||||
void SavePluginSettings(obs_data_t *obj)
|
||||
{
|
||||
@@ -53,17 +75,20 @@ void LoadPluginSettings(obs_data_t *obj)
|
||||
|
||||
void AddSaveStep(std::function<void(obs_data_t *)> step)
|
||||
{
|
||||
GetSwitcher()->AddSaveStep(step);
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
getSaveSteps().emplace_back(step);
|
||||
}
|
||||
|
||||
void AddLoadStep(std::function<void(obs_data_t *)> step)
|
||||
{
|
||||
GetSwitcher()->AddLoadStep(step);
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
getLoadSteps().emplace_back(step);
|
||||
}
|
||||
|
||||
void AddPostLoadStep(std::function<void()> step)
|
||||
{
|
||||
GetSwitcher()->AddPostLoadStep(step);
|
||||
std::lock_guard<std::mutex> lock(postLoadMutex);
|
||||
getPostLoadSteps().emplace_back(step);
|
||||
}
|
||||
|
||||
void AddIntervalResetStep(std::function<void()> step)
|
||||
@@ -72,20 +97,45 @@ void AddIntervalResetStep(std::function<void()> step)
|
||||
getResetIntervalSteps().emplace_back(step);
|
||||
}
|
||||
|
||||
void RunSaveSteps(obs_data_t *obj)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
for (const auto &func : getSaveSteps()) {
|
||||
func(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void RunLoadSteps(obs_data_t *obj)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
for (const auto &func : getLoadSteps()) {
|
||||
func(obj);
|
||||
}
|
||||
}
|
||||
|
||||
void RunPostLoadSteps()
|
||||
{
|
||||
GetSwitcher()->RunPostLoadSteps();
|
||||
std::lock_guard<std::mutex> lock(postLoadMutex);
|
||||
for (const auto &func : getPostLoadSteps()) {
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
void ClearPostLoadSteps()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(postLoadMutex);
|
||||
getPostLoadSteps().clear();
|
||||
}
|
||||
|
||||
void AddPluginInitStep(std::function<void()> step)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
std::lock_guard<std::mutex> lock(initMutex);
|
||||
getPluginInitSteps().emplace_back(step);
|
||||
}
|
||||
|
||||
void AddPluginPostLoadStep(std::function<void()> step)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
std::lock_guard<std::mutex> lock(initMutex);
|
||||
getPluginPostLoadSteps().emplace_back(step);
|
||||
}
|
||||
|
||||
@@ -97,7 +147,7 @@ void AddPluginCleanupStep(std::function<void()> step)
|
||||
|
||||
void RunPluginInitSteps()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
std::lock_guard<std::mutex> lock(initMutex);
|
||||
for (const auto &step : getPluginInitSteps()) {
|
||||
step();
|
||||
}
|
||||
@@ -188,7 +238,7 @@ NoMatchBehavior GetPluginNoMatchBehavior()
|
||||
|
||||
void SetNoMatchScene(const OBSWeakSource &scene)
|
||||
{
|
||||
GetSwitcher()->nonMatchingScene = scene;
|
||||
GetSwitcher()->nonMatchingScene.SetScene(scene);
|
||||
}
|
||||
|
||||
std::string ForegroundWindowTitle()
|
||||
@@ -231,4 +281,30 @@ bool IsFirstIntervalAfterStop()
|
||||
return GetSwitcher()->firstIntervalAfterStop;
|
||||
}
|
||||
|
||||
void SetMacroHighlightingEnabled(bool enable)
|
||||
{
|
||||
auto &settings = GetGlobalMacroSettings();
|
||||
settings._highlightActions = enable;
|
||||
settings._highlightConditions = enable;
|
||||
settings._highlightExecuted = enable;
|
||||
|
||||
obs_queue_task(
|
||||
OBS_TASK_UI,
|
||||
[](void *) {
|
||||
if (!SettingsWindowIsOpened()) {
|
||||
return;
|
||||
}
|
||||
MacroSignalManager::Instance()->HighlightChanged(
|
||||
GetGlobalMacroSettings()._highlightExecuted);
|
||||
},
|
||||
nullptr, false);
|
||||
}
|
||||
|
||||
bool IsMacroHighlightingEnabled()
|
||||
{
|
||||
const auto &settings = GetGlobalMacroSettings();
|
||||
return settings._highlightActions || settings._highlightConditions ||
|
||||
settings._highlightExecuted;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -12,7 +12,10 @@ 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()>);
|
||||
void RunSaveSteps(obs_data_t *);
|
||||
void RunLoadSteps(obs_data_t *);
|
||||
EXPORT void RunPostLoadSteps();
|
||||
void ClearPostLoadSteps();
|
||||
|
||||
EXPORT void AddPluginInitStep(std::function<void()>);
|
||||
EXPORT void AddPluginPostLoadStep(std::function<void()>);
|
||||
@@ -47,4 +50,7 @@ EXPORT bool InitialLoadIsComplete();
|
||||
EXPORT bool IsFirstInterval();
|
||||
EXPORT bool IsFirstIntervalAfterStop();
|
||||
|
||||
EXPORT void SetMacroHighlightingEnabled(bool enable);
|
||||
EXPORT bool IsMacroHighlightingEnabled();
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -111,6 +111,10 @@ std::vector<ThreadPrio> GetThreadPrioMapping()
|
||||
|
||||
bool SwitcherData::PrioFuncsValid()
|
||||
{
|
||||
if (functionNamesByPriority.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto fNBPCopy = functionNamesByPriority;
|
||||
|
||||
std::sort(fNBPCopy.begin(), fNBPCopy.end());
|
||||
|
||||
@@ -10,15 +10,18 @@
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
#include <QLayout>
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr std::string_view typeSaveName = "type";
|
||||
constexpr std::string_view nameSaveName = "name";
|
||||
constexpr std::string_view selectionSaveName = "sceneSelection";
|
||||
constexpr std::string_view canvasSaveName = "canvasSelection";
|
||||
|
||||
void SceneSelection::Save(obs_data_t *obj) const
|
||||
{
|
||||
auto data = obs_data_create();
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
obs_data_set_int(data, typeSaveName.data(), static_cast<int>(_type));
|
||||
switch (_type) {
|
||||
case Type::SCENE:
|
||||
@@ -41,8 +44,31 @@ void SceneSelection::Save(obs_data_t *obj) const
|
||||
default:
|
||||
break;
|
||||
}
|
||||
obs_data_set_string(data, canvasSaveName.data(),
|
||||
GetWeakCanvasName(_canvas).c_str());
|
||||
obs_data_set_obj(obj, selectionSaveName.data(), data);
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
||||
static OBSWeakSource getWeakSceneSourceByName(const OBSWeakCanvas &weakCanvas,
|
||||
const char *name)
|
||||
{
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
return GetWeakSourceByName(name);
|
||||
#else
|
||||
if (!weakCanvas) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas);
|
||||
if (!canvas) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OBSSourceAutoRelease source =
|
||||
obs_canvas_get_source_by_name(canvas, name);
|
||||
OBSWeakSource scene = OBSGetWeakRef(source);
|
||||
return scene;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SceneSelection::Load(obs_data_t *obj, const char *name,
|
||||
@@ -51,10 +77,15 @@ void SceneSelection::Load(obs_data_t *obj, const char *name,
|
||||
// TODO: Remove in future version
|
||||
if (!obs_data_has_user_value(obj, selectionSaveName.data())) {
|
||||
_type = static_cast<Type>(obs_data_get_int(obj, typeName));
|
||||
|
||||
OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas();
|
||||
_canvas = obs_canvas_get_weak_canvas(mainCanvas);
|
||||
obs_weak_canvas_release(_canvas);
|
||||
|
||||
auto targetName = obs_data_get_string(obj, name);
|
||||
switch (_type) {
|
||||
case Type::SCENE:
|
||||
_scene = GetWeakSourceByName(targetName);
|
||||
_scene = getWeakSceneSourceByName(_canvas, targetName);
|
||||
break;
|
||||
case Type::GROUP:
|
||||
_group = GetSceneGroupByName(targetName);
|
||||
@@ -69,12 +100,23 @@ void SceneSelection::Load(obs_data_t *obj, const char *name,
|
||||
return;
|
||||
}
|
||||
|
||||
auto data = obs_data_get_obj(obj, selectionSaveName.data());
|
||||
OBSDataAutoRelease data =
|
||||
obs_data_get_obj(obj, selectionSaveName.data());
|
||||
|
||||
if (obs_data_has_user_value(data, canvasSaveName.data())) {
|
||||
_canvas = GetWeakCanvasByName(
|
||||
obs_data_get_string(data, canvasSaveName.data()));
|
||||
} else {
|
||||
OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas();
|
||||
_canvas = obs_canvas_get_weak_canvas(mainCanvas);
|
||||
obs_weak_canvas_release(_canvas);
|
||||
}
|
||||
|
||||
_type = static_cast<Type>(obs_data_get_int(data, typeSaveName.data()));
|
||||
auto targetName = obs_data_get_string(data, nameSaveName.data());
|
||||
switch (_type) {
|
||||
case Type::SCENE:
|
||||
_scene = GetWeakSourceByName(targetName);
|
||||
_scene = getWeakSceneSourceByName(_canvas, targetName);
|
||||
break;
|
||||
case Type::GROUP:
|
||||
_group = GetSceneGroupByName(targetName);
|
||||
@@ -91,15 +133,18 @@ void SceneSelection::Load(obs_data_t *obj, const char *name,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
obs_data_release(data);
|
||||
}
|
||||
|
||||
static bool IsScene(const OBSWeakSource &source)
|
||||
static bool isScene(const OBSWeakSource &source)
|
||||
{
|
||||
auto s = obs_weak_source_get_source(source);
|
||||
bool ret = !!obs_scene_from_source(s);
|
||||
obs_source_release(s);
|
||||
return ret;
|
||||
OBSSourceAutoRelease s = obs_weak_source_get_source(source);
|
||||
return !!obs_scene_from_source(s);
|
||||
}
|
||||
|
||||
void SceneSelection::SetScene(const OBSWeakSource &scene)
|
||||
{
|
||||
_type = Type::SCENE;
|
||||
_scene = scene;
|
||||
}
|
||||
|
||||
OBSWeakSource SceneSelection::GetScene(bool advance) const
|
||||
@@ -116,23 +161,30 @@ OBSWeakSource SceneSelection::GetScene(bool advance) const
|
||||
}
|
||||
return _group->getCurrentScene();
|
||||
case Type::PREVIOUS:
|
||||
if (!IsMainCanvas(_canvas)) {
|
||||
return nullptr;
|
||||
}
|
||||
return GetPreviousScene();
|
||||
case Type::CURRENT:
|
||||
return GetCurrentScene();
|
||||
if (IsMainCanvas(_canvas)) {
|
||||
return GetCurrentScene();
|
||||
} else {
|
||||
return GetActiveCanvasScene(_canvas);
|
||||
}
|
||||
case Type::PREVIEW: {
|
||||
auto s = obs_frontend_get_current_preview_scene();
|
||||
auto scene = obs_source_get_weak_source(s);
|
||||
obs_weak_source_release(scene);
|
||||
obs_source_release(s);
|
||||
return scene;
|
||||
OBSSourceAutoRelease s =
|
||||
obs_frontend_get_current_preview_scene();
|
||||
OBSWeakSourceAutoRelease scene = obs_source_get_weak_source(s);
|
||||
return scene.Get();
|
||||
}
|
||||
case Type::VARIABLE: {
|
||||
auto var = _variable.lock();
|
||||
if (!var) {
|
||||
return nullptr;
|
||||
}
|
||||
auto scene = GetWeakSourceByName(var->Value().c_str());
|
||||
if (IsScene(scene)) {
|
||||
auto scene =
|
||||
getWeakSceneSourceByName(_canvas, var->Value().c_str());
|
||||
if (isScene(scene)) {
|
||||
return scene;
|
||||
}
|
||||
return nullptr;
|
||||
@@ -190,8 +242,23 @@ void SceneSelection::ResolveVariables()
|
||||
SceneSelection SceneSelectionWidget::CurrentSelection()
|
||||
{
|
||||
SceneSelection s;
|
||||
const int idx = currentIndex();
|
||||
const auto name = currentText();
|
||||
|
||||
static auto mainCanvas = obs_get_main_canvas();
|
||||
static auto mainCanvasWeak = obs_canvas_get_weak_canvas(mainCanvas);
|
||||
[[maybe_unused]] static const bool _ = []() {
|
||||
// Let's just hope we don't have to deal with selecting scenes
|
||||
// when the OBS main canvas gets deleted and release the
|
||||
// references here already to avoid reporting leaks on shutdown
|
||||
obs_canvas_release(mainCanvas);
|
||||
obs_weak_canvas_release(mainCanvasWeak);
|
||||
return true;
|
||||
}();
|
||||
|
||||
s._canvas = _forceMainCanvas ? OBSWeakCanvas(mainCanvasWeak)
|
||||
: _canvas->GetCanvas();
|
||||
|
||||
const int idx = _scenes->currentIndex();
|
||||
const auto name = _scenes->currentText();
|
||||
if (idx == -1 || name.isEmpty()) {
|
||||
return s;
|
||||
}
|
||||
@@ -214,7 +281,8 @@ SceneSelection SceneSelectionWidget::CurrentSelection()
|
||||
s._group = GetSceneGroupByQString(name);
|
||||
} else if (idx < _scenesEndIdx) {
|
||||
s._type = SceneSelection::Type::SCENE;
|
||||
s._scene = GetWeakSourceByQString(name);
|
||||
s._scene = getWeakSceneSourceByName(s._canvas,
|
||||
name.toStdString().c_str());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
@@ -234,20 +302,6 @@ static QStringList getOrderList(bool current, bool previous, bool preview)
|
||||
return list;
|
||||
}
|
||||
|
||||
static QStringList getScenesList()
|
||||
{
|
||||
QStringList list;
|
||||
char **scenes = obs_frontend_get_scene_names();
|
||||
char **temp = scenes;
|
||||
while (*temp) {
|
||||
const char *name = *temp;
|
||||
list << name;
|
||||
temp++;
|
||||
}
|
||||
bfree(scenes);
|
||||
return list;
|
||||
}
|
||||
|
||||
static QStringList getSceneGroupsList()
|
||||
{
|
||||
QStringList list;
|
||||
@@ -258,72 +312,92 @@ static QStringList getSceneGroupsList()
|
||||
return list;
|
||||
}
|
||||
|
||||
static QStringList getCanvasScenesList(obs_weak_canvas_t *weakCanvas)
|
||||
{
|
||||
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
if (!weakCanvas) {
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
OBSCanvasAutoRelease canvas = obs_weak_canvas_get_canvas(weakCanvas);
|
||||
static const auto enumCanvasScenes = [](void *listPtr,
|
||||
obs_source_t *source) -> bool {
|
||||
auto list = static_cast<QStringList *>(listPtr);
|
||||
*list << obs_source_get_name(source);
|
||||
return true;
|
||||
};
|
||||
|
||||
QStringList list;
|
||||
obs_canvas_enum_scenes(canvas, enumCanvasScenes, &list);
|
||||
return list;
|
||||
}
|
||||
|
||||
void SceneSelectionWidget::Reset()
|
||||
{
|
||||
auto previousSel = _currentSelection;
|
||||
PopulateSelection();
|
||||
PopulateSceneSelection(_currentSelection._canvas);
|
||||
SetScene(previousSel);
|
||||
}
|
||||
|
||||
void SceneSelectionWidget::PopulateSelection()
|
||||
void SceneSelectionWidget::PopulateSceneSelection(obs_weak_canvas_t *canvas)
|
||||
{
|
||||
clear();
|
||||
if (_current || _previous) {
|
||||
const QStringList order =
|
||||
getOrderList(_current, _previous, _preview);
|
||||
AddSelectionGroup(this, order);
|
||||
_scenes->clear();
|
||||
if ((_current || _previous)) {
|
||||
const bool isMain = IsMainCanvas(canvas);
|
||||
const QStringList order = getOrderList(
|
||||
_current, _previous && isMain, _preview && isMain);
|
||||
AddSelectionGroup(_scenes, order);
|
||||
}
|
||||
_placeholderEndIdx = count();
|
||||
_placeholderEndIdx = _scenes->count();
|
||||
|
||||
if (_variables) {
|
||||
const QStringList variables = GetVariablesNameList();
|
||||
AddSelectionGroup(this, variables);
|
||||
AddSelectionGroup(_scenes, variables);
|
||||
}
|
||||
_variablesEndIdx = count();
|
||||
_variablesEndIdx = _scenes->count();
|
||||
|
||||
if (_sceneGroups) {
|
||||
const QStringList sceneGroups = getSceneGroupsList();
|
||||
AddSelectionGroup(this, sceneGroups);
|
||||
AddSelectionGroup(_scenes, sceneGroups);
|
||||
}
|
||||
_groupsEndIdx = count();
|
||||
_groupsEndIdx = _scenes->count();
|
||||
|
||||
const QStringList scenes = getScenesList();
|
||||
AddSelectionGroup(this, scenes);
|
||||
_scenesEndIdx = count();
|
||||
const QStringList scenes = getCanvasScenesList(canvas);
|
||||
AddSelectionGroup(_scenes, scenes);
|
||||
_scenesEndIdx = _scenes->count();
|
||||
|
||||
// Remove last separator
|
||||
removeItem(count() - 1);
|
||||
setCurrentIndex(-1);
|
||||
_scenes->removeItem(_scenes->count() - 1);
|
||||
_scenes->setCurrentIndex(-1);
|
||||
|
||||
_isPopulated = true;
|
||||
|
||||
Resize();
|
||||
}
|
||||
|
||||
SceneSelectionWidget::SceneSelectionWidget(QWidget *parent, bool variables,
|
||||
bool sceneGroups, bool previous,
|
||||
bool current, bool preview)
|
||||
: FilterComboBox(parent,
|
||||
obs_module_text("AdvSceneSwitcher.selectScene")),
|
||||
: QWidget(parent),
|
||||
_scenes(new FilterComboBox(
|
||||
this, obs_module_text("AdvSceneSwitcher.selectScene"))),
|
||||
_canvas(new CanvasSelection(this)),
|
||||
_current(current),
|
||||
_previous(previous),
|
||||
_preview(preview),
|
||||
_variables(variables),
|
||||
_sceneGroups(sceneGroups)
|
||||
{
|
||||
setDuplicatesEnabled(true);
|
||||
PopulateSelection();
|
||||
_scenes->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
_scenes->setDuplicatesEnabled(true);
|
||||
|
||||
QWidget::connect(this, SIGNAL(currentIndexChanged(int)), this,
|
||||
QWidget::connect(_scenes, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(SelectionChanged(int)));
|
||||
|
||||
// Scene groups
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(SceneGroupAdded(const QString &)), this,
|
||||
SLOT(ItemAdd(const QString &)));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(SceneGroupRemoved(const QString &)), this,
|
||||
SLOT(ItemRemove(const QString &)));
|
||||
QWidget::connect(
|
||||
GetSettingsWindow(),
|
||||
SIGNAL(SceneGroupRenamed(const QString &, const QString &)),
|
||||
this, SLOT(ItemRename(const QString &, const QString &)));
|
||||
QWidget::connect(_canvas, SIGNAL(CanvasChanged(const OBSWeakCanvas &)),
|
||||
this, SLOT(CanvasChangedSlot(const OBSWeakCanvas &)));
|
||||
QWidget::connect(_canvas, SIGNAL(CanvasChanged(const OBSWeakCanvas &)),
|
||||
this, SIGNAL(CanvasChanged(const OBSWeakCanvas &)));
|
||||
|
||||
// Variables
|
||||
QWidget::connect(VariableSignalManager::Instance(),
|
||||
@@ -335,19 +409,37 @@ SceneSelectionWidget::SceneSelectionWidget(QWidget *parent, bool variables,
|
||||
QWidget::connect(VariableSignalManager::Instance(),
|
||||
SIGNAL(Rename(const QString &, const QString &)), this,
|
||||
SLOT(ItemRename(const QString &, const QString &)));
|
||||
|
||||
auto layout = new QHBoxLayout();
|
||||
layout->addWidget(_canvas);
|
||||
layout->addWidget(_scenes);
|
||||
setLayout(layout);
|
||||
setContentsMargins(0, 0, 0, 0);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
if (GetCanvasCount() <= 1) {
|
||||
_canvas->hide();
|
||||
}
|
||||
|
||||
Resize();
|
||||
}
|
||||
|
||||
void SceneSelectionWidget::SetScene(const SceneSelection &s)
|
||||
{
|
||||
int idx = -1;
|
||||
|
||||
_canvas->SetCanvas(s._canvas);
|
||||
if (!_isPopulated) {
|
||||
PopulateSceneSelection(s._canvas);
|
||||
}
|
||||
|
||||
switch (s.GetType()) {
|
||||
case SceneSelection::Type::SCENE: {
|
||||
if (_scenesEndIdx == -1) {
|
||||
idx = -1;
|
||||
break;
|
||||
}
|
||||
idx = FindIdxInRagne(this, _groupsEndIdx, _scenesEndIdx,
|
||||
idx = FindIdxInRagne(_scenes, _groupsEndIdx, _scenesEndIdx,
|
||||
s.ToString());
|
||||
break;
|
||||
}
|
||||
@@ -356,7 +448,7 @@ void SceneSelectionWidget::SetScene(const SceneSelection &s)
|
||||
idx = -1;
|
||||
break;
|
||||
}
|
||||
idx = FindIdxInRagne(this, _variablesEndIdx, _groupsEndIdx,
|
||||
idx = FindIdxInRagne(_scenes, _variablesEndIdx, _groupsEndIdx,
|
||||
s.ToString());
|
||||
break;
|
||||
}
|
||||
@@ -367,7 +459,7 @@ void SceneSelectionWidget::SetScene(const SceneSelection &s)
|
||||
}
|
||||
|
||||
idx = FindIdxInRagne(
|
||||
this, _selectIdx, _placeholderEndIdx,
|
||||
_scenes, _selectIdx, _placeholderEndIdx,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.selectPreviousScene"));
|
||||
break;
|
||||
@@ -379,7 +471,7 @@ void SceneSelectionWidget::SetScene(const SceneSelection &s)
|
||||
}
|
||||
|
||||
idx = FindIdxInRagne(
|
||||
this, _selectIdx, _placeholderEndIdx,
|
||||
_scenes, _selectIdx, _placeholderEndIdx,
|
||||
obs_module_text("AdvSceneSwitcher.selectCurrentScene"));
|
||||
break;
|
||||
}
|
||||
@@ -390,7 +482,7 @@ void SceneSelectionWidget::SetScene(const SceneSelection &s)
|
||||
}
|
||||
|
||||
idx = FindIdxInRagne(
|
||||
this, _selectIdx, _placeholderEndIdx,
|
||||
_scenes, _selectIdx, _placeholderEndIdx,
|
||||
obs_module_text("AdvSceneSwitcher.selectPreviewScene"));
|
||||
break;
|
||||
}
|
||||
@@ -399,22 +491,31 @@ void SceneSelectionWidget::SetScene(const SceneSelection &s)
|
||||
idx = -1;
|
||||
break;
|
||||
}
|
||||
idx = FindIdxInRagne(this, _placeholderEndIdx, _variablesEndIdx,
|
||||
s.ToString());
|
||||
idx = FindIdxInRagne(_scenes, _placeholderEndIdx,
|
||||
_variablesEndIdx, s.ToString());
|
||||
break;
|
||||
default:
|
||||
idx = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
setCurrentIndex(idx);
|
||||
_scenes->setCurrentIndex(idx);
|
||||
_currentSelection = s;
|
||||
|
||||
Resize();
|
||||
}
|
||||
|
||||
void SceneSelectionWidget::LockToMainCanvas()
|
||||
{
|
||||
_forceMainCanvas = true;
|
||||
_canvas->hide();
|
||||
}
|
||||
|
||||
void SceneSelectionWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
FilterComboBox::showEvent(event);
|
||||
const QSignalBlocker b(this);
|
||||
QWidget::showEvent(event);
|
||||
const QSignalBlocker b1(_scenes);
|
||||
const QSignalBlocker b2(_canvas);
|
||||
Reset();
|
||||
}
|
||||
|
||||
@@ -442,9 +543,16 @@ void SceneSelectionWidget::SelectionChanged(int)
|
||||
emit SceneChanged(_currentSelection);
|
||||
}
|
||||
|
||||
void SceneSelectionWidget::CanvasChangedSlot(const OBSWeakCanvas &)
|
||||
{
|
||||
_currentSelection = CurrentSelection();
|
||||
Reset();
|
||||
}
|
||||
|
||||
void SceneSelectionWidget::ItemAdd(const QString &)
|
||||
{
|
||||
const QSignalBlocker b(this);
|
||||
const QSignalBlocker b1(_scenes);
|
||||
const QSignalBlocker b2(_canvas);
|
||||
Reset();
|
||||
}
|
||||
|
||||
@@ -456,7 +564,7 @@ bool SceneSelectionWidget::NameUsed(const QString &name)
|
||||
return true;
|
||||
}
|
||||
return _currentSelection._type == SceneSelection::Type::VARIABLE &&
|
||||
currentText() == name;
|
||||
_scenes->currentText() == name;
|
||||
}
|
||||
|
||||
void SceneSelectionWidget::ItemRemove(const QString &name)
|
||||
@@ -470,8 +578,19 @@ void SceneSelectionWidget::ItemRemove(const QString &name)
|
||||
|
||||
void SceneSelectionWidget::ItemRename(const QString &, const QString &)
|
||||
{
|
||||
const QSignalBlocker b(this);
|
||||
const QSignalBlocker b1(_scenes);
|
||||
const QSignalBlocker b2(_canvas);
|
||||
Reset();
|
||||
}
|
||||
|
||||
void SceneSelectionWidget::Resize()
|
||||
{
|
||||
_scenes->adjustSize();
|
||||
_scenes->updateGeometry();
|
||||
_canvas->adjustSize();
|
||||
_canvas->updateGeometry();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
#include "filter-combo-box.hpp"
|
||||
|
||||
#include <obs.hpp>
|
||||
#include "canvas-helpers.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -24,19 +22,22 @@ public:
|
||||
};
|
||||
|
||||
EXPORT Type GetType() const { return _type; }
|
||||
EXPORT void SetScene(const OBSWeakSource &scene);
|
||||
EXPORT OBSWeakSource GetScene(bool advance = true) const;
|
||||
EXPORT OBSWeakCanvas GetCanvas() const { return _canvas; };
|
||||
EXPORT std::string ToString(bool resolve = false) const;
|
||||
EXPORT void ResolveVariables();
|
||||
|
||||
private:
|
||||
OBSWeakSource _scene;
|
||||
OBSWeakCanvas _canvas;
|
||||
SceneGroup *_group = nullptr;
|
||||
std::weak_ptr<Variable> _variable;
|
||||
Type _type = Type::SCENE;
|
||||
friend class SceneSelectionWidget;
|
||||
};
|
||||
|
||||
class SceneSelectionWidget : public FilterComboBox {
|
||||
class SceneSelectionWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@@ -45,15 +46,18 @@ public:
|
||||
bool previous = false, bool current = false,
|
||||
bool preview = false);
|
||||
EXPORT void SetScene(const SceneSelection &);
|
||||
EXPORT void LockToMainCanvas();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
signals:
|
||||
void SceneChanged(const SceneSelection &);
|
||||
void CanvasChanged(const OBSWeakCanvas &);
|
||||
|
||||
private slots:
|
||||
EXPORT void SelectionChanged(int);
|
||||
EXPORT void CanvasChangedSlot(const OBSWeakCanvas &);
|
||||
EXPORT void ItemAdd(const QString &name);
|
||||
EXPORT void ItemRemove(const QString &name);
|
||||
EXPORT void ItemRename(const QString &oldName, const QString &newName);
|
||||
@@ -61,11 +65,15 @@ private slots:
|
||||
private:
|
||||
void Reset();
|
||||
SceneSelection CurrentSelection();
|
||||
void PopulateSelection();
|
||||
void PopulateSceneSelection(obs_weak_canvas_t *canvas);
|
||||
bool IsCurrentSceneSelected(const QString &name);
|
||||
bool IsPreviousSceneSelected(const QString &name);
|
||||
bool IsPreviewSceneSelected(const QString &name);
|
||||
bool NameUsed(const QString &name);
|
||||
void Resize();
|
||||
|
||||
FilterComboBox *_scenes;
|
||||
CanvasSelection *_canvas;
|
||||
|
||||
bool _current;
|
||||
bool _previous;
|
||||
@@ -73,7 +81,10 @@ private:
|
||||
bool _variables;
|
||||
bool _sceneGroups;
|
||||
|
||||
bool _forceMainCanvas = false;
|
||||
|
||||
SceneSelection _currentSelection;
|
||||
bool _isPopulated = false;
|
||||
|
||||
// Order of entries
|
||||
// 1. "select entry" entry
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "log-helper.hpp"
|
||||
#include "canvas-helpers.hpp"
|
||||
#include "source-helpers.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
#include <obs-websocket-api.h>
|
||||
|
||||
#undef blog
|
||||
#include "log-helper.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -123,7 +127,13 @@ void RestoreTransitionOverride(obs_source_t *scene, const TransitionData &td)
|
||||
obs_data_set_int(data, "transition_duration", td.duration);
|
||||
}
|
||||
|
||||
void SwitchScene(const SceneSwitchInfo &sceneSwitch, bool force)
|
||||
static bool modifiesTransitionSettings(const SceneSwitchInfo &ssi)
|
||||
{
|
||||
return ssi.duration != 0 || ssi.transition;
|
||||
}
|
||||
|
||||
void SwitchScene(const SceneSwitchInfo &sceneSwitch, bool force,
|
||||
obs_weak_canvas_t *canvas)
|
||||
{
|
||||
if (!sceneSwitch.scene) {
|
||||
vblog(LOG_INFO, "nothing to switch to");
|
||||
@@ -134,17 +144,40 @@ void SwitchScene(const SceneSwitchInfo &sceneSwitch, bool force)
|
||||
obs_weak_source_get_source(sceneSwitch.scene);
|
||||
OBSSourceAutoRelease currentSource = obs_frontend_get_current_scene();
|
||||
|
||||
if (source && (source != currentSource || force)) {
|
||||
TransitionData currentTransitionData;
|
||||
SetNextTransition(sceneSwitch, currentSource,
|
||||
currentTransitionData);
|
||||
if (!source || (source == currentSource && !force)) {
|
||||
return;
|
||||
}
|
||||
|
||||
TransitionData currentTransitionData;
|
||||
const bool modifiesTransition = modifiesTransitionSettings(sceneSwitch);
|
||||
|
||||
if (!canvas || IsMainCanvas(canvas)) { // Assume main canvas by default
|
||||
if (modifiesTransition) {
|
||||
SetNextTransition(sceneSwitch, currentSource,
|
||||
currentTransitionData);
|
||||
}
|
||||
obs_frontend_set_current_scene(source);
|
||||
if (ShouldModifyTransitionOverrides()) {
|
||||
if (modifiesTransition && ShouldModifyTransitionOverrides()) {
|
||||
RestoreTransitionOverride(source,
|
||||
currentTransitionData);
|
||||
}
|
||||
vblog(LOG_INFO, "switched main canvas scene");
|
||||
return;
|
||||
}
|
||||
|
||||
vblog(LOG_INFO, "switched scene");
|
||||
if (GetWeakCanvasName(canvas) == "Aitum Vertical") {
|
||||
// Can't set transitions so we ignore these options
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
obs_data_set_string(data, "vendorName",
|
||||
"aitum-vertical-canvas");
|
||||
obs_data_set_string(data, "requestType", "switch_scene");
|
||||
OBSDataAutoRelease requestData = obs_data_create();
|
||||
obs_data_set_string(requestData, "scene",
|
||||
obs_source_get_name(source));
|
||||
obs_data_set_obj(data, "requestData", requestData);
|
||||
obs_websocket_request_response_free(
|
||||
obs_websocket_call_request("CallVendorRequest", data));
|
||||
vblog(LOG_INFO, "switched Aitum Vertical canvas scene");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
class obs_weak_canvas_t;
|
||||
#endif
|
||||
|
||||
struct SceneSwitchInfo {
|
||||
OBSWeakSource scene;
|
||||
OBSWeakSource transition;
|
||||
@@ -18,7 +22,8 @@ struct TransitionData {
|
||||
int duration = 0;
|
||||
};
|
||||
|
||||
EXPORT void SwitchScene(const SceneSwitchInfo &, bool force = false);
|
||||
EXPORT void SwitchScene(const SceneSwitchInfo &, bool force = false,
|
||||
obs_weak_canvas_t *canvas = nullptr);
|
||||
void SwitchPreviewScene(const OBSWeakSource &scene);
|
||||
|
||||
EXPORT std::chrono::high_resolution_clock::time_point
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
#include "source-helpers.hpp"
|
||||
#include "scene-group.hpp"
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
#include "canvas-helpers.hpp"
|
||||
#endif
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
@@ -38,7 +42,8 @@ static void hasFilterEnum(obs_source_t *, obs_source_t *filter, void *ptr)
|
||||
|
||||
QStringList GetSourcesWithFilterNames()
|
||||
{
|
||||
auto enumSourcesWithFilters = [](void *param, obs_source_t *source) {
|
||||
static auto enumSourcesWithFilters = [](void *param,
|
||||
obs_source_t *source) {
|
||||
if (!source) {
|
||||
return true;
|
||||
}
|
||||
@@ -53,7 +58,17 @@ QStringList GetSourcesWithFilterNames()
|
||||
|
||||
QStringList list;
|
||||
obs_enum_sources(enumSourcesWithFilters, &list);
|
||||
|
||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||
obs_enum_scenes(enumSourcesWithFilters, &list);
|
||||
#else
|
||||
static const auto enumCanvases = [](void *listPtr,
|
||||
obs_canvas_t *canvas) -> bool {
|
||||
obs_canvas_enum_scenes(canvas, enumSourcesWithFilters, listPtr);
|
||||
return true;
|
||||
};
|
||||
obs_enum_canvases(enumCanvases, &list);
|
||||
#endif
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,14 +46,17 @@ void StringList::ResolveVariables()
|
||||
}
|
||||
}
|
||||
|
||||
StringListEdit::StringListEdit(QWidget *parent, const QString &addString,
|
||||
const QString &addStringDescription,
|
||||
int maxStringSize, bool allowEmtpy)
|
||||
StringListEdit::StringListEdit(
|
||||
QWidget *parent, const QString &addString,
|
||||
const QString &addStringDescription, int maxStringSize,
|
||||
const std::function<bool(const std::string &)> &filter,
|
||||
const std::function<void(std::string &input)> &preprocess)
|
||||
: ListEditor(parent),
|
||||
_addString(addString),
|
||||
_addStringDescription(addStringDescription),
|
||||
_maxStringSize(maxStringSize),
|
||||
_allowEmpty(allowEmtpy)
|
||||
_filterCallback(filter),
|
||||
_preprocessCallback(preprocess)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -77,15 +80,19 @@ void StringListEdit::SetMaxStringSize(int size)
|
||||
|
||||
void StringListEdit::Add()
|
||||
{
|
||||
std::string name;
|
||||
std::string entry;
|
||||
bool accepted = NameDialog::AskForName(this, _addString,
|
||||
_addStringDescription, name, "",
|
||||
_addStringDescription, entry, "",
|
||||
_maxStringSize, false);
|
||||
|
||||
if (!accepted || (!_allowEmpty && name.empty())) {
|
||||
if (!accepted) {
|
||||
return;
|
||||
}
|
||||
StringVariable string = name;
|
||||
|
||||
_preprocessCallback(entry);
|
||||
if (_filterCallback(entry)) {
|
||||
return;
|
||||
}
|
||||
StringVariable string = entry;
|
||||
QVariant v = QVariant::fromValue(string);
|
||||
QListWidgetItem *item = new QListWidgetItem(
|
||||
QString::fromStdString(string.UnresolvedValue()), _list);
|
||||
@@ -145,17 +152,21 @@ void StringListEdit::Down()
|
||||
|
||||
void StringListEdit::Clicked(QListWidgetItem *item)
|
||||
{
|
||||
std::string name;
|
||||
std::string entry;
|
||||
bool accepted = NameDialog::AskForName(this, _addString,
|
||||
_addStringDescription, name,
|
||||
_addStringDescription, entry,
|
||||
item->text(), _maxStringSize,
|
||||
false);
|
||||
|
||||
if (!accepted || (!_allowEmpty && name.empty())) {
|
||||
if (!accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
StringVariable string = name;
|
||||
_preprocessCallback(entry);
|
||||
if (_filterCallback(entry)) {
|
||||
return;
|
||||
}
|
||||
|
||||
StringVariable string = entry;
|
||||
QVariant v = QVariant::fromValue(string);
|
||||
item->setText(QString::fromStdString(string.UnresolvedValue()));
|
||||
item->setData(Qt::UserRole, string);
|
||||
|
||||
@@ -19,14 +19,20 @@ public:
|
||||
friend class StringListEdit;
|
||||
};
|
||||
|
||||
class ADVSS_EXPORT StringListEdit final : public ListEditor {
|
||||
class ADVSS_EXPORT StringListEdit : public ListEditor {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
StringListEdit(QWidget *parent, const QString &addString = "",
|
||||
const QString &addStringDescription = "",
|
||||
int maxStringSize = 170, bool allowEmtpy = false);
|
||||
StringListEdit(
|
||||
QWidget *parent, const QString &addString = "",
|
||||
const QString &addStringDescription = "",
|
||||
int maxStringSize = 170,
|
||||
const std::function<bool(const std::string &)> &filter =
|
||||
[](const std::string &) { return false; },
|
||||
const std::function<void(std::string &input)> &preprocess =
|
||||
[](std::string &) {});
|
||||
void SetStringList(const StringList &);
|
||||
StringList GetStringList() const { return _stringList; }
|
||||
void SetMaxStringSize(int);
|
||||
|
||||
private slots:
|
||||
@@ -44,7 +50,8 @@ private:
|
||||
QString _addString;
|
||||
QString _addStringDescription;
|
||||
int _maxStringSize = 170;
|
||||
bool _allowEmpty = false;
|
||||
std::function<bool(const std::string &)> _filterCallback;
|
||||
std::function<void(std::string &)> _preprocessCallback;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include "temp-variable.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-action-macro.hpp"
|
||||
#include "macro-edit.hpp"
|
||||
#include "macro-segment.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
@@ -154,20 +155,161 @@ int TempVariableRef::GetIdx() const
|
||||
return segment->GetIndex();
|
||||
}
|
||||
|
||||
void TempVariableRef::Save(obs_data_t *obj, const char *name) const
|
||||
template<typename T>
|
||||
static bool
|
||||
segmentIsPartOfSegmentList(const MacroSegment *segment,
|
||||
const std::deque<std::shared_ptr<T>> &segmentList)
|
||||
{
|
||||
for (const auto &segmentFromList : segmentList) {
|
||||
if (segment == segmentFromList.get()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool segmentIsPartOfMacro(const MacroSegment *segment,
|
||||
const Macro *macro)
|
||||
{
|
||||
if (!macro) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return segmentIsPartOfSegmentList(segment, macro->Conditions()) ||
|
||||
segmentIsPartOfSegmentList(segment, macro->Actions()) ||
|
||||
segmentIsPartOfSegmentList(segment, macro->ElseActions());
|
||||
}
|
||||
|
||||
static bool isMatchingNestedMacroAction(MacroAction *action, const Macro *macro)
|
||||
{
|
||||
const auto nestedMacroAction = dynamic_cast<MacroActionMacro *>(action);
|
||||
if (!nestedMacroAction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return nestedMacroAction->_nestedMacro.get() == macro;
|
||||
}
|
||||
|
||||
static void appendNestedMacros(std::deque<std::shared_ptr<Macro>> ¯os,
|
||||
Macro *macro)
|
||||
{
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &action : macro->Actions()) {
|
||||
const auto nestedMacroAction =
|
||||
dynamic_cast<MacroActionMacro *>(action.get());
|
||||
if (nestedMacroAction) {
|
||||
macros.push_back(nestedMacroAction->_nestedMacro);
|
||||
}
|
||||
}
|
||||
for (const auto &action : macro->ElseActions()) {
|
||||
const auto nestedMacroAction =
|
||||
dynamic_cast<MacroActionMacro *>(action.get());
|
||||
if (nestedMacroAction) {
|
||||
macros.push_back(nestedMacroAction->_nestedMacro);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Macro *getParentMacro(const Macro *targetMacro,
|
||||
const std::vector<Macro *> ¯os)
|
||||
{
|
||||
if (!targetMacro) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (macros.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<Macro *> newMacros;
|
||||
for (const auto ¯o : macros) {
|
||||
for (const auto &action : macro->Actions()) {
|
||||
const auto nestedMacroAction =
|
||||
dynamic_cast<MacroActionMacro *>(action.get());
|
||||
if (!nestedMacroAction) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nestedMacroAction->_nestedMacro.get() ==
|
||||
targetMacro) {
|
||||
return nestedMacroAction->GetMacro();
|
||||
}
|
||||
|
||||
newMacros.emplace_back(
|
||||
nestedMacroAction->_nestedMacro.get());
|
||||
}
|
||||
for (const auto &action : macro->ElseActions()) {
|
||||
const auto nestedMacroAction =
|
||||
dynamic_cast<MacroActionMacro *>(action.get());
|
||||
if (!nestedMacroAction) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nestedMacroAction->_nestedMacro.get() ==
|
||||
targetMacro) {
|
||||
return nestedMacroAction->GetMacro();
|
||||
}
|
||||
|
||||
newMacros.emplace_back(
|
||||
nestedMacroAction->_nestedMacro.get());
|
||||
}
|
||||
}
|
||||
|
||||
return getParentMacro(targetMacro, newMacros);
|
||||
}
|
||||
|
||||
static Macro *getParentMacro(const Macro *macro)
|
||||
{
|
||||
std::vector<Macro *> macros;
|
||||
for (const auto ¯o : GetMacros()) {
|
||||
macros.emplace_back(macro.get());
|
||||
}
|
||||
return getParentMacro(macro, macros);
|
||||
}
|
||||
|
||||
static int getDepth(MacroSegment *segment, const Macro *macro, int depth = 0)
|
||||
{
|
||||
if (!macro) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (segmentIsPartOfMacro(segment, macro)) {
|
||||
return depth;
|
||||
}
|
||||
|
||||
return getDepth(segment, getParentMacro(macro), depth + 1);
|
||||
}
|
||||
|
||||
void TempVariableRef::Save(obs_data_t *obj, Macro *macro,
|
||||
const char *name) const
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
auto type = GetType();
|
||||
obs_data_set_int(data, "type", static_cast<int>(type));
|
||||
obs_data_set_int(data, "idx", GetIdx());
|
||||
obs_data_set_string(data, "id", _id.c_str());
|
||||
const auto segment = _segment.lock();
|
||||
if (segment) {
|
||||
obs_data_set_int(data, "depth", getDepth(segment.get(), macro));
|
||||
}
|
||||
obs_data_set_int(data, "version", 1);
|
||||
obs_data_set_obj(obj, name, data);
|
||||
}
|
||||
|
||||
void TempVariableRef::Load(obs_data_t *obj, Macro *macro, const char *name)
|
||||
void TempVariableRef::Load(obs_data_t *obj, Macro *macroPtr, const char *name)
|
||||
{
|
||||
if (!macro) {
|
||||
std::weak_ptr<Macro> macro;
|
||||
for (const auto ¯oShared : GetMacros()) {
|
||||
if (macroShared.get() == macroPtr) {
|
||||
macro = macroShared;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (macro.expired()) {
|
||||
_segment.reset();
|
||||
return;
|
||||
}
|
||||
@@ -176,6 +318,7 @@ void TempVariableRef::Load(obs_data_t *obj, Macro *macro, const char *name)
|
||||
_id = obs_data_get_string(data, "id");
|
||||
const auto type =
|
||||
static_cast<SegmentType>(obs_data_get_int(data, "type"));
|
||||
_depth = obs_data_get_int(data, "depth");
|
||||
|
||||
// Backwards compatibility checks
|
||||
if (obs_data_get_int(data, "version") < 1) {
|
||||
@@ -189,8 +332,19 @@ void TempVariableRef::Load(obs_data_t *obj, Macro *macro, const char *name)
|
||||
});
|
||||
}
|
||||
|
||||
void TempVariableRef::PostLoad(int idx, SegmentType type, Macro *macro)
|
||||
void TempVariableRef::PostLoad(int idx, SegmentType type,
|
||||
const std::weak_ptr<Macro> &weakMacro)
|
||||
{
|
||||
auto childMacro = weakMacro.lock();
|
||||
if (!childMacro) {
|
||||
return;
|
||||
}
|
||||
|
||||
Macro *macro = nullptr;
|
||||
for (int i = 0; i < _depth; i++) {
|
||||
macro = getParentMacro(childMacro.get());
|
||||
}
|
||||
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
@@ -247,20 +401,35 @@ bool TempVariableRef::operator==(const TempVariableRef &other) const
|
||||
return segment == other._segment.lock();
|
||||
}
|
||||
|
||||
static MacroEdit *findMacroEditParent(QWidget *widget)
|
||||
{
|
||||
if (!widget) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto macroEdit = qobject_cast<MacroEdit *>(widget);
|
||||
if (macroEdit) {
|
||||
return macroEdit;
|
||||
}
|
||||
|
||||
return findMacroEditParent(widget->parentWidget());
|
||||
}
|
||||
|
||||
TempVariableSelection::TempVariableSelection(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
_selection(new FilterComboBox(
|
||||
this, obs_module_text("AdvSceneSwitcher.tempVar.select"))),
|
||||
_info(new AutoUpdateTooltipLabel(this, [this]() {
|
||||
return SetupInfoLabel();
|
||||
}))
|
||||
_info(new AutoUpdateHelpIcon(this,
|
||||
[this]() { return SetupInfoLabel(); }))
|
||||
|
||||
{
|
||||
QString path = GetThemeTypeName() == "Light"
|
||||
? ":/res/images/help.svg"
|
||||
: ":/res/images/help_light.svg";
|
||||
QIcon icon(path);
|
||||
QPixmap pixmap = icon.pixmap(QSize(16, 16));
|
||||
_info->setPixmap(pixmap);
|
||||
MacroEdit *edit = findMacroEditParent(parent);
|
||||
assert(edit);
|
||||
_macroEdits.push_back(edit);
|
||||
while ((edit = findMacroEditParent(edit->parentWidget()))) {
|
||||
_macroEdits.push_back(edit);
|
||||
}
|
||||
|
||||
_info->hide();
|
||||
|
||||
_selection->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
@@ -272,10 +441,11 @@ TempVariableSelection::TempVariableSelection(QWidget *parent)
|
||||
SLOT(SelectionIdxChanged(int)));
|
||||
QWidget::connect(_selection, SIGNAL(highlighted(int)), this,
|
||||
SLOT(HighlightChanged(int)));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroSegmentOrderChanged()), this,
|
||||
SLOT(MacroSegmentsChanged()));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
for (const auto macroEdit : _macroEdits) {
|
||||
QWidget::connect(macroEdit, SIGNAL(MacroSegmentOrderChanged()),
|
||||
this, SLOT(MacroSegmentsChanged()));
|
||||
}
|
||||
QWidget::connect(TempVarSignalManager::Instance(),
|
||||
SIGNAL(SegmentTempVarsChanged(MacroSegment *)), this,
|
||||
SLOT(SegmentTempVarsChanged(MacroSegment *)));
|
||||
|
||||
@@ -333,20 +503,57 @@ void TempVariableSelection::HighlightChanged(int idx)
|
||||
HighlightSelection(var);
|
||||
}
|
||||
|
||||
static MacroSegment *
|
||||
getMacroSegmentFromNestedMacro(Macro *nestedMacro,
|
||||
const std::vector<MacroEdit *> ¯oEdits)
|
||||
{
|
||||
for (const auto ¯oEdit : macroEdits) {
|
||||
const auto macro = macroEdit->GetMacro();
|
||||
if (!macro) {
|
||||
continue;
|
||||
}
|
||||
for (const auto &action : macro->Actions()) {
|
||||
if (isMatchingNestedMacroAction(action.get(),
|
||||
nestedMacro)) {
|
||||
return action.get();
|
||||
}
|
||||
}
|
||||
for (const auto &action : macro->ElseActions()) {
|
||||
if (isMatchingNestedMacroAction(action.get(),
|
||||
nestedMacro)) {
|
||||
return action.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TempVariableSelection::PopulateSelection()
|
||||
{
|
||||
auto advssWindow =
|
||||
qobject_cast<AdvSceneSwitcher *>(GetSettingsWindow());
|
||||
if (!advssWindow) {
|
||||
std::vector<TempVariable> vars;
|
||||
const auto appendVars = [&vars](const Macro *macro,
|
||||
const MacroSegment *segment) {
|
||||
const auto newVars = macro->GetTempVars(segment);
|
||||
vars.insert(vars.end(), newVars.begin(), newVars.end());
|
||||
};
|
||||
|
||||
const auto segment = GetSegment();
|
||||
if (!segment) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto macro = advssWindow->GetSelectedMacro();
|
||||
if (!macro) {
|
||||
auto macro = segment->GetMacro();
|
||||
appendVars(macro, segment);
|
||||
|
||||
while ((macro = getParentMacro(macro))) {
|
||||
appendVars(macro,
|
||||
getMacroSegmentFromNestedMacro(macro, _macroEdits));
|
||||
}
|
||||
|
||||
if (vars.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto vars = macro->GetTempVars(GetSegment());
|
||||
for (const auto &var : vars) {
|
||||
QVariant variant;
|
||||
variant.setValue(var.GetRef());
|
||||
@@ -367,26 +574,49 @@ void TempVariableSelection::PopulateSelection()
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
static MacroEdit *
|
||||
getMacroEditFromMacro(const std::vector<MacroEdit *> ¯oEdits, Macro *macro)
|
||||
{
|
||||
for (const auto edit : macroEdits) {
|
||||
if (macro == edit->GetMacro().get()) {
|
||||
return edit;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TempVariableSelection::HighlightSelection(const TempVariableRef &var)
|
||||
{
|
||||
auto advssWindow =
|
||||
qobject_cast<AdvSceneSwitcher *>(GetSettingsWindow());
|
||||
if (!advssWindow) {
|
||||
const auto segment = var._segment.lock();
|
||||
if (!segment) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto macro = segment->GetMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
const MacroEdit *macroEdit = getMacroEditFromMacro(_macroEdits, macro);
|
||||
if (!macroEdit) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto color = GetThemeTypeName() == "Dark" ? Qt::white : Qt::blue;
|
||||
|
||||
auto type = var.GetType();
|
||||
switch (type) {
|
||||
case TempVariableRef::SegmentType::NONE:
|
||||
return;
|
||||
case TempVariableRef::SegmentType::CONDITION:
|
||||
advssWindow->HighlightCondition(var.GetIdx(), Qt::white);
|
||||
macroEdit->HighlightCondition(var.GetIdx(), color);
|
||||
return;
|
||||
case TempVariableRef::SegmentType::ACTION:
|
||||
advssWindow->HighlightAction(var.GetIdx(), Qt::white);
|
||||
macroEdit->HighlightAction(var.GetIdx(), color);
|
||||
return;
|
||||
case TempVariableRef::SegmentType::ELSEACTION:
|
||||
advssWindow->HighlightElseAction(var.GetIdx(), Qt::white);
|
||||
macroEdit->HighlightElseAction(var.GetIdx(), color);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
@@ -397,20 +627,20 @@ QString TempVariableSelection::SetupInfoLabel()
|
||||
{
|
||||
auto currentSelection = _selection->itemData(_selection->currentIndex())
|
||||
.value<TempVariableRef>();
|
||||
auto advssWindow =
|
||||
qobject_cast<AdvSceneSwitcher *>(GetSettingsWindow());
|
||||
if (!advssWindow) {
|
||||
const auto segment = currentSelection._segment.lock();
|
||||
if (!segment) {
|
||||
_info->setToolTip("");
|
||||
_info->hide();
|
||||
return "";
|
||||
}
|
||||
auto macro = advssWindow->GetSelectedMacro();
|
||||
|
||||
auto macro = segment->GetMacro();
|
||||
if (!macro) {
|
||||
_info->setToolTip("");
|
||||
_info->hide();
|
||||
return "";
|
||||
}
|
||||
auto var = currentSelection.GetTempVariable(macro.get());
|
||||
auto var = currentSelection.GetTempVariable(macro);
|
||||
if (!var) {
|
||||
_info->setToolTip("");
|
||||
_info->hide();
|
||||
@@ -451,15 +681,20 @@ MacroSegment *TempVariableSelection::GetSegment() const
|
||||
return segmentWidget->Data().get();
|
||||
}
|
||||
|
||||
TempVarSignalManager::TempVarSignalManager() : QObject() {}
|
||||
|
||||
TempVarSignalManager *TempVarSignalManager::Instance()
|
||||
{
|
||||
static TempVarSignalManager manager;
|
||||
return &manager;
|
||||
}
|
||||
|
||||
void NotifyUIAboutTempVarChange(MacroSegment *segment)
|
||||
{
|
||||
obs_queue_task(
|
||||
OBS_TASK_UI,
|
||||
[](void *segment) {
|
||||
if (!SettingsWindowIsOpened()) {
|
||||
return;
|
||||
}
|
||||
AdvSceneSwitcher::window->SegmentTempVarsChanged(
|
||||
TempVarSignalManager::Instance()->SegmentTempVarsChanged(
|
||||
(MacroSegment *)segment);
|
||||
},
|
||||
segment, false);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
namespace advss {
|
||||
|
||||
class Macro;
|
||||
class MacroEdit;
|
||||
class MacroSegment;
|
||||
class TempVariableRef;
|
||||
class TempVariableSelection;
|
||||
@@ -60,7 +61,8 @@ private:
|
||||
|
||||
class TempVariableRef {
|
||||
public:
|
||||
EXPORT void Save(obs_data_t *, const char *name = "tempVar") const;
|
||||
EXPORT void Save(obs_data_t *, Macro *,
|
||||
const char *name = "tempVar") const;
|
||||
EXPORT void Load(obs_data_t *, Macro *, const char *name = "tempVar");
|
||||
EXPORT std::optional<const TempVariable> GetTempVariable(Macro *) const;
|
||||
EXPORT bool operator==(const TempVariableRef &other) const;
|
||||
@@ -70,10 +72,12 @@ private:
|
||||
enum class SegmentType { NONE, CONDITION, ACTION, ELSEACTION };
|
||||
SegmentType GetType() const;
|
||||
int GetIdx() const;
|
||||
void PostLoad(int idx, SegmentType, Macro *);
|
||||
void PostLoad(int idx, SegmentType, const std::weak_ptr<Macro> &);
|
||||
|
||||
std::string _id = "";
|
||||
std::weak_ptr<MacroSegment> _segment;
|
||||
int _depth = 0;
|
||||
|
||||
friend TempVariable;
|
||||
friend TempVariableSelection;
|
||||
};
|
||||
@@ -101,7 +105,20 @@ private:
|
||||
MacroSegment *GetSegment() const;
|
||||
|
||||
FilterComboBox *_selection;
|
||||
AutoUpdateTooltipLabel *_info;
|
||||
AutoUpdateHelpIcon *_info;
|
||||
std::vector<MacroEdit *> _macroEdits;
|
||||
};
|
||||
|
||||
class TempVarSignalManager : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static TempVarSignalManager *Instance();
|
||||
|
||||
signals:
|
||||
void SegmentTempVarsChanged(MacroSegment *);
|
||||
|
||||
private:
|
||||
TempVarSignalManager();
|
||||
};
|
||||
|
||||
void NotifyUIAboutTempVarChange(MacroSegment *);
|
||||
|
||||
@@ -127,7 +127,7 @@ bool MacroActionFilter::Save(obs_data_t *obj) const
|
||||
static_cast<int>(_settingsInputMethod));
|
||||
_setting.Save(obj);
|
||||
_manualSettingValue.Save(obj, "manualSettingValue");
|
||||
_tempVar.Save(obj);
|
||||
_tempVar.Save(obj, GetMacro());
|
||||
_settingsString.Save(obj, "settings");
|
||||
_button.Save(obj);
|
||||
obs_data_set_int(obj, "version", 1);
|
||||
|
||||
@@ -169,7 +169,8 @@ MacroActionHttpEdit::MacroActionHttpEdit(
|
||||
_headerListLayout(new QVBoxLayout()),
|
||||
_headerList(new StringListEdit(
|
||||
this, obs_module_text("AdvSceneSwitcher.action.http.headers"),
|
||||
obs_module_text("AdvSceneSwitcher.action.http.addHeader"))),
|
||||
obs_module_text("AdvSceneSwitcher.action.http.addHeader"),
|
||||
170, [](const std::string &input) { return input.empty(); })),
|
||||
_timeout(new DurationSelection(this, false))
|
||||
{
|
||||
populateMethodSelection(_methods);
|
||||
|
||||
@@ -237,7 +237,24 @@ MacroActionMediaEdit::MacroActionMediaEdit(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.media.seek.percentage.label"))),
|
||||
_sources(new SourceSelectionWidget(this, getMediaSourcesList, true)),
|
||||
_sceneItems(new SceneItemSelectionWidget(parent, false)),
|
||||
_sceneItems(new SceneItemSelectionWidget(
|
||||
parent,
|
||||
{
|
||||
SceneItemSelection::Type::SOURCE_NAME,
|
||||
SceneItemSelection::Type::VARIABLE_NAME,
|
||||
SceneItemSelection::Type::SOURCE_NAME_PATTERN,
|
||||
SceneItemSelection::Type::SOURCE_GROUP,
|
||||
SceneItemSelection::Type::SOURCE_TYPE,
|
||||
SceneItemSelection::Type::INDEX,
|
||||
SceneItemSelection::Type::INDEX_RANGE,
|
||||
SceneItemSelection::Type::ALL,
|
||||
},
|
||||
// All instances of a media source will be in the same state.
|
||||
// So, for example, restarting one instance of a source will
|
||||
// automatically restart all other instances of that source,
|
||||
// too.
|
||||
// Thus, we hide the name clash resolution options
|
||||
SceneItemSelectionWidget::NameClashMode::HIDE)),
|
||||
_scenes(new SceneSelectionWidget(this, true, false, true, true, true))
|
||||
{
|
||||
populateActionSelection(_actions);
|
||||
|
||||
@@ -34,6 +34,12 @@ const static std::map<MacroActionOBSSettings::Action, std::string> actionTypes =
|
||||
"AdvSceneSwitcher.action.obsSetting.action.setOutputCanvasX"},
|
||||
{MacroActionOBSSettings::Action::OUTPUT_Y_VALUE,
|
||||
"AdvSceneSwitcher.action.obsSetting.action.setOutputCanvasY"},
|
||||
{MacroActionOBSSettings::Action::ENABLE_PREVIEW,
|
||||
"AdvSceneSwitcher.action.obsSetting.action.enablePreview"},
|
||||
{MacroActionOBSSettings::Action::DISABLE_PREVIEW,
|
||||
"AdvSceneSwitcher.action.obsSetting.action.disablePreview"},
|
||||
{MacroActionOBSSettings::Action::TOGGLE_PREVIEW,
|
||||
"AdvSceneSwitcher.action.obsSetting.action.togglePreview"},
|
||||
};
|
||||
|
||||
template<typename Func, typename... Args>
|
||||
@@ -62,6 +68,17 @@ static auto getConfigValueHelper(Func func, Func defaultFunc, Args... args)
|
||||
return std::optional<Ret>{};
|
||||
}
|
||||
|
||||
static void setPreviewEnabled(bool enabled)
|
||||
{
|
||||
static const auto enable = [](void *) {
|
||||
obs_frontend_set_preview_enabled(true);
|
||||
};
|
||||
static const auto disable = [](void *) {
|
||||
obs_frontend_set_preview_enabled(false);
|
||||
};
|
||||
obs_queue_task(OBS_TASK_UI, enabled ? enable : disable, nullptr, false);
|
||||
}
|
||||
|
||||
bool MacroActionOBSSettings::PerformAction()
|
||||
{
|
||||
switch (_action) {
|
||||
@@ -110,6 +127,15 @@ bool MacroActionOBSSettings::PerformAction()
|
||||
static_cast<int>(_canvasSizeValue));
|
||||
obs_frontend_reset_video();
|
||||
break;
|
||||
case Action::ENABLE_PREVIEW:
|
||||
setPreviewEnabled(true);
|
||||
break;
|
||||
case Action::DISABLE_PREVIEW:
|
||||
setPreviewEnabled(false);
|
||||
break;
|
||||
case Action::TOGGLE_PREVIEW:
|
||||
setPreviewEnabled(!obs_frontend_preview_enabled());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -347,18 +373,6 @@ void MacroActionOBSSettingsEdit::SetWidgetVisibility()
|
||||
return;
|
||||
}
|
||||
|
||||
const bool isFPSSelection =
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::FPS_TYPE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::FPS_COMMON_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::FPS_INT_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::FPS_DEN_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::FPS_NUM_VALUE;
|
||||
|
||||
_fpsType->setVisible(_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::FPS_TYPE);
|
||||
_fpsIntValue->setVisible(
|
||||
@@ -371,9 +385,36 @@ void MacroActionOBSSettingsEdit::SetWidgetVisibility()
|
||||
_fpsStringValue->setVisible(
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::FPS_COMMON_VALUE);
|
||||
_canvasSizeValue->setVisible(!isFPSSelection);
|
||||
_getCurrentValue->setVisible(_entryData->_action !=
|
||||
MacroActionOBSSettings::Action::FPS_TYPE);
|
||||
|
||||
const bool needsSizeSelection =
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::BASE_CANVAS_X_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::BASE_CANVAS_Y_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::OUTPUT_X_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::OUTPUT_Y_VALUE;
|
||||
_canvasSizeValue->setVisible(needsSizeSelection);
|
||||
|
||||
const bool canGetSettingsValue =
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::FPS_COMMON_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::FPS_INT_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::FPS_NUM_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::FPS_DEN_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::BASE_CANVAS_X_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::BASE_CANVAS_Y_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::OUTPUT_X_VALUE ||
|
||||
_entryData->_action ==
|
||||
MacroActionOBSSettings::Action::OUTPUT_Y_VALUE;
|
||||
_getCurrentValue->setVisible(canGetSettingsValue);
|
||||
}
|
||||
|
||||
void MacroActionOBSSettingsEdit::ActionChanged(int idx)
|
||||
|
||||
@@ -31,6 +31,9 @@ public:
|
||||
BASE_CANVAS_Y_VALUE,
|
||||
OUTPUT_X_VALUE,
|
||||
OUTPUT_Y_VALUE,
|
||||
ENABLE_PREVIEW,
|
||||
DISABLE_PREVIEW,
|
||||
TOGGLE_PREVIEW,
|
||||
};
|
||||
Action _action = Action::FPS_COMMON_VALUE;
|
||||
enum class FPSType {
|
||||
|
||||
@@ -21,17 +21,6 @@ bool MacroActionPluginState::_registered = MacroActionFactory::Register(
|
||||
{MacroActionPluginState::Create, MacroActionPluginStateEdit::Create,
|
||||
"AdvSceneSwitcher.action.pluginState"});
|
||||
|
||||
const static std::map<PluginStateAction, std::string> actionTypes = {
|
||||
{PluginStateAction::STOP,
|
||||
"AdvSceneSwitcher.action.pluginState.type.stop"},
|
||||
{PluginStateAction::NO_MATCH_BEHAVIOUR,
|
||||
"AdvSceneSwitcher.action.pluginState.type.noMatch"},
|
||||
{PluginStateAction::IMPORT_SETTINGS,
|
||||
"AdvSceneSwitcher.action.pluginState.type.import"},
|
||||
{PluginStateAction::TERMINATE,
|
||||
"AdvSceneSwitcher.action.pluginState.type.terminate"},
|
||||
};
|
||||
|
||||
const static std::map<NoMatchBehavior, std::string> noMatchValues = {
|
||||
{NoMatchBehavior::NO_SWITCH,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.dontSwitch"},
|
||||
@@ -67,7 +56,7 @@ static void setNoMatchBehaviour(int value, OBSWeakSource &scene)
|
||||
}
|
||||
}
|
||||
|
||||
static void closeOBSWindow()
|
||||
static void closeOBSWindow(void *)
|
||||
{
|
||||
blog(LOG_WARNING, "closing OBS window now!");
|
||||
auto obsWindow =
|
||||
@@ -80,7 +69,7 @@ static void closeOBSWindow()
|
||||
}
|
||||
}
|
||||
|
||||
static void terminateOBS(void *)
|
||||
static void askTerminateOBS(void *)
|
||||
{
|
||||
static std::mutex mtx;
|
||||
static std::mutex waitMutex;
|
||||
@@ -118,10 +107,10 @@ static void terminateOBS(void *)
|
||||
if (abortTerminate) {
|
||||
blog(LOG_INFO, "OBS shutdown was aborted");
|
||||
} else {
|
||||
closeOBSWindow();
|
||||
closeOBSWindow(nullptr);
|
||||
}
|
||||
} else {
|
||||
closeOBSWindow();
|
||||
closeOBSWindow(nullptr);
|
||||
}
|
||||
});
|
||||
thread.detach();
|
||||
@@ -142,25 +131,36 @@ static void terminateOBS(void *)
|
||||
bool MacroActionPluginState::PerformAction()
|
||||
{
|
||||
switch (_action) {
|
||||
case PluginStateAction::STOP:
|
||||
case Action::STOP:
|
||||
stopPlugin();
|
||||
break;
|
||||
case PluginStateAction::NO_MATCH_BEHAVIOUR:
|
||||
case Action::NO_MATCH_BEHAVIOUR:
|
||||
setNoMatchBehaviour(_value, _scene);
|
||||
break;
|
||||
case PluginStateAction::IMPORT_SETTINGS:
|
||||
case Action::IMPORT_SETTINGS:
|
||||
importSettings(_settingsPath);
|
||||
// There is no point in continuing
|
||||
// The settings will be invalid
|
||||
return false;
|
||||
case PluginStateAction::TERMINATE: {
|
||||
std::thread thread([]() {
|
||||
obs_queue_task(OBS_TASK_UI, terminateOBS, nullptr,
|
||||
false);
|
||||
case Action::TERMINATE: {
|
||||
std::thread thread([this]() {
|
||||
obs_queue_task(OBS_TASK_UI,
|
||||
this->_confirmShutdown ? askTerminateOBS
|
||||
: closeOBSWindow,
|
||||
nullptr, false);
|
||||
});
|
||||
thread.detach();
|
||||
break;
|
||||
}
|
||||
case Action::ENABLE_MACRO_HIGHLIGHTING:
|
||||
SetMacroHighlightingEnabled(true);
|
||||
break;
|
||||
case Action::DISABLE_MACRO_HIGHLIGHTING:
|
||||
SetMacroHighlightingEnabled(false);
|
||||
break;
|
||||
case Action::TOGGLE_MACRO_HIGHLIGHTING:
|
||||
SetMacroHighlightingEnabled(!IsMacroHighlightingEnabled());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -170,19 +170,28 @@ bool MacroActionPluginState::PerformAction()
|
||||
void MacroActionPluginState::LogAction() const
|
||||
{
|
||||
switch (_action) {
|
||||
case PluginStateAction::STOP:
|
||||
case Action::STOP:
|
||||
blog(LOG_INFO, "stop() called by macro");
|
||||
break;
|
||||
case PluginStateAction::NO_MATCH_BEHAVIOUR:
|
||||
case Action::NO_MATCH_BEHAVIOUR:
|
||||
ablog(LOG_INFO, "setting no match to %d", _value);
|
||||
break;
|
||||
case PluginStateAction::IMPORT_SETTINGS:
|
||||
case Action::IMPORT_SETTINGS:
|
||||
ablog(LOG_INFO, "importing settings from %s",
|
||||
_settingsPath.c_str());
|
||||
break;
|
||||
case PluginStateAction::TERMINATE:
|
||||
case Action::TERMINATE:
|
||||
ablog(LOG_INFO, "sending terminate signal to OBS in 10s");
|
||||
break;
|
||||
case Action::ENABLE_MACRO_HIGHLIGHTING:
|
||||
ablog(LOG_INFO, "enable macro highlighting");
|
||||
break;
|
||||
case Action::DISABLE_MACRO_HIGHLIGHTING:
|
||||
ablog(LOG_INFO, "disable macro highlighting");
|
||||
break;
|
||||
case Action::TOGGLE_MACRO_HIGHLIGHTING:
|
||||
ablog(LOG_INFO, "toggle macro highlighting");
|
||||
break;
|
||||
default:
|
||||
blog(LOG_WARNING, "ignored unknown pluginState action %d",
|
||||
static_cast<int>(_action));
|
||||
@@ -197,18 +206,22 @@ bool MacroActionPluginState::Save(obs_data_t *obj) const
|
||||
obs_data_set_int(obj, "value", _value);
|
||||
obs_data_set_string(obj, "scene", GetWeakSourceName(_scene).c_str());
|
||||
_settingsPath.Save(obj, "settingsPath");
|
||||
obs_data_set_bool(obj, "confirmShutdown", _confirmShutdown);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroActionPluginState::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_action =
|
||||
static_cast<PluginStateAction>(obs_data_get_int(obj, "action"));
|
||||
_action = static_cast<MacroActionPluginState::Action>(
|
||||
obs_data_get_int(obj, "action"));
|
||||
_value = obs_data_get_int(obj, "value");
|
||||
const char *sceneName = obs_data_get_string(obj, "scene");
|
||||
_scene = GetWeakSourceByName(sceneName);
|
||||
_settingsPath.Load(obj, "settingsPath");
|
||||
if (obs_data_has_user_value(obj, "confirmShutdown")) {
|
||||
_confirmShutdown = obs_data_get_bool(obj, "confirmShutdown");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -229,15 +242,32 @@ void MacroActionPluginState::ResolveVariablesToFixedValues()
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
const static std::map<MacroActionPluginState::Action, std::string> actionTypes = {
|
||||
{MacroActionPluginState::Action::STOP,
|
||||
"AdvSceneSwitcher.action.pluginState.type.stop"},
|
||||
{MacroActionPluginState::Action::NO_MATCH_BEHAVIOUR,
|
||||
"AdvSceneSwitcher.action.pluginState.type.noMatch"},
|
||||
{MacroActionPluginState::Action::IMPORT_SETTINGS,
|
||||
"AdvSceneSwitcher.action.pluginState.type.import"},
|
||||
{MacroActionPluginState::Action::TERMINATE,
|
||||
"AdvSceneSwitcher.action.pluginState.type.terminate"},
|
||||
{MacroActionPluginState::Action::ENABLE_MACRO_HIGHLIGHTING,
|
||||
"AdvSceneSwitcher.action.pluginState.type.enableMacroHighlighting"},
|
||||
{MacroActionPluginState::Action::DISABLE_MACRO_HIGHLIGHTING,
|
||||
"AdvSceneSwitcher.action.pluginState.type.disableMacroHighlighting"},
|
||||
{MacroActionPluginState::Action::TOGGLE_MACRO_HIGHLIGHTING,
|
||||
"AdvSceneSwitcher.action.pluginState.type.toggleMacroHighlighting"},
|
||||
};
|
||||
|
||||
for (const auto &[_, name] : actionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void populateValueSelection(QComboBox *list,
|
||||
PluginStateAction action)
|
||||
MacroActionPluginState::Action action)
|
||||
{
|
||||
if (action == PluginStateAction::NO_MATCH_BEHAVIOUR) {
|
||||
if (action == MacroActionPluginState::Action::NO_MATCH_BEHAVIOUR) {
|
||||
for (const auto &[_, name] : noMatchValues) {
|
||||
list->addItem(obs_module_text(name.c_str()));
|
||||
}
|
||||
@@ -246,15 +276,16 @@ static inline void populateValueSelection(QComboBox *list,
|
||||
|
||||
MacroActionPluginStateEdit::MacroActionPluginStateEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionPluginState> entryData)
|
||||
: QWidget(parent)
|
||||
: QWidget(parent),
|
||||
_actions(new QComboBox(this)),
|
||||
_values(new QComboBox(this)),
|
||||
_scenes(new QComboBox(this)),
|
||||
_settings(new FileSelection()),
|
||||
_settingsWarning(new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.action.pluginState.importWarning"))),
|
||||
_confirmShutdown(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.action.pluginState.confirmShutdown")))
|
||||
{
|
||||
_actions = new QComboBox();
|
||||
_values = new QComboBox();
|
||||
_scenes = new QComboBox();
|
||||
_settings = new FileSelection();
|
||||
_settingsWarning = new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.action.pluginState.importWarning"));
|
||||
|
||||
populateActionSelection(_actions);
|
||||
PopulateSceneSelection(_scenes);
|
||||
|
||||
@@ -266,19 +297,22 @@ MacroActionPluginStateEdit::MacroActionPluginStateEdit(
|
||||
this, SLOT(SceneChanged(const QString &)));
|
||||
QWidget::connect(_settings, SIGNAL(PathChanged(const QString &)), this,
|
||||
SLOT(PathChanged(const QString &)));
|
||||
QWidget::connect(_confirmShutdown, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(ConfirmShutdownChanged(int)));
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{actions}}", _actions},
|
||||
{"{{values}}", _values},
|
||||
{"{{scenes}}", _scenes},
|
||||
{"{{settings}}", _settings},
|
||||
{"{{settingsWarning}}", _settingsWarning},
|
||||
};
|
||||
auto entryLayout = new QHBoxLayout;
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.action.pluginState.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
entryLayout,
|
||||
{{"{{actions}}", _actions},
|
||||
{"{{values}}", _values},
|
||||
{"{{scenes}}", _scenes},
|
||||
{"{{settings}}", _settings}});
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->addLayout(entryLayout);
|
||||
layout->addWidget(_settingsWarning);
|
||||
layout->addWidget(_confirmShutdown);
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
@@ -295,6 +329,7 @@ void MacroActionPluginStateEdit::UpdateEntryData()
|
||||
_values->setCurrentIndex(_entryData->_value);
|
||||
_scenes->setCurrentText(GetWeakSourceName(_entryData->_scene).c_str());
|
||||
_settings->SetPath(_entryData->_settingsPath);
|
||||
_confirmShutdown->setChecked(_entryData->_confirmShutdown);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -302,7 +337,8 @@ void MacroActionPluginStateEdit::ActionChanged(int value)
|
||||
{
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_action = static_cast<PluginStateAction>(value);
|
||||
_entryData->_action =
|
||||
static_cast<MacroActionPluginState::Action>(value);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -329,6 +365,12 @@ void MacroActionPluginStateEdit::PathChanged(const QString &text)
|
||||
_entryData->_settingsPath = text.toStdString();
|
||||
}
|
||||
|
||||
void MacroActionPluginStateEdit::ConfirmShutdownChanged(int value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_confirmShutdown = value;
|
||||
}
|
||||
|
||||
void MacroActionPluginStateEdit::SetWidgetVisibility()
|
||||
{
|
||||
if (!_entryData) {
|
||||
@@ -339,20 +381,25 @@ void MacroActionPluginStateEdit::SetWidgetVisibility()
|
||||
_scenes->hide();
|
||||
_settings->hide();
|
||||
_settingsWarning->hide();
|
||||
_confirmShutdown->hide();
|
||||
|
||||
switch (_entryData->_action) {
|
||||
case PluginStateAction::STOP:
|
||||
case MacroActionPluginState::Action::STOP:
|
||||
break;
|
||||
case PluginStateAction::NO_MATCH_BEHAVIOUR:
|
||||
case MacroActionPluginState::Action::NO_MATCH_BEHAVIOUR:
|
||||
_values->show();
|
||||
if (static_cast<NoMatchBehavior>(_entryData->_value) ==
|
||||
NoMatchBehavior::SWITCH) {
|
||||
_scenes->show();
|
||||
}
|
||||
break;
|
||||
case PluginStateAction::IMPORT_SETTINGS:
|
||||
case MacroActionPluginState::Action::IMPORT_SETTINGS:
|
||||
_settings->show();
|
||||
_settingsWarning->show();
|
||||
break;
|
||||
case MacroActionPluginState::Action::TERMINATE:
|
||||
_confirmShutdown->show();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -3,17 +3,12 @@
|
||||
#include "file-selection.hpp"
|
||||
|
||||
#include <obs.hpp>
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QLabel>
|
||||
|
||||
namespace advss {
|
||||
|
||||
enum class PluginStateAction {
|
||||
STOP,
|
||||
NO_MATCH_BEHAVIOUR,
|
||||
IMPORT_SETTINGS,
|
||||
TERMINATE,
|
||||
};
|
||||
|
||||
class MacroActionPluginState : public MacroAction {
|
||||
public:
|
||||
MacroActionPluginState(Macro *m) : MacroAction(m) {}
|
||||
@@ -26,10 +21,21 @@ public:
|
||||
std::shared_ptr<MacroAction> Copy() const;
|
||||
void ResolveVariablesToFixedValues();
|
||||
|
||||
PluginStateAction _action = PluginStateAction::STOP;
|
||||
enum class Action {
|
||||
STOP,
|
||||
NO_MATCH_BEHAVIOUR,
|
||||
IMPORT_SETTINGS,
|
||||
TERMINATE,
|
||||
ENABLE_MACRO_HIGHLIGHTING,
|
||||
DISABLE_MACRO_HIGHLIGHTING,
|
||||
TOGGLE_MACRO_HIGHLIGHTING,
|
||||
};
|
||||
|
||||
Action _action = Action::STOP;
|
||||
int _value = 0;
|
||||
StringVariable _settingsPath;
|
||||
OBSWeakSource _scene;
|
||||
bool _confirmShutdown = true;
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
@@ -58,17 +64,19 @@ private slots:
|
||||
void ValueChanged(int value);
|
||||
void SceneChanged(const QString &text);
|
||||
void PathChanged(const QString &text);
|
||||
void ConfirmShutdownChanged(int);
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
protected:
|
||||
QComboBox *_actions;
|
||||
QComboBox *_values;
|
||||
QComboBox *_scenes;
|
||||
FileSelection *_settings;
|
||||
QLabel *_settingsWarning;
|
||||
std::shared_ptr<MacroActionPluginState> _entryData;
|
||||
QCheckBox *_confirmShutdown;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
std::shared_ptr<MacroActionPluginState> _entryData;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -250,6 +250,10 @@ MacroActionProjectorEdit::MacroActionProjectorEdit(
|
||||
_regex(new RegexConfigWidget(this)),
|
||||
_layout(new QHBoxLayout(this))
|
||||
{
|
||||
// The obs_frontend_open_projector() function does not seem to support
|
||||
// scenes of secondary canvases
|
||||
_scenes->LockToMainCanvas();
|
||||
|
||||
populateActionSelection(_actions);
|
||||
populateWindowTypes(_windowTypes);
|
||||
populateSelectionTypes(_types);
|
||||
@@ -396,26 +400,29 @@ void MacroActionProjectorEdit::SetWidgetVisibility()
|
||||
return;
|
||||
}
|
||||
|
||||
_projectorWindowName->setVisible(_entryData->_action ==
|
||||
const auto &action = _entryData->_action;
|
||||
const auto &type = _entryData->_type;
|
||||
|
||||
_projectorWindowName->setVisible(action ==
|
||||
MacroActionProjector::Action::CLOSE);
|
||||
_regex->setVisible(_entryData->_action ==
|
||||
MacroActionProjector::Action::CLOSE);
|
||||
_types->setVisible(_entryData->_action ==
|
||||
MacroActionProjector::Action::OPEN);
|
||||
_windowTypes->setVisible(_entryData->_action ==
|
||||
MacroActionProjector::Action::OPEN);
|
||||
_scenes->setVisible(
|
||||
_entryData->_action == MacroActionProjector::Action::OPEN &&
|
||||
_entryData->_type == MacroActionProjector::Type::SCENE);
|
||||
_sources->setVisible(
|
||||
_entryData->_action == MacroActionProjector::Action::OPEN &&
|
||||
_entryData->_type == MacroActionProjector::Type::SOURCE);
|
||||
_monitors->setVisible(_entryData->_action ==
|
||||
MacroActionProjector::Action::OPEN &&
|
||||
_regex->setVisible(action == MacroActionProjector::Action::CLOSE);
|
||||
_types->setVisible(action == MacroActionProjector::Action::OPEN);
|
||||
_windowTypes->setVisible(action == MacroActionProjector::Action::OPEN);
|
||||
_scenes->setVisible(action == MacroActionProjector::Action::OPEN &&
|
||||
type == MacroActionProjector::Type::SCENE);
|
||||
_sources->setVisible(action == MacroActionProjector::Action::OPEN &&
|
||||
type == MacroActionProjector::Type::SOURCE);
|
||||
_monitors->setVisible(action == MacroActionProjector::Action::OPEN &&
|
||||
_entryData->_fullscreen);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
if (action == MacroActionProjector::Action::CLOSE) {
|
||||
RemoveStretchIfPresent(_layout);
|
||||
} else {
|
||||
AddStretchIfNecessary(_layout);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "macro-action-random.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
#include "ui-helpers.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
@@ -106,8 +107,8 @@ MacroActionRandomEdit::MacroActionRandomEdit(
|
||||
QWidget::connect(_list, SIGNAL(Removed(int)), this, SLOT(Remove(int)));
|
||||
QWidget::connect(_list, SIGNAL(Replaced(int, const std::string &)),
|
||||
this, SLOT(Replace(int, const std::string &)));
|
||||
QWidget::connect(GetSettingsWindow(),
|
||||
SIGNAL(MacroRemoved(const QString &)), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Remove(const QString &)), this,
|
||||
SLOT(MacroRemove(const QString &)));
|
||||
QWidget::connect(_allowRepeat, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(AllowRepeatChanged(int)));
|
||||
|
||||
@@ -113,7 +113,19 @@ MacroActionSceneLockEdit::MacroActionSceneLockEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionSceneLock> entryData)
|
||||
: QWidget(parent),
|
||||
_scenes(new SceneSelectionWidget(this, true, false, true, true)),
|
||||
_sources(new SceneItemSelectionWidget(parent)),
|
||||
_sources(new SceneItemSelectionWidget(
|
||||
parent,
|
||||
{
|
||||
SceneItemSelection::Type::SOURCE_NAME,
|
||||
SceneItemSelection::Type::VARIABLE_NAME,
|
||||
SceneItemSelection::Type::SOURCE_NAME_PATTERN,
|
||||
SceneItemSelection::Type::SOURCE_GROUP,
|
||||
SceneItemSelection::Type::SOURCE_TYPE,
|
||||
SceneItemSelection::Type::INDEX,
|
||||
SceneItemSelection::Type::INDEX_RANGE,
|
||||
SceneItemSelection::Type::ALL,
|
||||
},
|
||||
SceneItemSelectionWidget::NameClashMode::ALL)),
|
||||
_actions(new QComboBox())
|
||||
{
|
||||
populateActionSelection(_actions);
|
||||
|
||||
@@ -276,8 +276,32 @@ MacroActionSceneOrderEdit::MacroActionSceneOrderEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionSceneOrder> entryData)
|
||||
: QWidget(parent),
|
||||
_scenes(new SceneSelectionWidget(this, true, false, false, true)),
|
||||
_sources(new SceneItemSelectionWidget(this)),
|
||||
_sources2(new SceneItemSelectionWidget(this)),
|
||||
_sources(new SceneItemSelectionWidget(
|
||||
this,
|
||||
{
|
||||
SceneItemSelection::Type::SOURCE_NAME,
|
||||
SceneItemSelection::Type::VARIABLE_NAME,
|
||||
SceneItemSelection::Type::SOURCE_NAME_PATTERN,
|
||||
SceneItemSelection::Type::SOURCE_GROUP,
|
||||
SceneItemSelection::Type::SOURCE_TYPE,
|
||||
SceneItemSelection::Type::INDEX,
|
||||
SceneItemSelection::Type::INDEX_RANGE,
|
||||
SceneItemSelection::Type::ALL,
|
||||
},
|
||||
SceneItemSelectionWidget::NameClashMode::ALL)),
|
||||
_sources2(new SceneItemSelectionWidget(
|
||||
this,
|
||||
{
|
||||
SceneItemSelection::Type::SOURCE_NAME,
|
||||
SceneItemSelection::Type::VARIABLE_NAME,
|
||||
SceneItemSelection::Type::SOURCE_NAME_PATTERN,
|
||||
SceneItemSelection::Type::SOURCE_GROUP,
|
||||
SceneItemSelection::Type::SOURCE_TYPE,
|
||||
SceneItemSelection::Type::INDEX,
|
||||
SceneItemSelection::Type::INDEX_RANGE,
|
||||
SceneItemSelection::Type::ALL,
|
||||
},
|
||||
SceneItemSelectionWidget::NameClashMode::ALL)),
|
||||
_actions(new QComboBox(this)),
|
||||
_position(new QSpinBox(this))
|
||||
{
|
||||
|
||||
@@ -19,14 +19,6 @@ bool MacroActionSwitchScene::_registered = MacroActionFactory::Register(
|
||||
{MacroActionSwitchScene::Create, MacroActionSwitchSceneEdit::Create,
|
||||
"AdvSceneSwitcher.action.scene"});
|
||||
|
||||
const static std::map<MacroActionSwitchScene::SceneType, std::string>
|
||||
sceneTypes = {
|
||||
{MacroActionSwitchScene::SceneType::PROGRAM,
|
||||
"AdvSceneSwitcher.action.scene.type.program"},
|
||||
{MacroActionSwitchScene::SceneType::PREVIEW,
|
||||
"AdvSceneSwitcher.action.scene.type.preview"},
|
||||
};
|
||||
|
||||
static void waitForTransitionChange(OBSWeakSource &transition,
|
||||
std::unique_lock<std::mutex> *lock,
|
||||
Macro *macro)
|
||||
@@ -144,34 +136,92 @@ bool MacroActionSwitchScene::WaitForTransition(OBSWeakSource &scene,
|
||||
|
||||
bool MacroActionSwitchScene::PerformAction()
|
||||
{
|
||||
auto scene = _scene.GetScene();
|
||||
OBSWeakSource sceneToSwitchTo;
|
||||
OBSWeakCanvas canvas;
|
||||
|
||||
switch (_action) {
|
||||
case Action::SCENE_NAME:
|
||||
sceneToSwitchTo = _scene.GetScene();
|
||||
canvas = _scene.GetCanvas();
|
||||
break;
|
||||
case Action::SCENE_LIST_NEXT: {
|
||||
const auto activeScene = GetActiveCanvasScene(_canvas);
|
||||
const int currentIndex = GetIndexOfScene(_canvas, activeScene);
|
||||
sceneToSwitchTo = GetSceneAtIndex(_canvas, currentIndex + 1);
|
||||
canvas = _canvas;
|
||||
break;
|
||||
}
|
||||
case Action::SCENE_LIST_PREVIOUS: {
|
||||
const auto activeScene = GetActiveCanvasScene(_canvas);
|
||||
const int currentIndex = GetIndexOfScene(_canvas, activeScene);
|
||||
sceneToSwitchTo = GetSceneAtIndex(_canvas, currentIndex - 1);
|
||||
canvas = _canvas;
|
||||
break;
|
||||
}
|
||||
case Action::SCENE_LIST_INDEX: {
|
||||
sceneToSwitchTo =
|
||||
GetSceneAtIndex(_canvas, _index.GetValue() - 1);
|
||||
canvas = _canvas;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (_sceneType == SceneType::PREVIEW) {
|
||||
OBSSourceAutoRelease previewScneSource =
|
||||
obs_weak_source_get_source(scene);
|
||||
obs_frontend_set_current_preview_scene(previewScneSource);
|
||||
OBSSourceAutoRelease previewSceneSource =
|
||||
obs_weak_source_get_source(sceneToSwitchTo);
|
||||
obs_frontend_set_current_preview_scene(previewSceneSource);
|
||||
return true;
|
||||
}
|
||||
|
||||
auto transition = _transition.GetTransition();
|
||||
SwitchScene({scene, transition, (int)(_duration.Milliseconds())},
|
||||
obs_frontend_preview_program_mode_active());
|
||||
if (_blockUntilTransitionDone && scene && scene != GetCurrentScene()) {
|
||||
return WaitForTransition(scene, transition);
|
||||
SwitchScene({sceneToSwitchTo, transition,
|
||||
(int)(_duration.Milliseconds())},
|
||||
obs_frontend_preview_program_mode_active(), canvas);
|
||||
if (_blockUntilTransitionDone && sceneToSwitchTo &&
|
||||
sceneToSwitchTo != GetCurrentScene() && IsMainCanvas(canvas)) {
|
||||
return WaitForTransition(sceneToSwitchTo, transition);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroActionSwitchScene::LogAction() const
|
||||
{
|
||||
ablog(LOG_INFO, "switch%s scene to '%s'",
|
||||
_sceneType == SceneType::PREVIEW ? " preview" : "",
|
||||
_scene.ToString(true).c_str());
|
||||
if (!ActionLoggingEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (_action) {
|
||||
case Action::SCENE_NAME:
|
||||
blog(LOG_INFO, "switch %s scene to '%s'",
|
||||
_sceneType == SceneType::PREVIEW ? " preview" : "program",
|
||||
_scene.ToString(true).c_str());
|
||||
break;
|
||||
case Action::SCENE_LIST_NEXT:
|
||||
blog(LOG_INFO, "switch %s to next scene in scene list",
|
||||
_sceneType == SceneType::PREVIEW ? " preview" : "program");
|
||||
break;
|
||||
case Action::SCENE_LIST_PREVIOUS:
|
||||
blog(LOG_INFO, "switch %s to previous scene in scene list",
|
||||
_sceneType == SceneType::PREVIEW ? " preview" : "program");
|
||||
break;
|
||||
case Action::SCENE_LIST_INDEX:
|
||||
blog(LOG_INFO, "switch %s to scene at index %d in scene list",
|
||||
_sceneType == SceneType::PREVIEW ? " preview" : "program",
|
||||
_index.GetValue());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool MacroActionSwitchScene::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
obs_data_set_string(obj, "canvas", GetWeakCanvasName(_canvas).c_str());
|
||||
_index.Save(obj, "index");
|
||||
_scene.Save(obj);
|
||||
_transition.Save(obj);
|
||||
_duration.Save(obj);
|
||||
@@ -184,6 +234,16 @@ bool MacroActionSwitchScene::Save(obs_data_t *obj) const
|
||||
bool MacroActionSwitchScene::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
if (obs_data_has_user_value(obj, "canvas")) {
|
||||
_canvas =
|
||||
GetWeakCanvasByName(obs_data_get_string(obj, "canvas"));
|
||||
} else {
|
||||
OBSCanvasAutoRelease main = obs_get_main_canvas();
|
||||
_canvas = obs_canvas_get_weak_canvas(main);
|
||||
}
|
||||
|
||||
_index.Save(obj, "index");
|
||||
_scene.Load(obj);
|
||||
_transition.Load(obj);
|
||||
_duration.Load(obj);
|
||||
@@ -195,7 +255,7 @@ bool MacroActionSwitchScene::Load(obs_data_t *obj)
|
||||
|
||||
std::string MacroActionSwitchScene::GetShortDesc() const
|
||||
{
|
||||
return _scene.ToString();
|
||||
return _action == Action::SCENE_NAME ? _scene.ToString() : "";
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionSwitchScene::Create(Macro *m)
|
||||
@@ -214,61 +274,128 @@ void MacroActionSwitchScene::ResolveVariablesToFixedValues()
|
||||
_duration.ResolveVariables();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void populate(QComboBox *list, const std::map<T, std::string> &data)
|
||||
{
|
||||
for (const auto &[value, name] : data) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void populateTypeSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[_, name] : sceneTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()));
|
||||
}
|
||||
static const std::map<MacroActionSwitchScene::SceneType, std::string>
|
||||
types = {
|
||||
{MacroActionSwitchScene::SceneType::PROGRAM,
|
||||
"AdvSceneSwitcher.action.scene.type.program"},
|
||||
{MacroActionSwitchScene::SceneType::PREVIEW,
|
||||
"AdvSceneSwitcher.action.scene.type.preview"},
|
||||
};
|
||||
|
||||
populate(list, types);
|
||||
}
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
static const std::map<MacroActionSwitchScene::Action, std::string>
|
||||
actions = {
|
||||
{MacroActionSwitchScene::Action::SCENE_NAME,
|
||||
"AdvSceneSwitcher.action.scene.action.fixed"},
|
||||
{MacroActionSwitchScene::Action::SCENE_LIST_NEXT,
|
||||
"AdvSceneSwitcher.action.scene.action.sceneListNext"},
|
||||
{MacroActionSwitchScene::Action::SCENE_LIST_PREVIOUS,
|
||||
"AdvSceneSwitcher.action.scene.action.sceneListPrevious"},
|
||||
{MacroActionSwitchScene::Action::SCENE_LIST_INDEX,
|
||||
"AdvSceneSwitcher.action.scene.action.sceneListIndex"},
|
||||
};
|
||||
|
||||
populate(list, actions);
|
||||
}
|
||||
|
||||
MacroActionSwitchSceneEdit::MacroActionSwitchSceneEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionSwitchScene> entryData)
|
||||
: QWidget(parent),
|
||||
_actions(new QComboBox(this)),
|
||||
_index(new VariableSpinBox(this)),
|
||||
_scenes(new SceneSelectionWidget(this, true, true, true)),
|
||||
_transitions(new TransitionSelectionWidget(this)),
|
||||
_duration(new DurationSelection(parent, false)),
|
||||
_duration(new DurationSelection(this, false)),
|
||||
_blockUntilTransitionDone(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.action.scene.blockUntilTransitionDone"))),
|
||||
_sceneTypes(new QComboBox()),
|
||||
_entryLayout(new QHBoxLayout())
|
||||
_sceneTypes(new QComboBox(this)),
|
||||
_canvas(new CanvasSelection(this)),
|
||||
_sceneNameAtIndex(new QLabel(this)),
|
||||
_updateSceneNameTimer(new QTimer(this)),
|
||||
_actionLayout(new QHBoxLayout()),
|
||||
_transitionLayout(new QHBoxLayout()),
|
||||
_notSupportedWarning(new QLabel(this))
|
||||
{
|
||||
_index->setMinimum(1);
|
||||
_index->setMaximum(999);
|
||||
|
||||
_duration->SpinBox()->setSpecialValueText("-");
|
||||
|
||||
populateTypeSelection(_sceneTypes);
|
||||
populateActionSelection(_actions);
|
||||
|
||||
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
|
||||
this, SLOT(SceneChanged(const SceneSelection &)));
|
||||
QWidget::connect(_transitions,
|
||||
SIGNAL(TransitionChanged(const TransitionSelection &)),
|
||||
this,
|
||||
SLOT(TransitionChanged(const TransitionSelection &)));
|
||||
QWidget::connect(_duration, SIGNAL(DurationChanged(const Duration &)),
|
||||
this, SLOT(DurationChanged(const Duration &)));
|
||||
QWidget::connect(_blockUntilTransitionDone, SIGNAL(stateChanged(int)),
|
||||
this, SLOT(BlockUntilTransitionDoneChanged(int)));
|
||||
QWidget::connect(_sceneTypes, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(SceneTypeChanged(int)));
|
||||
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.scene.entry"),
|
||||
_entryLayout,
|
||||
{{"{{scenes}}", _scenes},
|
||||
{"{{transitions}}", _transitions},
|
||||
{"{{duration}}", _duration},
|
||||
{"{{sceneTypes}}", _sceneTypes}});
|
||||
SetupWidgetConnections();
|
||||
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(_entryLayout);
|
||||
mainLayout->addLayout(_actionLayout);
|
||||
mainLayout->addLayout(_transitionLayout);
|
||||
mainLayout->addWidget(_blockUntilTransitionDone);
|
||||
mainLayout->addWidget(_notSupportedWarning);
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
_sceneTypes->setCurrentIndex(static_cast<int>(_entryData->_sceneType));
|
||||
SetWidgetData();
|
||||
|
||||
SetWidgetVisibility();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::SetupWidgetConnections() const
|
||||
{
|
||||
connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
connect(_sceneTypes, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(SceneTypeChanged(int)));
|
||||
connect(_canvas, SIGNAL(CanvasChanged(const OBSWeakCanvas &)), this,
|
||||
SLOT(CanvasChanged(const OBSWeakCanvas &)));
|
||||
connect(_index,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(IndexChanged(const NumberVariable<int> &)));
|
||||
connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)), this,
|
||||
SLOT(SceneChanged(const SceneSelection &)));
|
||||
connect(_scenes, SIGNAL(CanvasChanged(const OBSWeakCanvas &)), this,
|
||||
SLOT(SceneSelectionCanvasChanged(const OBSWeakCanvas &)));
|
||||
connect(_transitions,
|
||||
SIGNAL(TransitionChanged(const TransitionSelection &)), this,
|
||||
SLOT(TransitionChanged(const TransitionSelection &)));
|
||||
connect(_duration, SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(DurationChanged(const Duration &)));
|
||||
connect(_blockUntilTransitionDone, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(BlockUntilTransitionDoneChanged(int)));
|
||||
connect(_updateSceneNameTimer, SIGNAL(timeout()), this,
|
||||
SLOT(UpdateSceneNameAtIndex()));
|
||||
|
||||
_updateSceneNameTimer->setInterval(300);
|
||||
_updateSceneNameTimer->start();
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::SetWidgetData() const
|
||||
{
|
||||
_actions->setCurrentIndex(
|
||||
_actions->findData(static_cast<int>(_entryData->_action)));
|
||||
_index->SetValue(_entryData->_index);
|
||||
_sceneTypes->setCurrentIndex(_sceneTypes->findData(
|
||||
static_cast<int>(_entryData->_sceneType)));
|
||||
_scenes->SetScene(_entryData->_scene);
|
||||
_transitions->SetTransition(_entryData->_transition);
|
||||
_duration->SetDuration(_entryData->_duration);
|
||||
_blockUntilTransitionDone->setChecked(
|
||||
_entryData->_blockUntilTransitionDone);
|
||||
SetWidgetVisibility();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::DurationChanged(const Duration &dur)
|
||||
@@ -283,58 +410,182 @@ void MacroActionSwitchSceneEdit::BlockUntilTransitionDoneChanged(int state)
|
||||
_entryData->_blockUntilTransitionDone = state;
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::SceneTypeChanged(int value)
|
||||
void MacroActionSwitchSceneEdit::SceneTypeChanged(int)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_sceneType =
|
||||
static_cast<MacroActionSwitchScene::SceneType>(value);
|
||||
_entryData->_sceneType = static_cast<MacroActionSwitchScene::SceneType>(
|
||||
_sceneTypes->currentData().toInt());
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::CanvasChanged(const OBSWeakCanvas &canvas)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_canvas = canvas;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::SceneSelectionCanvasChanged(
|
||||
const OBSWeakCanvas &)
|
||||
{
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::ActionChanged(int value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_action = static_cast<MacroActionSwitchScene::Action>(
|
||||
_actions->currentData().toInt());
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::IndexChanged(const NumberVariable<int> &value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_index = value;
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::UpdateSceneNameAtIndex()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto weakSource =
|
||||
GetSceneAtIndex(_entryData->_canvas, _entryData->_index - 1);
|
||||
if (!weakSource) {
|
||||
_sceneNameAtIndex->setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
OBSSourceAutoRelease source = OBSGetStrongRef(weakSource);
|
||||
auto name = obs_source_get_name(source);
|
||||
if (!name) {
|
||||
_sceneNameAtIndex->setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
const QString text = QString("(") + name + ")";
|
||||
_sceneNameAtIndex->setText(text);
|
||||
}
|
||||
|
||||
static bool
|
||||
shouldShowDurationInTransitionLayout(MacroActionSwitchScene::SceneType type,
|
||||
const TransitionSelection &transition)
|
||||
{
|
||||
if (type == MacroActionSwitchScene::SceneType::PREVIEW) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (transition.GetType() != TransitionSelection::Type::TRANSITION) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isUsingFixedLengthTransition(transition.GetTransition())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::SetWidgetVisibility()
|
||||
{
|
||||
_entryLayout->removeWidget(_scenes);
|
||||
_entryLayout->removeWidget(_transitions);
|
||||
_entryLayout->removeWidget(_duration);
|
||||
_entryLayout->removeWidget(_sceneTypes);
|
||||
ClearLayout(_entryLayout);
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{scenes}}", _scenes},
|
||||
{"{{transitions}}", _transitions},
|
||||
{"{{duration}}", _duration},
|
||||
_actionLayout->removeWidget(_sceneTypes);
|
||||
_actionLayout->removeWidget(_actions);
|
||||
_actionLayout->removeWidget(_scenes);
|
||||
_actionLayout->removeWidget(_canvas);
|
||||
_actionLayout->removeWidget(_index);
|
||||
_actionLayout->removeWidget(_sceneNameAtIndex);
|
||||
ClearLayout(_actionLayout);
|
||||
|
||||
const int canvasCount = GetCanvasCount();
|
||||
const auto &action = _entryData->_action;
|
||||
|
||||
_scenes->setVisible(action ==
|
||||
MacroActionSwitchScene::Action::SCENE_NAME);
|
||||
_canvas->setVisible(
|
||||
action != MacroActionSwitchScene::Action::SCENE_NAME &&
|
||||
canvasCount > 1);
|
||||
_index->setVisible(action ==
|
||||
MacroActionSwitchScene::Action::SCENE_LIST_INDEX);
|
||||
_sceneNameAtIndex->setVisible(
|
||||
action == MacroActionSwitchScene::Action::SCENE_LIST_INDEX);
|
||||
|
||||
const std::unordered_map<std::string, QWidget *> actionWidgets = {
|
||||
{"{{actions}}", _actions},
|
||||
{"{{sceneTypes}}", _sceneTypes},
|
||||
};
|
||||
{"{{scenes}}", _scenes},
|
||||
{"{{canvas}}", _canvas},
|
||||
{"{{index}}", _index},
|
||||
{"{{sceneNameAtIndex}}", _sceneNameAtIndex}};
|
||||
|
||||
if (_entryData->_sceneType ==
|
||||
MacroActionSwitchScene::SceneType::PREVIEW) {
|
||||
_transitions->hide();
|
||||
_duration->hide();
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.scene.entry.preview"),
|
||||
_entryLayout, widgetPlaceholders);
|
||||
return;
|
||||
const char *layoutString = "";
|
||||
switch (action) {
|
||||
case MacroActionSwitchScene::Action::SCENE_NAME:
|
||||
layoutString =
|
||||
"AdvSceneSwitcher.action.scene.layout.action.fixed";
|
||||
break;
|
||||
case MacroActionSwitchScene::Action::SCENE_LIST_NEXT:
|
||||
case MacroActionSwitchScene::Action::SCENE_LIST_PREVIOUS:
|
||||
layoutString =
|
||||
(canvasCount > 1)
|
||||
? "AdvSceneSwitcher.action.scene.layout.action.list"
|
||||
: "AdvSceneSwitcher.action.scene.layout.action.list.noCanvasSelection";
|
||||
break;
|
||||
case MacroActionSwitchScene::Action::SCENE_LIST_INDEX:
|
||||
layoutString =
|
||||
(canvasCount > 1)
|
||||
? "AdvSceneSwitcher.action.scene.layout.action.listIndex"
|
||||
: "AdvSceneSwitcher.action.scene.layout.action.listIndex.noCanvasSelection";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_transitions->show();
|
||||
if (_entryData->_transition.GetType() !=
|
||||
TransitionSelection::Type::TRANSITION) {
|
||||
_duration->show();
|
||||
}
|
||||
const bool fixedDuration = isUsingFixedLengthTransition(
|
||||
_entryData->_transition.GetTransition());
|
||||
_duration->setVisible(!fixedDuration);
|
||||
PlaceWidgets(obs_module_text(layoutString), _actionLayout,
|
||||
actionWidgets);
|
||||
|
||||
if (fixedDuration) {
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.scene.entry.noDuration"),
|
||||
_entryLayout, widgetPlaceholders);
|
||||
} else {
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.action.scene.entry"),
|
||||
_entryLayout, widgetPlaceholders);
|
||||
}
|
||||
_transitionLayout->removeWidget(_transitions);
|
||||
_transitionLayout->removeWidget(_duration);
|
||||
ClearLayout(_transitionLayout);
|
||||
|
||||
const bool shouldShowDuration = shouldShowDurationInTransitionLayout(
|
||||
_entryData->_sceneType, _entryData->_transition);
|
||||
_duration->setVisible(shouldShowDuration);
|
||||
|
||||
layoutString =
|
||||
shouldShowDuration
|
||||
? "AdvSceneSwitcher.action.scene.layout.transitionWithDuration"
|
||||
: "AdvSceneSwitcher.action.scene.layout.transition";
|
||||
PlaceWidgets(obs_module_text(layoutString), _transitionLayout,
|
||||
{{"{{transitions}}", _transitions},
|
||||
{"{{duration}}", _duration}});
|
||||
|
||||
const auto canvas = action == MacroActionSwitchScene::Action::SCENE_NAME
|
||||
? _entryData->_scene.GetCanvas()
|
||||
: _entryData->_canvas;
|
||||
const bool isMainCanvas = IsMainCanvas(canvas);
|
||||
SetLayoutVisible(_transitionLayout, isMainCanvas);
|
||||
_blockUntilTransitionDone->setVisible(isMainCanvas);
|
||||
|
||||
_scenes->setVisible(action ==
|
||||
MacroActionSwitchScene::Action::SCENE_NAME);
|
||||
_index->setVisible(action ==
|
||||
MacroActionSwitchScene::Action::SCENE_LIST_INDEX);
|
||||
_sceneNameAtIndex->setVisible(
|
||||
action == MacroActionSwitchScene::Action::SCENE_LIST_INDEX);
|
||||
|
||||
const QString fmt = obs_module_text(
|
||||
"AdvSceneSwitcher.action.scene.canvasNotSupported");
|
||||
_notSupportedWarning->setText(
|
||||
fmt.arg(QString::fromStdString(GetWeakCanvasName(canvas))));
|
||||
_notSupportedWarning->setVisible(
|
||||
!IsMainCanvas(canvas) &&
|
||||
_entryData->_sceneType ==
|
||||
MacroActionSwitchScene::SceneType::PREVIEW);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionSwitchSceneEdit::SceneChanged(const SceneSelection &s)
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <QCheckBox>
|
||||
|
||||
#include <obs.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MacroActionSwitchScene : public MacroAction {
|
||||
@@ -21,8 +23,19 @@ public:
|
||||
std::shared_ptr<MacroAction> Copy() const;
|
||||
void ResolveVariablesToFixedValues();
|
||||
|
||||
enum class Action {
|
||||
SCENE_NAME,
|
||||
SCENE_LIST_NEXT,
|
||||
SCENE_LIST_PREVIOUS,
|
||||
SCENE_LIST_INDEX,
|
||||
};
|
||||
Action _action = Action::SCENE_NAME;
|
||||
|
||||
enum class SceneType { PROGRAM, PREVIEW };
|
||||
SceneType _sceneType = SceneType::PROGRAM;
|
||||
|
||||
OBSWeakCanvas _canvas;
|
||||
IntVariable _index = 1;
|
||||
SceneSelection _scene;
|
||||
TransitionSelection _transition;
|
||||
Duration _duration;
|
||||
@@ -57,18 +70,32 @@ private slots:
|
||||
void DurationChanged(const Duration &seconds);
|
||||
void BlockUntilTransitionDoneChanged(int state);
|
||||
void SceneTypeChanged(int);
|
||||
void CanvasChanged(const OBSWeakCanvas &);
|
||||
void SceneSelectionCanvasChanged(const OBSWeakCanvas &);
|
||||
void ActionChanged(int);
|
||||
void IndexChanged(const NumberVariable<int> &);
|
||||
void UpdateSceneNameAtIndex();
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
private:
|
||||
void SetupWidgetConnections() const;
|
||||
void SetWidgetData() const;
|
||||
void SetWidgetVisibility();
|
||||
|
||||
QComboBox *_actions;
|
||||
VariableSpinBox *_index;
|
||||
SceneSelectionWidget *_scenes;
|
||||
TransitionSelectionWidget *_transitions;
|
||||
DurationSelection *_duration;
|
||||
QCheckBox *_blockUntilTransitionDone;
|
||||
QComboBox *_sceneTypes;
|
||||
QHBoxLayout *_entryLayout;
|
||||
CanvasSelection *_canvas;
|
||||
QLabel *_sceneNameAtIndex;
|
||||
QTimer *_updateSceneNameTimer;
|
||||
QHBoxLayout *_actionLayout;
|
||||
QHBoxLayout *_transitionLayout;
|
||||
QLabel *_notSupportedWarning;
|
||||
|
||||
std::shared_ptr<MacroActionSwitchScene> _entryData;
|
||||
bool _loading = true;
|
||||
|
||||
@@ -400,7 +400,19 @@ MacroActionSceneTransformEdit::MacroActionSceneTransformEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionSceneTransform> entryData)
|
||||
: QWidget(parent),
|
||||
_scenes(new SceneSelectionWidget(this, true, false, false, true)),
|
||||
_sources(new SceneItemSelectionWidget(parent)),
|
||||
_sources(new SceneItemSelectionWidget(
|
||||
parent,
|
||||
{
|
||||
SceneItemSelection::Type::SOURCE_NAME,
|
||||
SceneItemSelection::Type::VARIABLE_NAME,
|
||||
SceneItemSelection::Type::SOURCE_NAME_PATTERN,
|
||||
SceneItemSelection::Type::SOURCE_GROUP,
|
||||
SceneItemSelection::Type::SOURCE_TYPE,
|
||||
SceneItemSelection::Type::INDEX,
|
||||
SceneItemSelection::Type::INDEX_RANGE,
|
||||
SceneItemSelection::Type::ALL,
|
||||
},
|
||||
SceneItemSelectionWidget::NameClashMode::ALL)),
|
||||
_action(new QComboBox()),
|
||||
_rotation(new VariableDoubleSpinBox()),
|
||||
_getTransform(new QPushButton(obs_module_text(
|
||||
|
||||
@@ -128,7 +128,19 @@ MacroActionSceneVisibilityEdit::MacroActionSceneVisibilityEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionSceneVisibility> entryData)
|
||||
: QWidget(parent),
|
||||
_scenes(new SceneSelectionWidget(this, true, false, true, true)),
|
||||
_sources(new SceneItemSelectionWidget(parent)),
|
||||
_sources(new SceneItemSelectionWidget(
|
||||
parent,
|
||||
{
|
||||
SceneItemSelection::Type::SOURCE_NAME,
|
||||
SceneItemSelection::Type::VARIABLE_NAME,
|
||||
SceneItemSelection::Type::SOURCE_NAME_PATTERN,
|
||||
SceneItemSelection::Type::SOURCE_GROUP,
|
||||
SceneItemSelection::Type::SOURCE_TYPE,
|
||||
SceneItemSelection::Type::INDEX,
|
||||
SceneItemSelection::Type::INDEX_RANGE,
|
||||
SceneItemSelection::Type::ALL,
|
||||
},
|
||||
SceneItemSelectionWidget::NameClashMode::ALL)),
|
||||
_actions(new QComboBox())
|
||||
{
|
||||
populateActionSelection(_actions);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "macro-action-sequence.hpp"
|
||||
#include "layout-helpers.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro-signals.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -212,7 +213,8 @@ MacroActionSequenceEdit::MacroActionSequenceEdit(
|
||||
SLOT(ContinueFromClicked()));
|
||||
QWidget::connect(_restart, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(RestartChanged(int)));
|
||||
QWidget::connect(this, SIGNAL(MacroRemoved(const QString &)), this,
|
||||
QWidget::connect(MacroSignalManager::Instance(),
|
||||
SIGNAL(Remove(const QString &)), this,
|
||||
SLOT(MacroRemove(const QString &)));
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
|
||||
@@ -201,7 +201,7 @@ bool MacroActionSource::Save(obs_data_t *obj) const
|
||||
static_cast<int>(_settingsInputMethod));
|
||||
_setting.Save(obj);
|
||||
_manualSettingValue.Save(obj, "manualSettingValue");
|
||||
_tempVar.Save(obj);
|
||||
_tempVar.Save(obj, GetMacro());
|
||||
_settingsString.Save(obj, "settings");
|
||||
obs_data_set_int(obj, "deinterlaceMode",
|
||||
static_cast<int>(_deinterlaceMode));
|
||||
|
||||
@@ -237,7 +237,19 @@ MacroActionTransitionEdit::MacroActionTransitionEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionTransition> entryData)
|
||||
: QWidget(parent),
|
||||
_actions(new QComboBox),
|
||||
_sources(new SceneItemSelectionWidget(parent, false)),
|
||||
_sources(new SceneItemSelectionWidget(
|
||||
parent,
|
||||
{
|
||||
SceneItemSelection::Type::SOURCE_NAME,
|
||||
SceneItemSelection::Type::VARIABLE_NAME,
|
||||
SceneItemSelection::Type::SOURCE_NAME_PATTERN,
|
||||
SceneItemSelection::Type::SOURCE_GROUP,
|
||||
SceneItemSelection::Type::SOURCE_TYPE,
|
||||
SceneItemSelection::Type::INDEX,
|
||||
SceneItemSelection::Type::INDEX_RANGE,
|
||||
SceneItemSelection::Type::ALL,
|
||||
},
|
||||
SceneItemSelectionWidget::NameClashMode::ALL)),
|
||||
_scenes(new SceneSelectionWidget(this, true, false, false, true)),
|
||||
_setTransition(new QCheckBox),
|
||||
_setDuration(new QCheckBox),
|
||||
@@ -268,7 +280,7 @@ MacroActionTransitionEdit::MacroActionTransitionEdit(
|
||||
QWidget::connect(_setDuration, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(SetDurationChanged(int)));
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{type}}", _actions},
|
||||
{"{{sources}}", _sources},
|
||||
{"{{scenes}}", _scenes},
|
||||
@@ -277,7 +289,8 @@ MacroActionTransitionEdit::MacroActionTransitionEdit(
|
||||
{"{{setTransition}}", _setTransition},
|
||||
{"{{setDuration}}", _setDuration},
|
||||
};
|
||||
QHBoxLayout *typeLayout = new QHBoxLayout;
|
||||
|
||||
auto typeLayout = new QHBoxLayout;
|
||||
PlaceWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.action.transition.entry.line1"),
|
||||
typeLayout, widgetPlaceholders);
|
||||
@@ -287,7 +300,7 @@ MacroActionTransitionEdit::MacroActionTransitionEdit(
|
||||
PlaceWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.action.transition.entry.line3"),
|
||||
_durationLayout, widgetPlaceholders);
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(typeLayout);
|
||||
mainLayout->addLayout(_transitionLayout);
|
||||
mainLayout->addLayout(_durationLayout);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user