mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-09-07 17:16:00 -05:00
Compare commits
79 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69b82ee2a3 | ||
|
|
f14e6bf252 | ||
|
|
e51ae79b4c | ||
|
|
8f55856fd5 | ||
|
|
a360d53419 | ||
|
|
d28164d02f | ||
|
|
f723212394 | ||
|
|
a0cb08d18f | ||
|
|
d18044b764 | ||
|
|
406b5d61f5 | ||
|
|
9a4eef4a83 | ||
|
|
efaf9a2ef3 | ||
|
|
edb2952fd6 | ||
|
|
088828a351 | ||
|
|
e359b7fa00 | ||
|
|
44fc5177d6 | ||
|
|
604a27141f | ||
|
|
fd65a84d7d | ||
|
|
966b389807 | ||
|
|
a6bcce5a63 | ||
|
|
530fbdd282 | ||
|
|
54f1051456 | ||
|
|
d136bf5561 | ||
|
|
5cba948e02 | ||
|
|
ab922f6735 | ||
|
|
d71c87535f | ||
|
|
ce501bd972 | ||
|
|
ec5944f53c | ||
|
|
5e64e0bbaa | ||
|
|
e16f1d732d | ||
|
|
cdacfc946c | ||
|
|
26e854f0a3 | ||
|
|
2bc89364b2 | ||
|
|
e080d2de9b | ||
|
|
ca1262aeb7 | ||
|
|
cbc95e2095 | ||
|
|
9c5051cbf8 | ||
|
|
e6ca3390a2 | ||
|
|
e74b531905 | ||
|
|
01437183ac | ||
|
|
e5ab2ceca3 | ||
|
|
e19f4ddf7c | ||
|
|
4e3a062084 | ||
|
|
96db0ad507 | ||
|
|
6b4bcc074a | ||
|
|
14dd390680 | ||
|
|
3fe8ea8961 | ||
|
|
3ee913ea98 | ||
|
|
d18277653c | ||
|
|
8c478cc330 | ||
|
|
003ffc161b | ||
|
|
74dc0c871b | ||
|
|
c8545dea4d | ||
|
|
e1b8edd444 | ||
|
|
f3996855c3 | ||
|
|
ea17e8ea08 | ||
|
|
00fc313609 | ||
|
|
c72f9abc2b | ||
|
|
6df818503e | ||
|
|
b17a6cc109 | ||
|
|
82d1aed472 | ||
|
|
eb6fc6c140 | ||
|
|
2710406f5f | ||
|
|
a634499423 | ||
|
|
71b3fbaa19 | ||
|
|
c656bb4571 | ||
|
|
6c4e4b8cd8 | ||
|
|
7b1a256f8a | ||
|
|
66f9eaf8c2 | ||
|
|
7fa0ba3355 | ||
|
|
eec9244e4c | ||
|
|
e265e4828e | ||
|
|
ad6e720912 | ||
|
|
70dad8ebb4 | ||
|
|
497b3b3e04 | ||
|
|
891811aa47 | ||
|
|
be9ddaa4c9 | ||
|
|
03494c2915 | ||
|
|
bcf7c247bf |
1
.github/scripts/.Brewfile
vendored
1
.github/scripts/.Brewfile
vendored
@@ -1,6 +1,5 @@
|
|||||||
brew "ccache"
|
brew "ccache"
|
||||||
brew "coreutils"
|
brew "coreutils"
|
||||||
brew "cmake"
|
brew "cmake"
|
||||||
brew "git"
|
|
||||||
brew "jq"
|
brew "jq"
|
||||||
brew "xcbeautify"
|
brew "xcbeautify"
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -16,6 +16,7 @@
|
|||||||
!.cmake-format.json
|
!.cmake-format.json
|
||||||
!.gitattributes
|
!.gitattributes
|
||||||
!.gitignore
|
!.gitignore
|
||||||
|
!.pre-commit-config.yaml
|
||||||
!BUILDING.md
|
!BUILDING.md
|
||||||
!buildspec.json
|
!buildspec.json
|
||||||
!CMakeLists.txt
|
!CMakeLists.txt
|
||||||
@@ -23,6 +24,9 @@
|
|||||||
!LICENSE
|
!LICENSE
|
||||||
!README.md
|
!README.md
|
||||||
|
|
||||||
|
# Exclude .orig leftovers
|
||||||
|
*.orig
|
||||||
|
|
||||||
# Exclude lock files
|
# Exclude lock files
|
||||||
*.lock.json
|
*.lock.json
|
||||||
|
|
||||||
|
|||||||
24
.pre-commit-config.yaml
Normal file
24
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
|
rev: v16.0.6
|
||||||
|
hooks:
|
||||||
|
- id: clang-format
|
||||||
|
args: [-fallback-style=none]
|
||||||
|
types_or: [c++, c]
|
||||||
|
exclude: |
|
||||||
|
(?x)^(
|
||||||
|
deps/.*|
|
||||||
|
tests/catch\.hpp|
|
||||||
|
.*\.mm
|
||||||
|
)$
|
||||||
|
|
||||||
|
- repo: https://github.com/cheshirekow/cmake-format-precommit
|
||||||
|
rev: v0.6.13
|
||||||
|
hooks:
|
||||||
|
- id: cmake-format
|
||||||
|
|
||||||
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
|
rev: v0.3.2
|
||||||
|
hooks:
|
||||||
|
- id: ruff-format
|
||||||
|
types_or: [python]
|
||||||
@@ -128,6 +128,8 @@ target_sources(
|
|||||||
lib/macro/macro-ref.hpp
|
lib/macro/macro-ref.hpp
|
||||||
lib/macro/macro-run-button.cpp
|
lib/macro/macro-run-button.cpp
|
||||||
lib/macro/macro-run-button.hpp
|
lib/macro/macro-run-button.hpp
|
||||||
|
lib/macro/macro-segment-copy-paste.cpp
|
||||||
|
lib/macro/macro-segment-copy-paste.hpp
|
||||||
lib/macro/macro-segment-list.cpp
|
lib/macro/macro-segment-list.cpp
|
||||||
lib/macro/macro-segment-list.hpp
|
lib/macro/macro-segment-list.hpp
|
||||||
lib/macro/macro-segment-selection.cpp
|
lib/macro/macro-segment-selection.cpp
|
||||||
@@ -145,12 +147,16 @@ target_sources(
|
|||||||
# Utility function sources
|
# Utility function sources
|
||||||
target_sources(
|
target_sources(
|
||||||
${LIB_NAME}
|
${LIB_NAME}
|
||||||
PRIVATE lib/utils/action-queue.cpp
|
PRIVATE lib/queue/action-queue.cpp
|
||||||
lib/utils/action-queue.hpp
|
lib/queue/action-queue.hpp
|
||||||
|
lib/queue/action-queue-tab.cpp
|
||||||
|
lib/queue/action-queue-tab.hpp
|
||||||
lib/utils/backup.cpp
|
lib/utils/backup.cpp
|
||||||
lib/utils/backup.hpp
|
lib/utils/backup.hpp
|
||||||
lib/utils/curl-helper.cpp
|
lib/utils/curl-helper.cpp
|
||||||
lib/utils/curl-helper.hpp
|
lib/utils/curl-helper.hpp
|
||||||
|
lib/utils/double-slider.cpp
|
||||||
|
lib/utils/double-slider.hpp
|
||||||
lib/utils/duration-control.cpp
|
lib/utils/duration-control.cpp
|
||||||
lib/utils/duration-control.hpp
|
lib/utils/duration-control.hpp
|
||||||
lib/utils/duration.cpp
|
lib/utils/duration.cpp
|
||||||
@@ -189,6 +195,10 @@ target_sources(
|
|||||||
lib/utils/regex-config.hpp
|
lib/utils/regex-config.hpp
|
||||||
lib/utils/resizing-text-edit.cpp
|
lib/utils/resizing-text-edit.cpp
|
||||||
lib/utils/resizing-text-edit.hpp
|
lib/utils/resizing-text-edit.hpp
|
||||||
|
lib/utils/resource-table.cpp
|
||||||
|
lib/utils/resource-table.hpp
|
||||||
|
lib/utils/resource-table-hotkey-handler.cpp
|
||||||
|
lib/utils/resource-table-hotkey-handler.hpp
|
||||||
lib/utils/scene-selection.cpp
|
lib/utils/scene-selection.cpp
|
||||||
lib/utils/scene-selection.hpp
|
lib/utils/scene-selection.hpp
|
||||||
lib/utils/scene-switch-helpers.cpp
|
lib/utils/scene-switch-helpers.cpp
|
||||||
@@ -199,6 +209,8 @@ target_sources(
|
|||||||
lib/utils/section.hpp
|
lib/utils/section.hpp
|
||||||
lib/utils/selection-helpers.cpp
|
lib/utils/selection-helpers.cpp
|
||||||
lib/utils/selection-helpers.hpp
|
lib/utils/selection-helpers.hpp
|
||||||
|
lib/utils/single-char-selection.cpp
|
||||||
|
lib/utils/single-char-selection.hpp
|
||||||
lib/utils/slider-spinbox.cpp
|
lib/utils/slider-spinbox.cpp
|
||||||
lib/utils/slider-spinbox.hpp
|
lib/utils/slider-spinbox.hpp
|
||||||
lib/utils/source-helpers.cpp
|
lib/utils/source-helpers.cpp
|
||||||
@@ -213,6 +225,8 @@ target_sources(
|
|||||||
lib/utils/switch-button.hpp
|
lib/utils/switch-button.hpp
|
||||||
lib/utils/sync-helpers.cpp
|
lib/utils/sync-helpers.cpp
|
||||||
lib/utils/sync-helpers.hpp
|
lib/utils/sync-helpers.hpp
|
||||||
|
lib/utils/tab-helpers.cpp
|
||||||
|
lib/utils/tab-helpers.hpp
|
||||||
lib/utils/temp-variable.cpp
|
lib/utils/temp-variable.cpp
|
||||||
lib/utils/temp-variable.hpp
|
lib/utils/temp-variable.hpp
|
||||||
lib/utils/ui-helpers.cpp
|
lib/utils/ui-helpers.cpp
|
||||||
@@ -230,6 +244,7 @@ target_sources(
|
|||||||
lib/variables/variable-string.cpp
|
lib/variables/variable-string.cpp
|
||||||
lib/variables/variable-string.hpp
|
lib/variables/variable-string.hpp
|
||||||
lib/variables/variable-tab.cpp
|
lib/variables/variable-tab.cpp
|
||||||
|
lib/variables/variable-tab.hpp
|
||||||
lib/variables/variable-text-edit.cpp
|
lib/variables/variable-text-edit.cpp
|
||||||
lib/variables/variable-text-edit.hpp
|
lib/variables/variable-text-edit.hpp
|
||||||
lib/variables/variable.cpp
|
lib/variables/variable.cpp
|
||||||
@@ -264,6 +279,7 @@ target_include_directories(
|
|||||||
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/lib"
|
PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/lib"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/lib/legacy"
|
"${CMAKE_CURRENT_SOURCE_DIR}/lib/legacy"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/lib/macro"
|
"${CMAKE_CURRENT_SOURCE_DIR}/lib/macro"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/lib/queue"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/lib/utils"
|
"${CMAKE_CURRENT_SOURCE_DIR}/lib/utils"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/lib/variables"
|
"${CMAKE_CURRENT_SOURCE_DIR}/lib/variables"
|
||||||
"${CMAKE_CURRENT_BINARY_DIR}/forms")
|
"${CMAKE_CURRENT_BINARY_DIR}/forms")
|
||||||
|
|||||||
@@ -22,4 +22,5 @@ sudo snap install obs-studio
|
|||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
- If you wish to contribute code to the project, have a look at this [section](BUILDING.md) describing how to compile the plugin.
|
- If you wish to contribute code to the project, have a look at this [section](BUILDING.md) describing how to compile the plugin.
|
||||||
|
- You can optionally use [pre-commit](https://pre-commit.com) to automatically handle formatting.
|
||||||
- If you wish to contribute translations, feel free to submit pull requests for the corresponding files under `data/locale`.
|
- If you wish to contribute translations, feel free to submit pull requests for the corresponding files under `data/locale`.
|
||||||
|
|||||||
@@ -49,7 +49,16 @@ invoke_formatter() {
|
|||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
|
|
||||||
local -a source_files=(src/**/*.(c|cpp|h|hpp|m|mm)(.N))
|
local -a source_files=()
|
||||||
|
for folder ("lib" "module" "plugins" "tests") {
|
||||||
|
source_files+=(${folder}/**/*.(c|cpp|h|hpp)(.N))
|
||||||
|
}
|
||||||
|
|
||||||
|
for file (${source_files}) {
|
||||||
|
if [[ $file == *"catch.hpp" ]]; then
|
||||||
|
source_files=("${source_files[@]/$file}")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
local -a format_args=(-style=file -fallback-style=none)
|
local -a format_args=(-style=file -fallback-style=none)
|
||||||
if (( _loglevel > 2 )) format_args+=(--verbose)
|
if (( _loglevel > 2 )) format_args+=(--verbose)
|
||||||
|
|||||||
@@ -1,19 +1,22 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
defaultLocaleFile = "en-US.ini"
|
defaultLocaleFile = "en-US.ini"
|
||||||
|
|
||||||
|
|
||||||
class localeEntry:
|
class localeEntry:
|
||||||
locale = ""
|
locale = ""
|
||||||
placeholders = []
|
widgetPlaceholders = []
|
||||||
|
qStringArgs = []
|
||||||
|
|
||||||
def __init__(self, locale, widgets) -> None:
|
def __init__(self, locale, widgetPlaceholders, qStringArgs) -> None:
|
||||||
self.locale = locale
|
self.locale = locale
|
||||||
self.placeholders = widgets
|
self.widgetPlaceholders = widgetPlaceholders
|
||||||
|
self.qStringArgs = qStringArgs
|
||||||
|
|
||||||
|
|
||||||
def getNonDefaultLocales(dir):
|
def getNonDefaultLocales(dir):
|
||||||
@@ -22,21 +25,33 @@ def getNonDefaultLocales(dir):
|
|||||||
f = os.path.join(dir, filename)
|
f = os.path.join(dir, filename)
|
||||||
if os.path.isfile(f) and not f.endswith(defaultLocaleFile):
|
if os.path.isfile(f) and not f.endswith(defaultLocaleFile):
|
||||||
files.append(f)
|
files.append(f)
|
||||||
|
|
||||||
return files
|
return files
|
||||||
|
|
||||||
|
|
||||||
def getAllLocaleEntriesWithWidgetPlaceholders(file):
|
def getAllLocaleEntries(file):
|
||||||
localeEntries = []
|
localeEntries = []
|
||||||
with open(file, 'r', encoding='UTF-8') as f:
|
with open(file, "r", encoding="UTF-8") as f:
|
||||||
for line in f.readlines():
|
for line in f.readlines():
|
||||||
widgetPlaceholders = []
|
widgetPlaceholders = []
|
||||||
|
qStringArgs = []
|
||||||
|
|
||||||
|
if line.startswith(";"):
|
||||||
|
continue
|
||||||
|
|
||||||
for word in line.split("{{"):
|
for word in line.split("{{"):
|
||||||
if not "}}" in word:
|
if not "}}" in word:
|
||||||
continue
|
continue
|
||||||
word = "{{" + word[:word.rfind("}}")] + "}}"
|
placeholder = "{{" + word[: word.rfind("}}")] + "}}"
|
||||||
widgetPlaceholders.append(word)
|
widgetPlaceholders.append(placeholder)
|
||||||
localeEntries.append(localeEntry(
|
|
||||||
line.split("=")[0], widgetPlaceholders))
|
for match in re.finditer(r"%\d+", line):
|
||||||
|
qStringArgs.append(match.group(0))
|
||||||
|
|
||||||
|
localeEntries.append(
|
||||||
|
localeEntry(line.split("=")[0], widgetPlaceholders, qStringArgs)
|
||||||
|
)
|
||||||
|
|
||||||
return localeEntries
|
return localeEntries
|
||||||
|
|
||||||
|
|
||||||
@@ -44,47 +59,85 @@ def getLocaleEntryFrom(entry, list):
|
|||||||
for element in list:
|
for element in list:
|
||||||
if element.locale == entry.locale:
|
if element.locale == entry.locale:
|
||||||
return element
|
return element
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def checkWidgetPlacehodlers(file, expectedPlaceholders):
|
def checkLocaleEntries(file, expectedLocaleEntries):
|
||||||
localeEntries = getAllLocaleEntriesWithWidgetPlaceholders(file)
|
localeEntries = getAllLocaleEntries(file)
|
||||||
result = True
|
result = True
|
||||||
|
|
||||||
for localeEntry in localeEntries:
|
for localeEntry in localeEntries:
|
||||||
expectedEntry = getLocaleEntryFrom(localeEntry, expectedPlaceholders)
|
expectedLocaleEntry = getLocaleEntryFrom(localeEntry, expectedLocaleEntries)
|
||||||
if expectedEntry is None:
|
|
||||||
|
if expectedLocaleEntry is None:
|
||||||
|
result = False
|
||||||
print(
|
print(
|
||||||
"WARNING: Locale entry \"{}\" from \"{}\" not found in \"{}\"".format(localeEntry.locale, file, defaultLocaleFile))
|
'ERROR: Locale entry "{}" from "{}" not found in "{}"'.format(
|
||||||
|
localeEntry.locale, file, defaultLocaleFile
|
||||||
|
)
|
||||||
|
)
|
||||||
continue
|
continue
|
||||||
for p in localeEntry.placeholders:
|
|
||||||
if p not in expectedEntry.placeholders:
|
for placeholder in localeEntry.widgetPlaceholders:
|
||||||
print("WARNING: Locale entry \"{}\" from \"{}\" does contain \"{}\" while \"{}\" does not".format(
|
if placeholder not in expectedLocaleEntry.widgetPlaceholders:
|
||||||
localeEntry.locale, file, p, defaultLocaleFile))
|
|
||||||
for p in expectedEntry.placeholders:
|
|
||||||
if p not in localeEntry.placeholders:
|
|
||||||
result = False
|
result = False
|
||||||
print("ERROR: Locale entry \"{}\" from \"{}\" does not contain \"{}\"".format(
|
print(
|
||||||
localeEntry.locale, file, p))
|
'ERROR: Locale entry "{}" from "{}" does contain "{}" widget placeholder while "{}" does not'.format(
|
||||||
|
localeEntry.locale, file, placeholder, defaultLocaleFile
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for placeholder in expectedLocaleEntry.widgetPlaceholders:
|
||||||
|
if placeholder not in localeEntry.widgetPlaceholders:
|
||||||
|
result = False
|
||||||
|
print(
|
||||||
|
'ERROR: Locale entry "{}" from "{}" does not contain "{}" widget placeholder'.format(
|
||||||
|
localeEntry.locale, file, placeholder
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for arg in localeEntry.qStringArgs:
|
||||||
|
if arg not in expectedLocaleEntry.qStringArgs:
|
||||||
|
result = False
|
||||||
|
print(
|
||||||
|
'ERROR: Locale entry "{}" from "{}" does contain "{}" QString arg while "{}" does not'.format(
|
||||||
|
localeEntry.locale, file, arg, defaultLocaleFile
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for arg in expectedLocaleEntry.qStringArgs:
|
||||||
|
if arg not in localeEntry.qStringArgs:
|
||||||
|
result = False
|
||||||
|
print(
|
||||||
|
'ERROR: Locale entry "{}" from "{}" does not contain "{}" QString arg'.format(
|
||||||
|
localeEntry.locale, file, arg
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description='Checks for inconsistencies regarding widget placeholders in the different locale files.')
|
description="Checks for inconsistencies regarding widget placeholders in the different locale files."
|
||||||
parser.add_argument(
|
)
|
||||||
'-p', '--path', help='Path to locale folder', required=True)
|
parser.add_argument("-p", "--path", help="Path to locale folder", required=True)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
placeholders = getAllLocaleEntriesWithWidgetPlaceholders(
|
defaultLocaleEntries = getAllLocaleEntries(
|
||||||
os.path.join(args.path, defaultLocaleFile))
|
os.path.join(args.path, defaultLocaleFile)
|
||||||
|
)
|
||||||
nonDefaultLocales = getNonDefaultLocales(args.path)
|
nonDefaultLocales = getNonDefaultLocales(args.path)
|
||||||
|
|
||||||
result = True
|
result = True
|
||||||
for f in nonDefaultLocales:
|
for file in nonDefaultLocales:
|
||||||
if checkWidgetPlacehodlers(f, placeholders) == False:
|
if checkLocaleEntries(file, defaultLocaleEntries) == False:
|
||||||
result = False
|
result = False
|
||||||
|
|
||||||
if result == False:
|
if result == False:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
print("SUCCESS: No issues found!")
|
print("SUCCESS: No issues found!")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,14 @@ if(NOT DEFINED PLUGIN_BUILD_NUMBER AND EXISTS "${_BUILD_NUMBER_CACHE}")
|
|||||||
file(READ "${_BUILD_NUMBER_CACHE}" PLUGIN_BUILD_NUMBER)
|
file(READ "${_BUILD_NUMBER_CACHE}" PLUGIN_BUILD_NUMBER)
|
||||||
math(EXPR PLUGIN_BUILD_NUMBER "${PLUGIN_BUILD_NUMBER}+1")
|
math(EXPR PLUGIN_BUILD_NUMBER "${PLUGIN_BUILD_NUMBER}+1")
|
||||||
elseif(NOT DEFINED PLUGIN_BUILD_NUMBER)
|
elseif(NOT DEFINED PLUGIN_BUILD_NUMBER)
|
||||||
if($ENV{CI} AND $ENV{GITHUB_RUN_ID})
|
if($ENV{CI})
|
||||||
set(PLUGIN_BUILD_NUMBER "$ENV{GITHUB_RUN_ID}")
|
if($ENV{GITHUB_RUN_ID})
|
||||||
|
set(PLUGIN_BUILD_NUMBER "$ENV{GITHUB_RUN_ID}")
|
||||||
|
elseif($ENV{GITLAB_RUN_ID})
|
||||||
|
set(PLUGIN_BUILD_NUMBER "$ENV{GITLAB_RUN_ID}")
|
||||||
|
else()
|
||||||
|
set(PLUGIN_BUILD_NUMBER "1")
|
||||||
|
endif()
|
||||||
else()
|
else()
|
||||||
set(PLUGIN_BUILD_NUMBER "1")
|
set(PLUGIN_BUILD_NUMBER "1")
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -68,13 +68,21 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL GNU)
|
if(CMAKE_CXX_COMPILER_ID STREQUAL GNU)
|
||||||
|
# Disable warning for https://github.com/WarmUpTill/SceneSwitcher/issues/1091
|
||||||
|
add_compile_options(-Wno-error=psabi)
|
||||||
|
|
||||||
# Disable false-positive warning in GCC 12.1.0 and later
|
# Disable false-positive warning in GCC 12.1.0 and later
|
||||||
add_compile_options(-Wno-error=maybe-uninitialized)
|
if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.1.0)
|
||||||
|
add_compile_options(-Wno-error=maybe-uninitialized)
|
||||||
|
add_compile_options(-Wno-error=stringop-overflow)
|
||||||
|
endif()
|
||||||
|
|
||||||
# Add warning for infinite recursion (added in GCC 12)
|
# Add warning for infinite recursion (added in GCC 12)
|
||||||
if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0.0)
|
if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0.0)
|
||||||
add_compile_options(-Winfinite-recursion)
|
add_compile_options(-Winfinite-recursion)
|
||||||
endif()
|
endif()
|
||||||
|
elseif(CMAKE_CXX_COMPILER_ID STREQUAL Clang)
|
||||||
|
add_compile_options(-Wno-error=null-pointer-subtraction)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Enable compiler and build tracing (requires Ninja generator)
|
# Enable compiler and build tracing (requires Ninja generator)
|
||||||
|
|||||||
@@ -80,8 +80,7 @@ AdvSceneSwitcher.macroTab.runInParallel="Parallel zu anderen Makros ausführen"
|
|||||||
AdvSceneSwitcher.macroTab.onChange="Nur bei Änderung ausführen"
|
AdvSceneSwitcher.macroTab.onChange="Nur bei Änderung ausführen"
|
||||||
AdvSceneSwitcher.macroTab.defaultname="Makro %1"
|
AdvSceneSwitcher.macroTab.defaultname="Makro %1"
|
||||||
AdvSceneSwitcher.macroTab.defaultGroupName="Gruppe %1"
|
AdvSceneSwitcher.macroTab.defaultGroupName="Gruppe %1"
|
||||||
AdvSceneSwitcher.macroTab.exists="Makro-Name existiert bereits"
|
AdvSceneSwitcher.macroTab.removeGroupPopup.text="Sicher, dass \"%1\" und alle zugehörigen Elemente gelöscht werden?"
|
||||||
AdvSceneSwitcher.macroTab.groupDeleteConfirm="Sicher, dass \"%1\" und alle zugehörigen Elemente gelöscht werden?"
|
|
||||||
AdvSceneSwitcher.macroTab.copy="Kopie des aktuellen Makros erstellen"
|
AdvSceneSwitcher.macroTab.copy="Kopie des aktuellen Makros erstellen"
|
||||||
AdvSceneSwitcher.macroTab.group="Ausgewählte Elemente gruppieren"
|
AdvSceneSwitcher.macroTab.group="Ausgewählte Elemente gruppieren"
|
||||||
AdvSceneSwitcher.macroTab.ungroup="Gruppierung ausgewählter Gruppen aufheben"
|
AdvSceneSwitcher.macroTab.ungroup="Gruppierung ausgewählter Gruppen aufheben"
|
||||||
@@ -288,8 +287,8 @@ AdvSceneSwitcher.condition.sceneOrder.entry="Auf{{scenes}}{{sources}}{{condition
|
|||||||
AdvSceneSwitcher.condition.hotkey="Hotkey"
|
AdvSceneSwitcher.condition.hotkey="Hotkey"
|
||||||
AdvSceneSwitcher.condition.hotkey.name="Makro-Trigger-Hotkey"
|
AdvSceneSwitcher.condition.hotkey.name="Makro-Trigger-Hotkey"
|
||||||
AdvSceneSwitcher.condition.hotkey.tip="Hinweis: Die Tastenkombinationen für diesen Hotkey können in den OBS-Einstellungen konfiguriert werden"
|
AdvSceneSwitcher.condition.hotkey.tip="Hinweis: Die Tastenkombinationen für diesen Hotkey können in den OBS-Einstellungen konfiguriert werden"
|
||||||
AdvSceneSwitcher.condition.hotkey.entry.line1="Hotkey ist gedrückt"
|
AdvSceneSwitcher.condition.hotkey.entry.keyState="Hotkey ist{{keyState}}"
|
||||||
AdvSceneSwitcher.condition.hotkey.entry.line2="Name: {{name}}"
|
AdvSceneSwitcher.condition.hotkey.entry.name="Name:{{name}}"
|
||||||
AdvSceneSwitcher.condition.replay="Replay Buffer"
|
AdvSceneSwitcher.condition.replay="Replay Buffer"
|
||||||
AdvSceneSwitcher.condition.replay.state.stopped="Replay Buffer gestoppt"
|
AdvSceneSwitcher.condition.replay.state.stopped="Replay Buffer gestoppt"
|
||||||
AdvSceneSwitcher.condition.replay.state.started="Replay Buffer gestartet"
|
AdvSceneSwitcher.condition.replay.state.started="Replay Buffer gestartet"
|
||||||
@@ -445,7 +444,7 @@ AdvSceneSwitcher.action.filter="Filter"
|
|||||||
AdvSceneSwitcher.action.filter.type.enable="Aktivieren"
|
AdvSceneSwitcher.action.filter.type.enable="Aktivieren"
|
||||||
AdvSceneSwitcher.action.filter.type.disable="Deaktivieren"
|
AdvSceneSwitcher.action.filter.type.disable="Deaktivieren"
|
||||||
AdvSceneSwitcher.action.filter.type.settings="Einstellungen festlegen"
|
AdvSceneSwitcher.action.filter.type.settings="Einstellungen festlegen"
|
||||||
AdvSceneSwitcher.action.filter.entry="Auf{{sources}}{{actions}}{{filters}}{{filters}}{{refresh}}"
|
AdvSceneSwitcher.action.filter.entry="Auf{{sources}}{{actions}}{{filters}}{{filters}}{{refresh}}{{settingsButtons}}"
|
||||||
AdvSceneSwitcher.action.filter.getSettings="Aktuelle Einstellungen abfragen"
|
AdvSceneSwitcher.action.filter.getSettings="Aktuelle Einstellungen abfragen"
|
||||||
AdvSceneSwitcher.action.source="Quelle"
|
AdvSceneSwitcher.action.source="Quelle"
|
||||||
AdvSceneSwitcher.action.source.type.enable="Aktivieren"
|
AdvSceneSwitcher.action.source.type.enable="Aktivieren"
|
||||||
@@ -454,7 +453,6 @@ AdvSceneSwitcher.action.source.type.settings="Einstellungen festlegen"
|
|||||||
AdvSceneSwitcher.action.source.type.refreshSettings="Aktualisieren der Quelleneinstellungen"
|
AdvSceneSwitcher.action.source.type.refreshSettings="Aktualisieren der Quelleneinstellungen"
|
||||||
AdvSceneSwitcher.action.source.type.pressSettingsButton="Drücken der Einstellungstaste"
|
AdvSceneSwitcher.action.source.type.pressSettingsButton="Drücken der Einstellungstaste"
|
||||||
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="Kann verwendet werden, um Browser-, Medien- usw. Quellen zu aktualisieren"
|
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="Kann verwendet werden, um Browser-, Medien- usw. Quellen zu aktualisieren"
|
||||||
AdvSceneSwitcher.action.source.noSettingsButtons="Keine Buttons gefunden!"
|
|
||||||
AdvSceneSwitcher.action.source.warning="Warnung: Das globale Aktivieren und Deaktivieren von Quellen kann nicht über die OBS-Benutzeroberfläche gesteuert werden"
|
AdvSceneSwitcher.action.source.warning="Warnung: Das globale Aktivieren und Deaktivieren von Quellen kann nicht über die OBS-Benutzeroberfläche gesteuert werden"
|
||||||
AdvSceneSwitcher.action.source.getSettings="Aktuelle Einstellungen abfragen"
|
AdvSceneSwitcher.action.source.getSettings="Aktuelle Einstellungen abfragen"
|
||||||
AdvSceneSwitcher.action.media="Medien"
|
AdvSceneSwitcher.action.media="Medien"
|
||||||
@@ -471,7 +469,6 @@ AdvSceneSwitcher.action.macro.type.unpause="Nicht mehr pausieren"
|
|||||||
AdvSceneSwitcher.action.macro.type.resetCounter="Zähler zurücksetzen"
|
AdvSceneSwitcher.action.macro.type.resetCounter="Zähler zurücksetzen"
|
||||||
AdvSceneSwitcher.action.macro.type.run="Aktionen ausführen"
|
AdvSceneSwitcher.action.macro.type.run="Aktionen ausführen"
|
||||||
AdvSceneSwitcher.action.macro.type.stop="Aktionen stoppen"
|
AdvSceneSwitcher.action.macro.type.stop="Aktionen stoppen"
|
||||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
|
||||||
AdvSceneSwitcher.action.pluginState="Plugin-Status"
|
AdvSceneSwitcher.action.pluginState="Plugin-Status"
|
||||||
AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenwechsler stoppen"
|
AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenwechsler stoppen"
|
||||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:"
|
AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:"
|
||||||
@@ -545,7 +542,7 @@ AdvSceneSwitcher.action.sceneCollection="Szenensammlung"
|
|||||||
AdvSceneSwitcher.action.sceneCollection.entry="Aktive Szenensammlung umschalten auf {{sceneCollections}}"
|
AdvSceneSwitcher.action.sceneCollection.entry="Aktive Szenensammlung umschalten auf {{sceneCollections}}"
|
||||||
AdvSceneSwitcher.action.sceneCollection.warning="Hinweis: Alle danach folgenden Aktionen werden nicht ausgeführt, da durch die Änderung der Szenensammlung auch die Einstellungen des Szenenwechslers neu geladen werden.\nDie Szenensammlungsaktion wird ignoriert, solange das Einstellungsfenster geöffnet ist."
|
AdvSceneSwitcher.action.sceneCollection.warning="Hinweis: Alle danach folgenden Aktionen werden nicht ausgeführt, da durch die Änderung der Szenensammlung auch die Einstellungen des Szenenwechslers neu geladen werden.\nDie Szenensammlungsaktion wird ignoriert, solange das Einstellungsfenster geöffnet ist."
|
||||||
AdvSceneSwitcher.action.sequence="Sequenz"
|
AdvSceneSwitcher.action.sequence="Sequenz"
|
||||||
AdvSceneSwitcher.action.sequence.entry="Jedes Mal, wenn diese Aktion ausgeführt wird, wird das nächste Makro in der Liste ausgeführt (pausierte Makros werden ignoriert)"
|
; AdvSceneSwitcher.action.sequence.entry="Jedes Mal, wenn diese Aktion ausgeführt wird, wird das nächste Makro in der Liste ausgeführt (pausierte Makros werden ignoriert)"
|
||||||
AdvSceneSwitcher.action.sequence.status="Zuletzt ausgeführtes Makro: %1 - Nächstes auszuführendes Makro: %2"
|
AdvSceneSwitcher.action.sequence.status="Zuletzt ausgeführtes Makro: %1 - Nächstes auszuführendes Makro: %2"
|
||||||
AdvSceneSwitcher.action.sequence.status.none="keines"
|
AdvSceneSwitcher.action.sequence.status.none="keines"
|
||||||
AdvSceneSwitcher.action.sequence.restart="Neustart am Anfang, wenn das Ende der Liste erreicht ist"
|
AdvSceneSwitcher.action.sequence.restart="Neustart am Anfang, wenn das Ende der Liste erreicht ist"
|
||||||
@@ -571,6 +568,7 @@ AdvSceneSwitcher.action.variable.actionNoVariableSupport="Das Abrufen von Variab
|
|||||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Bedingungen wird nicht unterstützt!"
|
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Bedingungen wird nicht unterstützt!"
|
||||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Aktueller Wert:"
|
AdvSceneSwitcher.action.variable.currentSegmentValue="Aktueller Wert:"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.noSettingsButtons="Keine Buttons gefunden!"
|
||||||
|
|
||||||
; Transition Tab
|
; Transition Tab
|
||||||
AdvSceneSwitcher.transitionTab.title="Szenenübergänge"
|
AdvSceneSwitcher.transitionTab.title="Szenenübergänge"
|
||||||
|
|||||||
@@ -72,14 +72,62 @@ AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="At least one optio
|
|||||||
; Variables Tab
|
; Variables Tab
|
||||||
AdvSceneSwitcher.variableTab.title="Variables"
|
AdvSceneSwitcher.variableTab.title="Variables"
|
||||||
AdvSceneSwitcher.variableTab.help="Variables can be used in many places throughout the plugin.\n\nClick on the highlighted plus symbol to add a new variable."
|
AdvSceneSwitcher.variableTab.help="Variables can be used in many places throughout the plugin.\n\nClick on the highlighted plus symbol to add a new variable."
|
||||||
AdvSceneSwitcher.variableTab.tooltip.variableAddButton="Add new variable"
|
AdvSceneSwitcher.variableTab.variableAddButton.tooltip="Add new variable"
|
||||||
AdvSceneSwitcher.variableTab.tooltip.variableRemoveButton="Remove selected variables"
|
AdvSceneSwitcher.variableTab.variableRemoveButton.tooltip="Remove selected variables"
|
||||||
AdvSceneSwitcher.variableTab.header.name="Name"
|
AdvSceneSwitcher.variableTab.removeSingleVariablePopup.text="Are you sure you want to remove \"%1\"?"
|
||||||
AdvSceneSwitcher.variableTab.header.value="Value"
|
AdvSceneSwitcher.variableTab.removeMultipleVariablesPopup.text="Are you sure you want to remove %1 variables?"
|
||||||
AdvSceneSwitcher.variableTab.header.saveLoadBehavior="Save/Load behavior"
|
AdvSceneSwitcher.variableTab.name.header="Name"
|
||||||
AdvSceneSwitcher.variableTab.header.lastUse="Last used"
|
AdvSceneSwitcher.variableTab.value.header="Value"
|
||||||
AdvSceneSwitcher.variableTab.neverNused="Never"
|
AdvSceneSwitcher.variableTab.saveLoadBehavior.header="Save/Load behavior"
|
||||||
AdvSceneSwitcher.variableTab.lastUsed="%1 seconds ago"
|
AdvSceneSwitcher.variableTab.saveLoadBehavior.text.default="Default to \"%1\""
|
||||||
|
AdvSceneSwitcher.variableTab.lastUsed.header="Last used"
|
||||||
|
AdvSceneSwitcher.variableTab.lastUsed.text="%1 seconds ago"
|
||||||
|
AdvSceneSwitcher.variableTab.lastUsed.text.never="Never"
|
||||||
|
AdvSceneSwitcher.variableTab.lastChanged.header="Last changed"
|
||||||
|
AdvSceneSwitcher.variableTab.lastChanged.text="%1 seconds ago"
|
||||||
|
AdvSceneSwitcher.variableTab.lastChanged.text.none="No change since launch"
|
||||||
|
AdvSceneSwitcher.variableTab.lastChanged.tooltip="Times changed: %1\n\nPrevious value: %2"
|
||||||
|
|
||||||
|
; Action Queue Tab
|
||||||
|
AdvSceneSwitcher.actionQueueTab.title="Action Queues"
|
||||||
|
AdvSceneSwitcher.actionQueueTab.help="Action queues are executed sequentially but in parallel to the reset of the macro system.\nThe first action added to the queue will be the first one to be processed.\n\nClick on the highlighted plus symbol to add a new queue."
|
||||||
|
AdvSceneSwitcher.actionQueueTab.queueAddButton.tooltip="Add new action queue"
|
||||||
|
AdvSceneSwitcher.actionQueueTab.queueRemoveButton.tooltip="Remove selected action queues"
|
||||||
|
AdvSceneSwitcher.actionQueueTab.name.header="Name"
|
||||||
|
AdvSceneSwitcher.actionQueueTab.size.header="Size"
|
||||||
|
AdvSceneSwitcher.actionQueueTab.isRunning.header="Is running"
|
||||||
|
AdvSceneSwitcher.actionQueueTab.runOnStartup.header="Run on startup"
|
||||||
|
AdvSceneSwitcher.actionQueueTab.yes="Yes"
|
||||||
|
AdvSceneSwitcher.actionQueueTab.no="No"
|
||||||
|
AdvSceneSwitcher.actionQueueTab.removeSingleConnectionPopup.text="Are you sure you want to remove \"%1\"?"
|
||||||
|
AdvSceneSwitcher.actionQueueTab.removeMultipleConnectionsPopup.text="Are you sure you want to remove %1 action queues?"
|
||||||
|
|
||||||
|
; Websocket Connections Tab
|
||||||
|
AdvSceneSwitcher.websocketConnectionTab.title="Websocket Connections"
|
||||||
|
AdvSceneSwitcher.websocketConnectionTab.help="Websocket connections can be used to communicate with other OBS instances or programs.\n\nClick on the highlighted plus symbol to add a new connection."
|
||||||
|
AdvSceneSwitcher.websocketConnectionTab.websocketConnectionAddButton.tooltip="Add new webscoket connection"
|
||||||
|
AdvSceneSwitcher.websocketConnectionTab.websocketConnectionRemoveButton.tooltip="Remove selected websocket connections"
|
||||||
|
AdvSceneSwitcher.websocketConnectionTab.name.header="Name"
|
||||||
|
AdvSceneSwitcher.websocketConnectionTab.address.header="Address"
|
||||||
|
AdvSceneSwitcher.websocketConnectionTab.port.header="Port"
|
||||||
|
AdvSceneSwitcher.websocketConnectionTab.protocol.header="Is using OBS protocol?"
|
||||||
|
AdvSceneSwitcher.websocketConnectionTab.protocol.yes="Yes"
|
||||||
|
AdvSceneSwitcher.websocketConnectionTab.protocol.no="No"
|
||||||
|
AdvSceneSwitcher.websocketConnectionTab.removeSingleConnectionPopup.text="Are you sure you want to remove \"%1\"?"
|
||||||
|
AdvSceneSwitcher.websocketConnectionTab.removeMultipleConnectionsPopup.text="Are you sure you want to remove %1 connections?"
|
||||||
|
|
||||||
|
; Twitch Connections Tab
|
||||||
|
AdvSceneSwitcher.twitchConnectionTab.title="Twitch Connections"
|
||||||
|
AdvSceneSwitcher.twitchConnectionTab.help="Twitch connections can be used to use Twitch events as triggers to execute actions or perform actions on the linked Twitch account.\n\nClick on the highlighted plus symbol to add a new connection."
|
||||||
|
AdvSceneSwitcher.twitchConnectionTab.twitchConnectionAddButton.tooltip.tooltip="Add new Twitch connection"
|
||||||
|
AdvSceneSwitcher.twitchConnectionTab.twitchConnectionRemoveButton.tooltip="Remove selected Twitch connections"
|
||||||
|
AdvSceneSwitcher.twitchConnectionTab.name.header="Name"
|
||||||
|
AdvSceneSwitcher.twitchConnectionTab.isValid.header="Is valid?"
|
||||||
|
AdvSceneSwitcher.twitchConnectionTab.permissionCount.header="Number of permissions"
|
||||||
|
AdvSceneSwitcher.twitchConnectionTab.yes="Yes"
|
||||||
|
AdvSceneSwitcher.twitchConnectionTab.no="No"
|
||||||
|
AdvSceneSwitcher.twitchConnectionTab.removeSingleConnectionPopup.text="Are you sure you want to remove \"%1\"?"
|
||||||
|
AdvSceneSwitcher.twitchConnectionTab.removeMultipleConnectionsPopup.text="Are you sure you want to remove %1 Twitch connections?"
|
||||||
|
|
||||||
; Macro Tab
|
; Macro Tab
|
||||||
AdvSceneSwitcher.macroTab.title="Macro"
|
AdvSceneSwitcher.macroTab.title="Macro"
|
||||||
@@ -94,6 +142,7 @@ AdvSceneSwitcher.macroTab.edit.logic="Logic type:"
|
|||||||
AdvSceneSwitcher.macroTab.edit.condition="Condition type:"
|
AdvSceneSwitcher.macroTab.edit.condition="Condition type:"
|
||||||
AdvSceneSwitcher.macroTab.edit.action="Action type:"
|
AdvSceneSwitcher.macroTab.edit.action="Action type:"
|
||||||
AdvSceneSwitcher.macroTab.add="Add new macro"
|
AdvSceneSwitcher.macroTab.add="Add new macro"
|
||||||
|
AdvSceneSwitcher.macroTab.addGroup="Add new macro group"
|
||||||
AdvSceneSwitcher.macroTab.name="Name:"
|
AdvSceneSwitcher.macroTab.name="Name:"
|
||||||
AdvSceneSwitcher.macroTab.run="Run macro"
|
AdvSceneSwitcher.macroTab.run="Run macro"
|
||||||
AdvSceneSwitcher.macroTab.run.tooltip="Run all macro actions regardless of condition.\nIf else actions are available, hold Shift and click the button to execute them instead."
|
AdvSceneSwitcher.macroTab.run.tooltip="Run all macro actions regardless of condition.\nIf else actions are available, hold Shift and click the button to execute them instead."
|
||||||
@@ -103,10 +152,11 @@ AdvSceneSwitcher.macroTab.runInParallel="Run macro in parallel to other macros"
|
|||||||
AdvSceneSwitcher.macroTab.onChange="Perform actions only on condition change"
|
AdvSceneSwitcher.macroTab.onChange="Perform actions only on condition change"
|
||||||
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
||||||
AdvSceneSwitcher.macroTab.defaultGroupName="Group %1"
|
AdvSceneSwitcher.macroTab.defaultGroupName="Group %1"
|
||||||
AdvSceneSwitcher.macroTab.exists="Macro name exists already"
|
AdvSceneSwitcher.macroTab.macroNameExists="The name \"%1\" is already used by a macro."
|
||||||
AdvSceneSwitcher.macroTab.groupDeleteConfirm="Are you sure you want to delete \"%1\" and all its elements?"
|
AdvSceneSwitcher.macroTab.groupNameExists="The name \"%1\" is already used by a macro group."
|
||||||
AdvSceneSwitcher.macroTab.deleteMultipleMacrosConfirmation="Are you sure you want to delete %1 macros?"
|
AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text="Are you sure you want to remove \"%1\"?"
|
||||||
AdvSceneSwitcher.macroTab.deleteSingleMacroConfirmation="Are you sure you want to delete \"%1\"?"
|
AdvSceneSwitcher.macroTab.removeMultipleMacrosPopup.text="Are you sure you want to remove %1 macros/groups?"
|
||||||
|
AdvSceneSwitcher.macroTab.removeGroupPopup.text="Are you sure you want to remove \"%1\" group and all its elements?"
|
||||||
AdvSceneSwitcher.macroTab.contextMenuAdd="Add"
|
AdvSceneSwitcher.macroTab.contextMenuAdd="Add"
|
||||||
AdvSceneSwitcher.macroTab.copy="Duplicate Macro"
|
AdvSceneSwitcher.macroTab.copy="Duplicate Macro"
|
||||||
AdvSceneSwitcher.macroTab.group="Group Selected Macros"
|
AdvSceneSwitcher.macroTab.group="Group Selected Macros"
|
||||||
@@ -115,14 +165,20 @@ AdvSceneSwitcher.macroTab.rename="Rename"
|
|||||||
AdvSceneSwitcher.macroTab.remove="Remove"
|
AdvSceneSwitcher.macroTab.remove="Remove"
|
||||||
AdvSceneSwitcher.macroTab.export="Export"
|
AdvSceneSwitcher.macroTab.export="Export"
|
||||||
AdvSceneSwitcher.macroTab.export.info="Paste the string below into the import dialog to import the selected macros:"
|
AdvSceneSwitcher.macroTab.export.info="Paste the string below into the import dialog to import the selected macros:"
|
||||||
|
AdvSceneSwitcher.macroTab.export.usePlainText="Use plain text"
|
||||||
AdvSceneSwitcher.macroTab.import="Import"
|
AdvSceneSwitcher.macroTab.import="Import"
|
||||||
AdvSceneSwitcher.macroTab.import.info="Paste the export string into the below text box to import macros:"
|
AdvSceneSwitcher.macroTab.import.info="Paste the export string into the below text box to import macros:"
|
||||||
AdvSceneSwitcher.macroTab.import.invalid="Invalid import data provided!"
|
AdvSceneSwitcher.macroTab.import.invalid="Invalid import data provided!"
|
||||||
AdvSceneSwitcher.macroTab.import.nameConflict="Cannot continue importing macro \"%1\" as a macro with the same name already exists!\nDo you want to continue with the import of \"%2\" and choose a new name? (Will be skipped otherwise)"
|
AdvSceneSwitcher.macroTab.import.nameConflict="Cannot continue with import of \"%1\" as the name is already in use!\nDo want to choose a new name for the imported \"%2\"? (It will be skipped otherwise)"
|
||||||
AdvSceneSwitcher.macroTab.expandAll="Expand all"
|
AdvSceneSwitcher.macroTab.expandAll="Expand all"
|
||||||
AdvSceneSwitcher.macroTab.collapseAll="Collapse all"
|
AdvSceneSwitcher.macroTab.collapseAll="Collapse all"
|
||||||
AdvSceneSwitcher.macroTab.maximize="Maximize"
|
AdvSceneSwitcher.macroTab.maximize="Maximize"
|
||||||
AdvSceneSwitcher.macroTab.minimize="Minimize"
|
AdvSceneSwitcher.macroTab.minimize="Minimize"
|
||||||
|
AdvSceneSwitcher.macroTab.segment.useCustomLabel="Use custom label"
|
||||||
|
AdvSceneSwitcher.macroTab.segment.defaultCustomLabel="My label"
|
||||||
|
AdvSceneSwitcher.macroTab.segment.setCustomLabel="Set label ..."
|
||||||
|
AdvSceneSwitcher.macroTab.segment.copy="Copy"
|
||||||
|
AdvSceneSwitcher.macroTab.segment.paste="Paste"
|
||||||
AdvSceneSwitcher.macroTab.highlightSettings="Visual settings"
|
AdvSceneSwitcher.macroTab.highlightSettings="Visual settings"
|
||||||
AdvSceneSwitcher.macroTab.hotkeySettings="Hotkey settings"
|
AdvSceneSwitcher.macroTab.hotkeySettings="Hotkey settings"
|
||||||
AdvSceneSwitcher.macroTab.generalSettings="General settings"
|
AdvSceneSwitcher.macroTab.generalSettings="General settings"
|
||||||
@@ -133,6 +189,7 @@ AdvSceneSwitcher.macroTab.highlightPerformedActions="Highlight recently performe
|
|||||||
AdvSceneSwitcher.macroTab.newMacroRegisterHotkey="Register hotkeys to control the pause state of new macros"
|
AdvSceneSwitcher.macroTab.newMacroRegisterHotkey="Register hotkeys to control the pause state of new macros"
|
||||||
AdvSceneSwitcher.macroTab.currentDisableHotkeys="Register hotkeys to control the pause state of selected macro"
|
AdvSceneSwitcher.macroTab.currentDisableHotkeys="Register hotkeys to control the pause state of selected macro"
|
||||||
AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup="Skip execution of actions of current macro on startup"
|
AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup="Skip execution of actions of current macro on startup"
|
||||||
|
AdvSceneSwitcher.macroTab.currentStopActionsIfNotDone="Stop and rerun actions of the currently selected macro, if the actions are still running, when a new execution is triggered"
|
||||||
AdvSceneSwitcher.macroTab.currentRegisterDock="Register dock widget to control the pause state of selected macro or run it manually"
|
AdvSceneSwitcher.macroTab.currentRegisterDock="Register dock widget to control the pause state of selected macro or run it manually"
|
||||||
AdvSceneSwitcher.macroTab.currentDockAddRunButton="Add button to run the macro"
|
AdvSceneSwitcher.macroTab.currentDockAddRunButton="Add button to run the macro"
|
||||||
AdvSceneSwitcher.macroTab.currentDockAddPauseButton="Add button to pause or unpause the macro"
|
AdvSceneSwitcher.macroTab.currentDockAddPauseButton="Add button to pause or unpause the macro"
|
||||||
@@ -427,10 +484,12 @@ AdvSceneSwitcher.condition.sceneOrder.type.position="Is at position"
|
|||||||
AdvSceneSwitcher.condition.sceneOrder.positionInfo="The position value starts at the bottom with 0 and increases by one for each scene item including the ones in scene groups"
|
AdvSceneSwitcher.condition.sceneOrder.positionInfo="The position value starts at the bottom with 0 and increases by one for each scene item including the ones in scene groups"
|
||||||
AdvSceneSwitcher.condition.sceneOrder.entry="On{{scenes}}{{sources}}{{conditions}}{{sources2}}{{position}}"
|
AdvSceneSwitcher.condition.sceneOrder.entry="On{{scenes}}{{sources}}{{conditions}}{{sources2}}{{position}}"
|
||||||
AdvSceneSwitcher.condition.hotkey="Hotkey"
|
AdvSceneSwitcher.condition.hotkey="Hotkey"
|
||||||
|
AdvSceneSwitcher.condition.hotkey.pressed="pressed"
|
||||||
|
AdvSceneSwitcher.condition.hotkey.released="released"
|
||||||
AdvSceneSwitcher.condition.hotkey.name="Macro trigger hotkey"
|
AdvSceneSwitcher.condition.hotkey.name="Macro trigger hotkey"
|
||||||
AdvSceneSwitcher.condition.hotkey.tip="Note: You can configure the keybindings for this hotkey in the OBS settings window"
|
AdvSceneSwitcher.condition.hotkey.tip="Note: You can configure the keybindings for this hotkey in the OBS settings window"
|
||||||
AdvSceneSwitcher.condition.hotkey.entry.line1="Hotkey is pressed"
|
AdvSceneSwitcher.condition.hotkey.entry.keyState="Hotkey is{{keyState}}"
|
||||||
AdvSceneSwitcher.condition.hotkey.entry.line2="Name:{{name}}"
|
AdvSceneSwitcher.condition.hotkey.entry.name="Name:{{name}}"
|
||||||
AdvSceneSwitcher.condition.replay="Replay buffer"
|
AdvSceneSwitcher.condition.replay="Replay buffer"
|
||||||
AdvSceneSwitcher.condition.replay.state.stopped="Replay buffer stopped"
|
AdvSceneSwitcher.condition.replay.state.stopped="Replay buffer stopped"
|
||||||
AdvSceneSwitcher.condition.replay.state.started="Replay buffer started"
|
AdvSceneSwitcher.condition.replay.state.started="Replay buffer started"
|
||||||
@@ -535,7 +594,7 @@ AdvSceneSwitcher.condition.run="Run"
|
|||||||
AdvSceneSwitcher.condition.run.entry="Process exits before timeout of{{timeout}}seconds"
|
AdvSceneSwitcher.condition.run.entry="Process exits before timeout of{{timeout}}seconds"
|
||||||
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Check for exit code{{exitCode}}"
|
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Check for exit code{{exitCode}}"
|
||||||
AdvSceneSwitcher.condition.midi="MIDI"
|
AdvSceneSwitcher.condition.midi="MIDI"
|
||||||
AdvSceneSwitcher.condition.midi.entry="Mesasge was received from{{device}}which matches:"
|
AdvSceneSwitcher.condition.midi.entry="Message was received from{{device}}which matches:"
|
||||||
AdvSceneSwitcher.condition.midi.entry.listen="Set MIDI message selection to messages incoming on selected device:{{listenButton}}"
|
AdvSceneSwitcher.condition.midi.entry.listen="Set MIDI message selection to messages incoming on selected device:{{listenButton}}"
|
||||||
AdvSceneSwitcher.condition.display="Display"
|
AdvSceneSwitcher.condition.display="Display"
|
||||||
AdvSceneSwitcher.condition.display.type.displayName="Name of connected displays matches"
|
AdvSceneSwitcher.condition.display.type.displayName="Name of connected displays matches"
|
||||||
@@ -615,6 +674,15 @@ AdvSceneSwitcher.condition.queue.type.stopped="Stopped"
|
|||||||
AdvSceneSwitcher.condition.queue.type.size="Size"
|
AdvSceneSwitcher.condition.queue.type.size="Size"
|
||||||
AdvSceneSwitcher.condition.queue.entry.startStop="Queue{{queues}}is{{conditions}}"
|
AdvSceneSwitcher.condition.queue.entry.startStop="Queue{{queues}}is{{conditions}}"
|
||||||
AdvSceneSwitcher.condition.queue.entry.size="Queue{{queues}}{{conditions}}is less than{{size}}"
|
AdvSceneSwitcher.condition.queue.entry.size="Queue{{queues}}{{conditions}}is less than{{size}}"
|
||||||
|
AdvSceneSwitcher.condition.clipboard="Clipboard"
|
||||||
|
AdvSceneSwitcher.condition.clipboard.placeholder="Clipboard text"
|
||||||
|
AdvSceneSwitcher.condition.clipboard.urlTooltip="Depending on the OS files might be represented as URLs also!"
|
||||||
|
AdvSceneSwitcher.condition.clipboard.condition.changed="Clipboard content changed"
|
||||||
|
AdvSceneSwitcher.condition.clipboard.condition.isText="Clipboard contains text"
|
||||||
|
AdvSceneSwitcher.condition.clipboard.condition.isImage="Clipboard contains an image"
|
||||||
|
AdvSceneSwitcher.condition.clipboard.condition.isURL="Clipboard contains an URL"
|
||||||
|
AdvSceneSwitcher.condition.clipboard.condition.matches="Clipboard content matches"
|
||||||
|
AdvSceneSwitcher.condition.clipboard.condition.entry="{{conditions}}{{regex}}{{urlInfo}}"
|
||||||
|
|
||||||
; Macro Actions
|
; Macro Actions
|
||||||
AdvSceneSwitcher.action.scene="Switch scene"
|
AdvSceneSwitcher.action.scene="Switch scene"
|
||||||
@@ -636,6 +704,8 @@ AdvSceneSwitcher.action.audio.type.sourceVolume="Set source volume"
|
|||||||
AdvSceneSwitcher.action.audio.type.masterVolume="Set master volume"
|
AdvSceneSwitcher.action.audio.type.masterVolume="Set master volume"
|
||||||
AdvSceneSwitcher.action.audio.type.syncOffset="Set sync offset"
|
AdvSceneSwitcher.action.audio.type.syncOffset="Set sync offset"
|
||||||
AdvSceneSwitcher.action.audio.type.monitor="Set audio monitoring"
|
AdvSceneSwitcher.action.audio.type.monitor="Set audio monitoring"
|
||||||
|
AdvSceneSwitcher.action.audio.type.enableOnTrack="Enable on audio track"
|
||||||
|
AdvSceneSwitcher.action.audio.type.disableOnTrack="Disable on audio track"
|
||||||
AdvSceneSwitcher.action.audio.type.balance="Set balance"
|
AdvSceneSwitcher.action.audio.type.balance="Set balance"
|
||||||
AdvSceneSwitcher.action.audio.balance.description="Move the slider in the direction of the audio channel you want to focus on."
|
AdvSceneSwitcher.action.audio.balance.description="Move the slider in the direction of the audio channel you want to focus on."
|
||||||
AdvSceneSwitcher.action.audio.fade.type.duration="over a duration of"
|
AdvSceneSwitcher.action.audio.fade.type.duration="over a duration of"
|
||||||
@@ -644,7 +714,7 @@ AdvSceneSwitcher.action.audio.fade.duration="{{fade}}Fade{{fadeTypes}}{{duration
|
|||||||
AdvSceneSwitcher.action.audio.fade.rate="{{fade}}Fade{{fadeTypes}}{{rate}}per second."
|
AdvSceneSwitcher.action.audio.fade.rate="{{fade}}Fade{{fadeTypes}}{{rate}}per second."
|
||||||
AdvSceneSwitcher.action.audio.fade.wait="Wait for fade to complete."
|
AdvSceneSwitcher.action.audio.fade.wait="Wait for fade to complete."
|
||||||
AdvSceneSwitcher.action.audio.fade.abort="Abort already active fade."
|
AdvSceneSwitcher.action.audio.fade.abort="Abort already active fade."
|
||||||
AdvSceneSwitcher.action.audio.entry="{{actions}}{{audioSources}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}"
|
AdvSceneSwitcher.action.audio.entry="{{actions}}{{audioSources}}{{volume}}{{volumeDB}}{{percentDBToggle}}{{syncOffset}}{{monitorTypes}}{{track}}"
|
||||||
AdvSceneSwitcher.action.recording="Recording"
|
AdvSceneSwitcher.action.recording="Recording"
|
||||||
AdvSceneSwitcher.action.recording.type.stop="Stop recording"
|
AdvSceneSwitcher.action.recording.type.stop="Stop recording"
|
||||||
AdvSceneSwitcher.action.recording.type.start="Start recording"
|
AdvSceneSwitcher.action.recording.type.start="Start recording"
|
||||||
@@ -672,7 +742,8 @@ AdvSceneSwitcher.action.streaming.type.username="Set username"
|
|||||||
AdvSceneSwitcher.action.streaming.type.password="Set password"
|
AdvSceneSwitcher.action.streaming.type.password="Set password"
|
||||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||||
AdvSceneSwitcher.action.run="Run"
|
AdvSceneSwitcher.action.run="Run"
|
||||||
AdvSceneSwitcher.action.run.entry.wait="{{wait}}Wait for process exit or at most {{timeout}}"
|
AdvSceneSwitcher.action.run.wait.entry="{{wait}}Wait for process exit or at most {{timeout}}{{waitHelp}}"
|
||||||
|
AdvSceneSwitcher.action.run.wait.help.tooltip="Note that macro properties won't work if you leave this unticked, as the process spawns detached from the rest of logic and there's no control over it."
|
||||||
AdvSceneSwitcher.action.sceneVisibility="Scene item visibility"
|
AdvSceneSwitcher.action.sceneVisibility="Scene item visibility"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Show"
|
AdvSceneSwitcher.action.sceneVisibility.type.show="Show"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
|
AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
|
||||||
@@ -685,9 +756,10 @@ AdvSceneSwitcher.action.filter.type.enable="Enable"
|
|||||||
AdvSceneSwitcher.action.filter.type.disable="Disable"
|
AdvSceneSwitcher.action.filter.type.disable="Disable"
|
||||||
AdvSceneSwitcher.action.filter.type.toggle="Toggle"
|
AdvSceneSwitcher.action.filter.type.toggle="Toggle"
|
||||||
AdvSceneSwitcher.action.filter.type.settings="Set settings"
|
AdvSceneSwitcher.action.filter.type.settings="Set settings"
|
||||||
|
AdvSceneSwitcher.action.filter.type.pressSettingsButton="Press settings button"
|
||||||
AdvSceneSwitcher.action.filter.refresh="Refresh"
|
AdvSceneSwitcher.action.filter.refresh="Refresh"
|
||||||
AdvSceneSwitcher.action.filter.refreshTooltip="Repopulate the filter settings selection with the settings of the filter which's name matches the variable value."
|
AdvSceneSwitcher.action.filter.refreshTooltip="Repopulate the filter settings selection with the settings of the filter which's name matches the variable value."
|
||||||
AdvSceneSwitcher.action.filter.entry="On{{sources}}{{actions}}{{filters}}{{refresh}}"
|
AdvSceneSwitcher.action.filter.entry="On{{sources}}{{actions}}{{filters}}{{refresh}}{{settingsButtons}}"
|
||||||
AdvSceneSwitcher.action.filter.entry.settings="{{settings}}{{settingsInputMethod}}{{settingValue}}{{tempVar}}"
|
AdvSceneSwitcher.action.filter.entry.settings="{{settings}}{{settingsInputMethod}}{{settingValue}}{{tempVar}}"
|
||||||
AdvSceneSwitcher.action.filter.getSettings="Get current settings"
|
AdvSceneSwitcher.action.filter.getSettings="Get current settings"
|
||||||
AdvSceneSwitcher.action.filter.inputMethod.individualManual="Set to fixed value"
|
AdvSceneSwitcher.action.filter.inputMethod.individualManual="Set to fixed value"
|
||||||
@@ -705,7 +777,6 @@ AdvSceneSwitcher.action.source.type.deinterlaceOrder="Set deinterlace field orde
|
|||||||
AdvSceneSwitcher.action.source.type.openInteractionDialog="Open interaction dialog"
|
AdvSceneSwitcher.action.source.type.openInteractionDialog="Open interaction dialog"
|
||||||
AdvSceneSwitcher.action.source.type.openFilterDialog="Open filter dialog"
|
AdvSceneSwitcher.action.source.type.openFilterDialog="Open filter dialog"
|
||||||
AdvSceneSwitcher.action.source.type.openPropertiesDialog="Open properties dialog"
|
AdvSceneSwitcher.action.source.type.openPropertiesDialog="Open properties dialog"
|
||||||
AdvSceneSwitcher.action.source.noSettingsButtons="No buttons found!"
|
|
||||||
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}{{refresh}}"
|
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}{{refresh}}"
|
||||||
AdvSceneSwitcher.action.source.entry.settings="{{settings}}{{settingsInputMethod}}{{settingValue}}{{tempVar}}"
|
AdvSceneSwitcher.action.source.entry.settings="{{settings}}{{settingsInputMethod}}{{settingValue}}{{tempVar}}"
|
||||||
AdvSceneSwitcher.action.source.warning="Warning: Enabling and disabling sources globally cannot be controlled by the OBS UI\nYou might be looking for \"Scene item visibility\""
|
AdvSceneSwitcher.action.source.warning="Warning: Enabling and disabling sources globally cannot be controlled by the OBS UI\nYou might be looking for \"Scene item visibility\""
|
||||||
@@ -743,12 +814,20 @@ AdvSceneSwitcher.action.macro="Macro"
|
|||||||
AdvSceneSwitcher.action.macro.type.pause="Pause"
|
AdvSceneSwitcher.action.macro.type.pause="Pause"
|
||||||
AdvSceneSwitcher.action.macro.type.unpause="Unpause"
|
AdvSceneSwitcher.action.macro.type.unpause="Unpause"
|
||||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter"
|
AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter"
|
||||||
AdvSceneSwitcher.action.macro.type.run="Run actions"
|
AdvSceneSwitcher.action.macro.type.run="Run macro"
|
||||||
|
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Do not consider condition state"
|
||||||
|
AdvSceneSwitcher.action.macro.type.run.conditions.true="Only if conditions evaluate to true"
|
||||||
|
AdvSceneSwitcher.action.macro.type.run.conditions.false="Only if conditions evaluate to false"
|
||||||
|
AdvSceneSwitcher.action.macro.type.run.actionType.regular="actions"
|
||||||
|
AdvSceneSwitcher.action.macro.type.run.actionType.else="else-actions"
|
||||||
|
AdvSceneSwitcher.action.macro.type.run.skipWhenPaused="Skip execution when macro is paused"
|
||||||
AdvSceneSwitcher.action.macro.type.stop="Stop actions"
|
AdvSceneSwitcher.action.macro.type.stop="Stop actions"
|
||||||
AdvSceneSwitcher.action.macro.type.disableAction="Disable action"
|
AdvSceneSwitcher.action.macro.type.disableAction="Disable action"
|
||||||
AdvSceneSwitcher.action.macro.type.enableAction="Enable action"
|
AdvSceneSwitcher.action.macro.type.enableAction="Enable action"
|
||||||
AdvSceneSwitcher.action.macro.type.toggleAction="Toggle action"
|
AdvSceneSwitcher.action.macro.type.toggleAction="Toggle action"
|
||||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
AdvSceneSwitcher.action.macro.entry.run="{{actions}}{{actionTypes}}of{{macros}}"
|
||||||
|
AdvSceneSwitcher.action.macro.entry.run.condition="{{conditionBehaviors}}of{{conditionMacros}}"
|
||||||
|
AdvSceneSwitcher.action.macro.entry.other="{{actions}}{{actionIndex}}{{macros}}"
|
||||||
AdvSceneSwitcher.action.pluginState="Plugin state"
|
AdvSceneSwitcher.action.pluginState="Plugin state"
|
||||||
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
|
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
|
||||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Change the no-match behaviour:"
|
AdvSceneSwitcher.action.pluginState.type.noMatch="Change the no-match behaviour:"
|
||||||
@@ -833,6 +912,7 @@ AdvSceneSwitcher.action.systray.title="Title:"
|
|||||||
AdvSceneSwitcher.action.systray.message="Message:"
|
AdvSceneSwitcher.action.systray.message="Message:"
|
||||||
AdvSceneSwitcher.action.systray.icon="Icon:"
|
AdvSceneSwitcher.action.systray.icon="Icon:"
|
||||||
AdvSceneSwitcher.action.systray.iconHint="Leave blank to use the default icon"
|
AdvSceneSwitcher.action.systray.iconHint="Leave blank to use the default icon"
|
||||||
|
AdvSceneSwitcher.action.systray.disabled="System tray notifications seem to be disabled in the OBS settings!"
|
||||||
AdvSceneSwitcher.action.screenshot="Screenshot"
|
AdvSceneSwitcher.action.screenshot="Screenshot"
|
||||||
AdvSceneSwitcher.action.screenshot.save.default="Default"
|
AdvSceneSwitcher.action.screenshot.save.default="Default"
|
||||||
AdvSceneSwitcher.action.screenshot.save.custom="Custom"
|
AdvSceneSwitcher.action.screenshot.save.custom="Custom"
|
||||||
@@ -893,6 +973,10 @@ AdvSceneSwitcher.action.variable.type.stringLength="Set to length of string"
|
|||||||
AdvSceneSwitcher.action.variable.type.extractJson="Extract json field with name"
|
AdvSceneSwitcher.action.variable.type.extractJson="Extract json field with name"
|
||||||
AdvSceneSwitcher.action.variable.type.setToTempvar="Set to macro property"
|
AdvSceneSwitcher.action.variable.type.setToTempvar="Set to macro property"
|
||||||
AdvSceneSwitcher.action.variable.type.sceneItemName="Set to scene item name at index"
|
AdvSceneSwitcher.action.variable.type.sceneItemName="Set to scene item name at index"
|
||||||
|
AdvSceneSwitcher.action.variable.type.padValue="Pad current value"
|
||||||
|
AdvSceneSwitcher.action.variable.type.truncateValue="Truncate current value"
|
||||||
|
AdvSceneSwitcher.action.variable.truncateOrPadDirection.left="Left"
|
||||||
|
AdvSceneSwitcher.action.variable.truncateOrPadDirection.right="Right"
|
||||||
AdvSceneSwitcher.action.variable.askForValuePromptDefault="Assign value to variable \"%1\":"
|
AdvSceneSwitcher.action.variable.askForValuePromptDefault="Assign value to variable \"%1\":"
|
||||||
AdvSceneSwitcher.action.variable.askForValuePrompt="Assign value to variable:"
|
AdvSceneSwitcher.action.variable.askForValuePrompt="Assign value to variable:"
|
||||||
AdvSceneSwitcher.action.variable.mathExpression.example="( 1 + 2 * 3 ) / 4"
|
AdvSceneSwitcher.action.variable.mathExpression.example="( 1 + 2 * 3 ) / 4"
|
||||||
@@ -904,7 +988,9 @@ AdvSceneSwitcher.action.variable.invalidSelection="Invalid selection!"
|
|||||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Getting variable values from %1 actions is not supported!"
|
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Getting variable values from %1 actions is not supported!"
|
||||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Getting variable values from %1 conditions is not supported!"
|
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Getting variable values from %1 conditions is not supported!"
|
||||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Current value:"
|
AdvSceneSwitcher.action.variable.currentSegmentValue="Current value:"
|
||||||
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{sceneItemIndex}}"
|
AdvSceneSwitcher.action.variable.entry.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}"
|
||||||
|
AdvSceneSwitcher.action.variable.entry.pad="{{actions}}of{{variables}}to length{{stringLength}}by adding{{paddingCharSelection}}to the{{direction}}"
|
||||||
|
AdvSceneSwitcher.action.variable.entry.truncate="{{actions}}of{{variables}}to length{{stringLength}}by removing characters from the{{direction}}"
|
||||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}"
|
AdvSceneSwitcher.action.variable.entry.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}"
|
||||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
|
AdvSceneSwitcher.action.variable.entry.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
|
||||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||||
@@ -1600,6 +1686,15 @@ AdvSceneSwitcher.tempVar.macro.matchedCount.description="The number of macros of
|
|||||||
|
|
||||||
AdvSceneSwitcher.tempVar.process.name="Process name"
|
AdvSceneSwitcher.tempVar.process.name="Process name"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.tempVar.run.process.id="Process ID"
|
||||||
|
AdvSceneSwitcher.tempVar.run.process.id.description="PID of the process assigned by the system."
|
||||||
|
AdvSceneSwitcher.tempVar.run.process.exitCode="Process exit code"
|
||||||
|
AdvSceneSwitcher.tempVar.run.process.exitCode.description="Numeric code with which the process exited. Usually 0 is positive and other values are error codes."
|
||||||
|
AdvSceneSwitcher.tempVar.run.process.stream.output="Process standard output stream"
|
||||||
|
AdvSceneSwitcher.tempVar.run.process.stream.output.description="Full standard output stream, usually numbered 1 and what you see in CLI after running the command."
|
||||||
|
AdvSceneSwitcher.tempVar.run.process.stream.error="Process standard error stream"
|
||||||
|
AdvSceneSwitcher.tempVar.run.process.stream.error.description="Full standard error stream, usually numbered 2."
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.recording.durationSeconds="Recording duration"
|
AdvSceneSwitcher.tempVar.recording.durationSeconds="Recording duration"
|
||||||
AdvSceneSwitcher.tempVar.recording.durationSeconds.description="Recording duration in seconds.\nThis value does not change while the recording is paused and will be reset to zero if the recording is stopped."
|
AdvSceneSwitcher.tempVar.recording.durationSeconds.description="Recording duration in seconds.\nThis value does not change while the recording is paused and will be reset to zero if the recording is stopped."
|
||||||
|
|
||||||
@@ -1631,6 +1726,12 @@ AdvSceneSwitcher.tempVar.streaming.keyframeInterval.description="Stream keyframe
|
|||||||
AdvSceneSwitcher.tempVar.streaming.durationSeconds="Stream duration"
|
AdvSceneSwitcher.tempVar.streaming.durationSeconds="Stream duration"
|
||||||
AdvSceneSwitcher.tempVar.streaming.durationSeconds.description="Seconds passed since the stream was started.\nThis value will be zero if the stream is stopped."
|
AdvSceneSwitcher.tempVar.streaming.durationSeconds.description="Seconds passed since the stream was started.\nThis value will be zero if the stream is stopped."
|
||||||
|
|
||||||
|
AdvSceneSwitcher.tempVar.clipboard.text="Clipboard text"
|
||||||
|
AdvSceneSwitcher.tempVar.clipboard.text.description="The text contained in the clipboard.\nWill be empty if the clipboard does not contain text."
|
||||||
|
|
||||||
|
AdvSceneSwitcher.tempVar.file.content="File content"
|
||||||
|
AdvSceneSwitcher.tempVar.file.date="File modification date"
|
||||||
|
|
||||||
AdvSceneSwitcher.selectScene="--select scene--"
|
AdvSceneSwitcher.selectScene="--select scene--"
|
||||||
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
||||||
AdvSceneSwitcher.selectCurrentScene="Current Scene"
|
AdvSceneSwitcher.selectCurrentScene="Current Scene"
|
||||||
@@ -1656,10 +1757,27 @@ AdvSceneSwitcher.enterText="--enter text--"
|
|||||||
AdvSceneSwitcher.enterURL="--enter URL--"
|
AdvSceneSwitcher.enterURL="--enter URL--"
|
||||||
AdvSceneSwitcher.selectHotkey="--select hotkey--"
|
AdvSceneSwitcher.selectHotkey="--select hotkey--"
|
||||||
AdvSceneSwitcher.selectDisplay="--select display--"
|
AdvSceneSwitcher.selectDisplay="--select display--"
|
||||||
AdvSceneSwitcher.selectSetting="--select setting--"
|
|
||||||
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved"
|
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved"
|
||||||
AdvSceneSwitcher.selectWindowTip="Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB"
|
AdvSceneSwitcher.selectWindowTip="Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.invalid=" (Invalid)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.bool=" (Bool)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.int=" (Int)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.float=" (Float)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.text=" (Text)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.path=" (Path)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.list=" (List)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.color=" (Color)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.button=" (Button)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.font=" (Font)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.font=" (Font)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.editableList=" (Editable list)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.frameRate=" (Frame rate)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.group=" (Group)"
|
||||||
|
AdvSceneSwitcher.settings.suffix.type.colorAlpha=" (Color alpha)"
|
||||||
|
AdvSceneSwitcher.setting.select="--select setting--"
|
||||||
|
|
||||||
|
|
||||||
AdvSceneSwitcher.sceneItemSelection.configure="Configure scene item selection type"
|
AdvSceneSwitcher.sceneItemSelection.configure="Configure scene item selection type"
|
||||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Source name"
|
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Source name"
|
||||||
AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
|
AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
|
||||||
@@ -1703,6 +1821,8 @@ AdvSceneSwitcher.audio.monitor.none="Monitor Off"
|
|||||||
AdvSceneSwitcher.audio.monitor.monitorOnly="Monitor Only (mute output)"
|
AdvSceneSwitcher.audio.monitor.monitorOnly="Monitor Only (mute output)"
|
||||||
AdvSceneSwitcher.audio.monitor.both="Monitor and Output"
|
AdvSceneSwitcher.audio.monitor.both="Monitor and Output"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.noSettingsButtons="No buttons found!"
|
||||||
|
|
||||||
; Legacy tabs below - please don't waste your time adding translations for these :)
|
; Legacy tabs below - please don't waste your time adding translations for these :)
|
||||||
; Transition Tab
|
; Transition Tab
|
||||||
AdvSceneSwitcher.transitionTab.title="Transition"
|
AdvSceneSwitcher.transitionTab.title="Transition"
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ AdvSceneSwitcher.macroTab.run="Ejecutar macro"
|
|||||||
AdvSceneSwitcher.macroTab.runInParallel="Ejecutar macro en paralelo a otras macros"
|
AdvSceneSwitcher.macroTab.runInParallel="Ejecutar macro en paralelo a otras macros"
|
||||||
AdvSceneSwitcher.macroTab.onChange="Realizar acciones solo en el cambio de condición"
|
AdvSceneSwitcher.macroTab.onChange="Realizar acciones solo en el cambio de condición"
|
||||||
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
||||||
AdvSceneSwitcher.macroTab.exists="El nombre de la macro ya existe"
|
|
||||||
AdvSceneSwitcher.macroTab.copy="Crear copia"
|
AdvSceneSwitcher.macroTab.copy="Crear copia"
|
||||||
AdvSceneSwitcher.macroTab.expandAll="Expandir todo"
|
AdvSceneSwitcher.macroTab.expandAll="Expandir todo"
|
||||||
AdvSceneSwitcher.macroTab.collapseAll="Contraer todo"
|
AdvSceneSwitcher.macroTab.collapseAll="Contraer todo"
|
||||||
@@ -239,8 +238,7 @@ AdvSceneSwitcher.condition.sceneOrder.entry="En{{scenes}}{{sources}}{{conditions
|
|||||||
AdvSceneSwitcher.condition.hotkey="Tecla de acceso rápido"
|
AdvSceneSwitcher.condition.hotkey="Tecla de acceso rápido"
|
||||||
AdvSceneSwitcher.condition.hotkey.name="Tecla de acceso directo de activación de macro"
|
AdvSceneSwitcher.condition.hotkey.name="Tecla de acceso directo de activación de macro"
|
||||||
AdvSceneSwitcher.condition.hotkey.tip="Nota: puede configurar las combinaciones de teclas para esta tecla de acceso rápido en la ventana de configuración de OBS"
|
AdvSceneSwitcher.condition.hotkey.tip="Nota: puede configurar las combinaciones de teclas para esta tecla de acceso rápido en la ventana de configuración de OBS"
|
||||||
AdvSceneSwitcher.condition.hotkey.entry.line1="Se presiona la tecla de acceso rápido"
|
AdvSceneSwitcher.condition.hotkey.entry.name="Nombre:{{name}}"
|
||||||
AdvSceneSwitcher.condition.hotkey.entry.line2="Nombre: {{name}}"
|
|
||||||
AdvSceneSwitcher.condition.replay="Búfer de reproducción"
|
AdvSceneSwitcher.condition.replay="Búfer de reproducción"
|
||||||
AdvSceneSwitcher.condition.replay.state.stopped="Búfer de reproducción detenido"
|
AdvSceneSwitcher.condition.replay.state.stopped="Búfer de reproducción detenido"
|
||||||
AdvSceneSwitcher.condition.replay.state.started="Búfer de reproducción iniciado"
|
AdvSceneSwitcher.condition.replay.state.started="Búfer de reproducción iniciado"
|
||||||
@@ -366,7 +364,7 @@ AdvSceneSwitcher.action.filter="Filtro"
|
|||||||
AdvSceneSwitcher.action.filter.type.enable="Habilitar"
|
AdvSceneSwitcher.action.filter.type.enable="Habilitar"
|
||||||
AdvSceneSwitcher.action.filter.type.disable="Deshabilitar"
|
AdvSceneSwitcher.action.filter.type.disable="Deshabilitar"
|
||||||
AdvSceneSwitcher.action.filter.type.settings="Establecer configuración"
|
AdvSceneSwitcher.action.filter.type.settings="Establecer configuración"
|
||||||
AdvSceneSwitcher.action.filter.entry="En{{sources}}{{actions}}{{filters}}{{refresh}}"
|
AdvSceneSwitcher.action.filter.entry="En{{sources}}{{actions}}{{filters}}{{refresh}}{{settingsButtons}}"
|
||||||
AdvSceneSwitcher.action.filter.getSettings="Obtener la configuración actual"
|
AdvSceneSwitcher.action.filter.getSettings="Obtener la configuración actual"
|
||||||
AdvSceneSwitcher.action.source="Fuente"
|
AdvSceneSwitcher.action.source="Fuente"
|
||||||
AdvSceneSwitcher.action.source.type.enable="Habilitar"
|
AdvSceneSwitcher.action.source.type.enable="Habilitar"
|
||||||
@@ -388,7 +386,6 @@ AdvSceneSwitcher.action.macro.type.unpause="Reanudar"
|
|||||||
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
|
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
|
||||||
AdvSceneSwitcher.action.macro.type.run="Ejecutar"
|
AdvSceneSwitcher.action.macro.type.run="Ejecutar"
|
||||||
AdvSceneSwitcher.action.macro.type.stop="Detener"
|
AdvSceneSwitcher.action.macro.type.stop="Detener"
|
||||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
|
||||||
AdvSceneSwitcher.action.pluginState="Estado del complemento"
|
AdvSceneSwitcher.action.pluginState="Estado del complemento"
|
||||||
AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced Scene Switcher"
|
AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced Scene Switcher"
|
||||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:"
|
AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:"
|
||||||
@@ -455,7 +452,7 @@ AdvSceneSwitcher.action.sceneCollection="Colección de escenas"
|
|||||||
AdvSceneSwitcher.action.sceneCollection.entry="Cambiar la colección de escenas activa a {{sceneCollections}}"
|
AdvSceneSwitcher.action.sceneCollection.entry="Cambiar la colección de escenas activa a {{sceneCollections}}"
|
||||||
AdvSceneSwitcher.action.sceneCollection.warning="Nota: Cualquier acción posterior a esta no se ejecutará, ya que la colección de escenas cambiante también volverá a cargar la configuración del conmutador de escenas.\nLa acción de la colección de escenas se ignorará mientras se abra la ventana de configuración".
|
AdvSceneSwitcher.action.sceneCollection.warning="Nota: Cualquier acción posterior a esta no se ejecutará, ya que la colección de escenas cambiante también volverá a cargar la configuración del conmutador de escenas.\nLa acción de la colección de escenas se ignorará mientras se abra la ventana de configuración".
|
||||||
AdvSceneSwitcher.action.sequence="Secuencia"
|
AdvSceneSwitcher.action.sequence="Secuencia"
|
||||||
AdvSceneSwitcher.action.sequence.entry="Cada vez que se realiza esta acción, ejecute la siguiente macro de la lista (las macros en pausa se ignoran)"
|
; AdvSceneSwitcher.action.sequence.entry="Cada vez que se realiza esta acción, ejecute la siguiente macro de la lista (las macros en pausa se ignoran)"
|
||||||
AdvSceneSwitcher.action.sequence.status="Última macro ejecutada: %1 - Siguiente macro a ejecutar: %2"
|
AdvSceneSwitcher.action.sequence.status="Última macro ejecutada: %1 - Siguiente macro a ejecutar: %2"
|
||||||
AdvSceneSwitcher.action.sequence.status.none="ninguno"
|
AdvSceneSwitcher.action.sequence.status.none="ninguno"
|
||||||
AdvSceneSwitcher.action.sequence.restart="Reiniciar desde el principio una vez que se alcance el final de la lista"
|
AdvSceneSwitcher.action.sequence.restart="Reiniciar desde el principio una vez que se alcance el final de la lista"
|
||||||
|
|||||||
@@ -82,10 +82,9 @@ AdvSceneSwitcher.macroTab.runInParallel="Exécuter la macro en parallèle avec d
|
|||||||
AdvSceneSwitcher.macroTab.onChange="Exécuter des actions uniquement en cas de changement de condition"
|
AdvSceneSwitcher.macroTab.onChange="Exécuter des actions uniquement en cas de changement de condition"
|
||||||
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
||||||
AdvSceneSwitcher.macroTab.defaultGroupName="Groupe %1"
|
AdvSceneSwitcher.macroTab.defaultGroupName="Groupe %1"
|
||||||
AdvSceneSwitcher.macroTab.exists="Le nom de la macro existe déjà"
|
AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text="Êtes-vous sûr de vouloir supprimer \"%1\" ?"
|
||||||
AdvSceneSwitcher.macroTab.groupDeleteConfirm="Êtes-vous sûr de vouloir supprimer \"%1\" et tous ses éléments ?"
|
AdvSceneSwitcher.macroTab.removeMultipleMacrosPopup.text="Êtes-vous sûr de vouloir supprimer %1 macros ?"
|
||||||
AdvSceneSwitcher.macroTab.deleteMultipleMacrosConfirmation="Êtes-vous sûr de vouloir supprimer %1 macros ?"
|
AdvSceneSwitcher.macroTab.removeGroupPopup.text="Êtes-vous sûr de vouloir supprimer \"%1\" et tous ses éléments ?"
|
||||||
AdvSceneSwitcher.macroTab.deleteSingleMacroConfirmation="Êtes-vous sûr de vouloir supprimer \"%1\" ?"
|
|
||||||
AdvSceneSwitcher.macroTab.contextMenuAdd="Ajouter"
|
AdvSceneSwitcher.macroTab.contextMenuAdd="Ajouter"
|
||||||
AdvSceneSwitcher.macroTab.copy="Dupliquer la macro"
|
AdvSceneSwitcher.macroTab.copy="Dupliquer la macro"
|
||||||
AdvSceneSwitcher.macroTab.group="Grouper les macros sélectionnées"
|
AdvSceneSwitcher.macroTab.group="Grouper les macros sélectionnées"
|
||||||
@@ -352,8 +351,7 @@ AdvSceneSwitcher.condition.sceneOrder.entry="Sur{{scenes}}{{sources}}{{condition
|
|||||||
AdvSceneSwitcher.condition.hotkey="Raccourci clavier"
|
AdvSceneSwitcher.condition.hotkey="Raccourci clavier"
|
||||||
AdvSceneSwitcher.condition.hotkey.name="Raccourci clavier de déclenchement de macro"
|
AdvSceneSwitcher.condition.hotkey.name="Raccourci clavier de déclenchement de macro"
|
||||||
AdvSceneSwitcher.condition.hotkey.tip="Remarque : Vous pouvez configurer les raccourcis clavier pour ce raccourci dans la fenêtre de paramètres d'OBS"
|
AdvSceneSwitcher.condition.hotkey.tip="Remarque : Vous pouvez configurer les raccourcis clavier pour ce raccourci dans la fenêtre de paramètres d'OBS"
|
||||||
AdvSceneSwitcher.condition.hotkey.entry.line1="Raccourci clavier est enfoncé"
|
AdvSceneSwitcher.condition.hotkey.entry.name="Nom:{{name}}"
|
||||||
AdvSceneSwitcher.condition.hotkey.entry.line2="Nom :{{name}}"
|
|
||||||
AdvSceneSwitcher.condition.replay="Tampon de répétition"
|
AdvSceneSwitcher.condition.replay="Tampon de répétition"
|
||||||
AdvSceneSwitcher.condition.replay.state.stopped="Tampon de répétition arrêté"
|
AdvSceneSwitcher.condition.replay.state.stopped="Tampon de répétition arrêté"
|
||||||
AdvSceneSwitcher.condition.replay.state.started="Tampon de répétition démarré"
|
AdvSceneSwitcher.condition.replay.state.started="Tampon de répétition démarré"
|
||||||
@@ -522,7 +520,7 @@ AdvSceneSwitcher.action.filter.type.enable="Activer"
|
|||||||
AdvSceneSwitcher.action.filter.type.disable="Désactiver"
|
AdvSceneSwitcher.action.filter.type.disable="Désactiver"
|
||||||
AdvSceneSwitcher.action.filter.type.toggle="Basculer"
|
AdvSceneSwitcher.action.filter.type.toggle="Basculer"
|
||||||
AdvSceneSwitcher.action.filter.type.settings="Définir les paramètres"
|
AdvSceneSwitcher.action.filter.type.settings="Définir les paramètres"
|
||||||
AdvSceneSwitcher.action.filter.entry="Sur{{sources}}{{actions}}{{filters}}{{refresh}}"
|
AdvSceneSwitcher.action.filter.entry="Sur{{sources}}{{actions}}{{filters}}{{refresh}}{{settingsButtons}}"
|
||||||
AdvSceneSwitcher.action.filter.getSettings="Obtenir les paramètres actuels"
|
AdvSceneSwitcher.action.filter.getSettings="Obtenir les paramètres actuels"
|
||||||
AdvSceneSwitcher.action.source="Source"
|
AdvSceneSwitcher.action.source="Source"
|
||||||
AdvSceneSwitcher.action.source.type.enable="Activer"
|
AdvSceneSwitcher.action.source.type.enable="Activer"
|
||||||
@@ -534,7 +532,6 @@ AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="Peut être utilisé
|
|||||||
AdvSceneSwitcher.action.source.type.deinterlaceMode="Définir le mode de désentrelacement"
|
AdvSceneSwitcher.action.source.type.deinterlaceMode="Définir le mode de désentrelacement"
|
||||||
AdvSceneSwitcher.action.source.type.deinterlaceOrder="Définir l'ordre de désentrelacement des champs"
|
AdvSceneSwitcher.action.source.type.deinterlaceOrder="Définir l'ordre de désentrelacement des champs"
|
||||||
AdvSceneSwitcher.action.source.type.openInteractionDialog="Ouvrir la boîte de dialogue d'interaction"
|
AdvSceneSwitcher.action.source.type.openInteractionDialog="Ouvrir la boîte de dialogue d'interaction"
|
||||||
AdvSceneSwitcher.action.source.noSettingsButtons="Aucun bouton trouvé !"
|
|
||||||
AdvSceneSwitcher.action.source.warning="Avertissement : Activer et désactiver les sources globalement ne peut pas être contrôlé par l'interface utilisateur d'OBS\nVous pourriez rechercher \"Visibilité de l'élément de scène\""
|
AdvSceneSwitcher.action.source.warning="Avertissement : Activer et désactiver les sources globalement ne peut pas être contrôlé par l'interface utilisateur d'OBS\nVous pourriez rechercher \"Visibilité de l'élément de scène\""
|
||||||
AdvSceneSwitcher.action.source.getSettings="Obtenir les paramètres actuels"
|
AdvSceneSwitcher.action.source.getSettings="Obtenir les paramètres actuels"
|
||||||
AdvSceneSwitcher.action.source.deinterlaceMode.disable="Désactiver"
|
AdvSceneSwitcher.action.source.deinterlaceMode.disable="Désactiver"
|
||||||
@@ -660,7 +657,7 @@ AdvSceneSwitcher.action.sceneCollection="Collection de scènes"
|
|||||||
AdvSceneSwitcher.action.sceneCollection.entry="Changer la collection de scènes active vers{{sceneCollections}}"
|
AdvSceneSwitcher.action.sceneCollection.entry="Changer la collection de scènes active vers{{sceneCollections}}"
|
||||||
AdvSceneSwitcher.action.sceneCollection.warning="Note : Toutes les actions suivantes ne seront pas exécutées car le changement de collection de scènes rechargera également les paramètres du commutateur de scènes. L'action de collection de scènes sera ignorée lorsque la fenêtre des paramètres est ouverte."
|
AdvSceneSwitcher.action.sceneCollection.warning="Note : Toutes les actions suivantes ne seront pas exécutées car le changement de collection de scènes rechargera également les paramètres du commutateur de scènes. L'action de collection de scènes sera ignorée lorsque la fenêtre des paramètres est ouverte."
|
||||||
AdvSceneSwitcher.action.sequence="Séquence"
|
AdvSceneSwitcher.action.sequence="Séquence"
|
||||||
AdvSceneSwitcher.action.sequence.entry="Chaque fois que cette action est effectuée, exécutez le macro suivant dans la liste (les macros en pause sont ignorés)"
|
; AdvSceneSwitcher.action.sequence.entry="Chaque fois que cette action est effectuée, exécutez le macro suivant dans la liste (les macros en pause sont ignorés)"
|
||||||
AdvSceneSwitcher.action.sequence.status="Dernier macro exécuté : %1 - Prochain macro à exécuter : %2"
|
AdvSceneSwitcher.action.sequence.status="Dernier macro exécuté : %1 - Prochain macro à exécuter : %2"
|
||||||
AdvSceneSwitcher.action.sequence.status.none="aucun"
|
AdvSceneSwitcher.action.sequence.status.none="aucun"
|
||||||
AdvSceneSwitcher.action.sequence.restart="Recommencer depuis le début une fois la fin de la liste atteinte"
|
AdvSceneSwitcher.action.sequence.restart="Recommencer depuis le début une fois la fin de la liste atteinte"
|
||||||
@@ -739,6 +736,8 @@ AdvSceneSwitcher.action.twitch.type.channel.info.category.set="Définir la caté
|
|||||||
AdvSceneSwitcher.action.twitch.type.commercial.start="Démarrer une publicité d'une durée de"
|
AdvSceneSwitcher.action.twitch.type.commercial.start="Démarrer une publicité d'une durée de"
|
||||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Impossible de sélectionner une catégorie sans avoir d'abord sélectionné un compte Twitch !"
|
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Impossible de sélectionner une catégorie sans avoir d'abord sélectionné un compte Twitch !"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.noSettingsButtons="Aucun bouton trouvé !"
|
||||||
|
|
||||||
; Transition Tab
|
; Transition Tab
|
||||||
AdvSceneSwitcher.transitionTab.title="Transition"
|
AdvSceneSwitcher.transitionTab.title="Transition"
|
||||||
AdvSceneSwitcher.transitionTab.transitionForAToB="Utiliser une transition pour le passage automatisé de la scène A à la scène B"
|
AdvSceneSwitcher.transitionTab.transitionForAToB="Utiliser une transition pour le passage automatisé de la scène A à la scène B"
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ AdvSceneSwitcher.macroTab.edit.action="Тип действия:"
|
|||||||
AdvSceneSwitcher.macroTab.add="Добавить новый макрос"
|
AdvSceneSwitcher.macroTab.add="Добавить новый макрос"
|
||||||
AdvSceneSwitcher.macroTab.name="Имя:"
|
AdvSceneSwitcher.macroTab.name="Имя:"
|
||||||
AdvSceneSwitcher.macroTab.defaultname="Макрос %1"
|
AdvSceneSwitcher.macroTab.defaultname="Макрос %1"
|
||||||
AdvSceneSwitcher.macroTab.exists="Имя макроса уже существует"
|
|
||||||
AdvSceneSwitcher.macroTab.copy="Создать копию"
|
AdvSceneSwitcher.macroTab.copy="Создать копию"
|
||||||
; Macro Logic
|
; Macro Logic
|
||||||
AdvSceneSwitcher.logic.none="Игнорировать вход"
|
AdvSceneSwitcher.logic.none="Игнорировать вход"
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ AdvSceneSwitcher.macroTab.run="Makro Çalıştırma"
|
|||||||
AdvSceneSwitcher.macroTab.runInParallel="Makroyu diğer makrolara paralel olarak çalıştırın"
|
AdvSceneSwitcher.macroTab.runInParallel="Makroyu diğer makrolara paralel olarak çalıştırın"
|
||||||
AdvSceneSwitcher.macroTab.onChange="Eylemleri yalnızca koşul değişikliğinde gerçekleştirin"
|
AdvSceneSwitcher.macroTab.onChange="Eylemleri yalnızca koşul değişikliğinde gerçekleştirin"
|
||||||
AdvSceneSwitcher.macroTab.defaultname="Makro %1"
|
AdvSceneSwitcher.macroTab.defaultname="Makro %1"
|
||||||
AdvSceneSwitcher.macroTab.exists="Macro adı zaten mevcut"
|
|
||||||
AdvSceneSwitcher.macroTab.copy="Kopya oluştur"
|
AdvSceneSwitcher.macroTab.copy="Kopya oluştur"
|
||||||
AdvSceneSwitcher.macroTab.expandAll="Hepsini Genişlet"
|
AdvSceneSwitcher.macroTab.expandAll="Hepsini Genişlet"
|
||||||
AdvSceneSwitcher.macroTab.collapseAll="Hepsini Küçült"
|
AdvSceneSwitcher.macroTab.collapseAll="Hepsini Küçült"
|
||||||
@@ -296,7 +295,7 @@ AdvSceneSwitcher.action.filter="Filtrele"
|
|||||||
AdvSceneSwitcher.action.filter.type.enable="Etkin"
|
AdvSceneSwitcher.action.filter.type.enable="Etkin"
|
||||||
AdvSceneSwitcher.action.filter.type.disable="Etkisiz"
|
AdvSceneSwitcher.action.filter.type.disable="Etkisiz"
|
||||||
AdvSceneSwitcher.action.filter.type.settings="Ayarları yap"
|
AdvSceneSwitcher.action.filter.type.settings="Ayarları yap"
|
||||||
AdvSceneSwitcher.action.filter.entry="Açık{{sources}}{{actions}}{{filters}}{{refresh}}"
|
AdvSceneSwitcher.action.filter.entry="Açık{{sources}}{{actions}}{{filters}}{{refresh}}{{settingsButtons}}"
|
||||||
AdvSceneSwitcher.action.filter.getSettings="Mevcut ayarları al"
|
AdvSceneSwitcher.action.filter.getSettings="Mevcut ayarları al"
|
||||||
AdvSceneSwitcher.action.source="Kaynak"
|
AdvSceneSwitcher.action.source="Kaynak"
|
||||||
AdvSceneSwitcher.action.source.type.enable="Etkin"
|
AdvSceneSwitcher.action.source.type.enable="Etkin"
|
||||||
@@ -316,7 +315,6 @@ AdvSceneSwitcher.action.macro.type.pause="Duraklat"
|
|||||||
AdvSceneSwitcher.action.macro.type.unpause="Duraklatma"
|
AdvSceneSwitcher.action.macro.type.unpause="Duraklatma"
|
||||||
AdvSceneSwitcher.action.macro.type.resetCounter="Sayacı sıfırla"
|
AdvSceneSwitcher.action.macro.type.resetCounter="Sayacı sıfırla"
|
||||||
AdvSceneSwitcher.action.macro.type.run="Çalıştır"
|
AdvSceneSwitcher.action.macro.type.run="Çalıştır"
|
||||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
|
||||||
AdvSceneSwitcher.action.pluginState="Eklenti durumu"
|
AdvSceneSwitcher.action.pluginState="Eklenti durumu"
|
||||||
AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisini durdurun"
|
AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisini durdurun"
|
||||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:"
|
AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:"
|
||||||
|
|||||||
@@ -81,10 +81,9 @@ AdvSceneSwitcher.macroTab.runInParallel="与其他宏同时运行宏"
|
|||||||
AdvSceneSwitcher.macroTab.onChange="仅在条件更改时执行操作"
|
AdvSceneSwitcher.macroTab.onChange="仅在条件更改时执行操作"
|
||||||
AdvSceneSwitcher.macroTab.defaultname="宏 %1"
|
AdvSceneSwitcher.macroTab.defaultname="宏 %1"
|
||||||
AdvSceneSwitcher.macroTab.defaultGroupName="组 %1"
|
AdvSceneSwitcher.macroTab.defaultGroupName="组 %1"
|
||||||
AdvSceneSwitcher.macroTab.exists="宏名称已存在"
|
AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text="你确定你要删除 \"%1\"?"
|
||||||
AdvSceneSwitcher.macroTab.groupDeleteConfirm="您确定要删除 \"%1\"及其所有元素吗?"
|
AdvSceneSwitcher.macroTab.removeMultipleMacrosPopup.text="您确定要删除 %1 宏吗?"
|
||||||
AdvSceneSwitcher.macroTab.deleteMultipleMacrosConfirmation="您确定要删除 %1 宏吗?"
|
AdvSceneSwitcher.macroTab.removeGroupPopup.text="您确定要删除 \"%1\"及其所有元素吗?"
|
||||||
AdvSceneSwitcher.macroTab.deleteSingleMacroConfirmation="你确定你要删除 \"%1\"?"
|
|
||||||
AdvSceneSwitcher.macroTab.contextMenuAdd="增加"
|
AdvSceneSwitcher.macroTab.contextMenuAdd="增加"
|
||||||
AdvSceneSwitcher.macroTab.copy="创建副本"
|
AdvSceneSwitcher.macroTab.copy="创建副本"
|
||||||
AdvSceneSwitcher.macroTab.group="对选定的宏进行分组"
|
AdvSceneSwitcher.macroTab.group="对选定的宏进行分组"
|
||||||
@@ -333,8 +332,7 @@ AdvSceneSwitcher.condition.sceneOrder.entry="在 {{scenes}} {{sources}} {{condit
|
|||||||
AdvSceneSwitcher.condition.hotkey="热键"
|
AdvSceneSwitcher.condition.hotkey="热键"
|
||||||
AdvSceneSwitcher.condition.hotkey.name="宏触发热键"
|
AdvSceneSwitcher.condition.hotkey.name="宏触发热键"
|
||||||
AdvSceneSwitcher.condition.hotkey.tip="注意:您可以在OBS设置窗口中为此热键配置按键绑定"
|
AdvSceneSwitcher.condition.hotkey.tip="注意:您可以在OBS设置窗口中为此热键配置按键绑定"
|
||||||
AdvSceneSwitcher.condition.hotkey.entry.line1="热键被按下"
|
AdvSceneSwitcher.condition.hotkey.entry.name="名称:{{name}}"
|
||||||
AdvSceneSwitcher.condition.hotkey.entry.line2="名称: {{name}}"
|
|
||||||
AdvSceneSwitcher.condition.replay="回放缓存"
|
AdvSceneSwitcher.condition.replay="回放缓存"
|
||||||
AdvSceneSwitcher.condition.replay.state.stopped="回放缓存已停止"
|
AdvSceneSwitcher.condition.replay.state.stopped="回放缓存已停止"
|
||||||
AdvSceneSwitcher.condition.replay.state.started="回放缓存已启动"
|
AdvSceneSwitcher.condition.replay.state.started="回放缓存已启动"
|
||||||
@@ -501,7 +499,7 @@ AdvSceneSwitcher.action.filter="滤镜"
|
|||||||
AdvSceneSwitcher.action.filter.type.enable="开启"
|
AdvSceneSwitcher.action.filter.type.enable="开启"
|
||||||
AdvSceneSwitcher.action.filter.type.disable="关闭"
|
AdvSceneSwitcher.action.filter.type.disable="关闭"
|
||||||
AdvSceneSwitcher.action.filter.type.settings="参数设置"
|
AdvSceneSwitcher.action.filter.type.settings="参数设置"
|
||||||
AdvSceneSwitcher.action.filter.entry="置{{sources}}{{actions}}{{filters}}{{refresh}}"
|
AdvSceneSwitcher.action.filter.entry="置{{sources}}{{actions}}{{filters}}{{refresh}}{{settingsButtons}}"
|
||||||
AdvSceneSwitcher.action.filter.getSettings="获取当前设置"
|
AdvSceneSwitcher.action.filter.getSettings="获取当前设置"
|
||||||
AdvSceneSwitcher.action.source="源"
|
AdvSceneSwitcher.action.source="源"
|
||||||
AdvSceneSwitcher.action.source.type.enable="启用"
|
AdvSceneSwitcher.action.source.type.enable="启用"
|
||||||
@@ -510,7 +508,6 @@ AdvSceneSwitcher.action.source.type.settings="配置设置"
|
|||||||
AdvSceneSwitcher.action.source.type.refreshSettings="刷新源设置"
|
AdvSceneSwitcher.action.source.type.refreshSettings="刷新源设置"
|
||||||
AdvSceneSwitcher.action.source.type.pressSettingsButton="按下设置按钮"
|
AdvSceneSwitcher.action.source.type.pressSettingsButton="按下设置按钮"
|
||||||
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="可用于刷新浏览器、媒体、源、etc"
|
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="可用于刷新浏览器、媒体、源、etc"
|
||||||
AdvSceneSwitcher.action.source.noSettingsButtons="未找到按钮!"
|
|
||||||
AdvSceneSwitcher.action.source.warning="警告:OBS UI无法控制全局启用和禁用源,注意,通过这个设置禁用,我测试,你必须通过这个在启用才行,不然点击小眼睛你无法显示!"
|
AdvSceneSwitcher.action.source.warning="警告:OBS UI无法控制全局启用和禁用源,注意,通过这个设置禁用,我测试,你必须通过这个在启用才行,不然点击小眼睛你无法显示!"
|
||||||
AdvSceneSwitcher.action.source.getSettings="获取当前设置"
|
AdvSceneSwitcher.action.source.getSettings="获取当前设置"
|
||||||
AdvSceneSwitcher.action.media="媒体"
|
AdvSceneSwitcher.action.media="媒体"
|
||||||
@@ -527,7 +524,6 @@ AdvSceneSwitcher.action.macro.type.unpause="取消暂停"
|
|||||||
AdvSceneSwitcher.action.macro.type.resetCounter="复位计数器"
|
AdvSceneSwitcher.action.macro.type.resetCounter="复位计数器"
|
||||||
AdvSceneSwitcher.action.macro.type.run="运行操作"
|
AdvSceneSwitcher.action.macro.type.run="运行操作"
|
||||||
AdvSceneSwitcher.action.macro.type.stop="停止操作"
|
AdvSceneSwitcher.action.macro.type.stop="停止操作"
|
||||||
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
|
|
||||||
AdvSceneSwitcher.action.pluginState="插件状态"
|
AdvSceneSwitcher.action.pluginState="插件状态"
|
||||||
AdvSceneSwitcher.action.pluginState.type.stop="停止高级场景切换插件"
|
AdvSceneSwitcher.action.pluginState.type.stop="停止高级场景切换插件"
|
||||||
AdvSceneSwitcher.action.pluginState.type.noMatch="没有匹配项时:"
|
AdvSceneSwitcher.action.pluginState.type.noMatch="没有匹配项时:"
|
||||||
@@ -607,7 +603,7 @@ AdvSceneSwitcher.action.sceneCollection="场景集合"
|
|||||||
AdvSceneSwitcher.action.sceneCollection.entry="将活动场景集合切换到 {{sceneCollections}}"
|
AdvSceneSwitcher.action.sceneCollection.entry="将活动场景集合切换到 {{sceneCollections}}"
|
||||||
AdvSceneSwitcher.action.sceneCollection.warning="注意:在此之后的任何操作都不会执行,因为更改场景集合也会重新加载场景切换器设置。\n打开“设置”窗口时,场景采集操作将被忽略."
|
AdvSceneSwitcher.action.sceneCollection.warning="注意:在此之后的任何操作都不会执行,因为更改场景集合也会重新加载场景切换器设置。\n打开“设置”窗口时,场景采集操作将被忽略."
|
||||||
AdvSceneSwitcher.action.sequence="场景序列"
|
AdvSceneSwitcher.action.sequence="场景序列"
|
||||||
AdvSceneSwitcher.action.sequence.entry="每次执行此操作时,运行列表中的下一个宏(暂停的宏将被忽略)"
|
; AdvSceneSwitcher.action.sequence.entry="每次执行此操作时,运行列表中的下一个宏(暂停的宏将被忽略)"
|
||||||
AdvSceneSwitcher.action.sequence.status="上次执行的宏:%1 - 要执行的下一个宏: %2"
|
AdvSceneSwitcher.action.sequence.status="上次执行的宏:%1 - 要执行的下一个宏: %2"
|
||||||
AdvSceneSwitcher.action.sequence.status.none="无"
|
AdvSceneSwitcher.action.sequence.status.none="无"
|
||||||
AdvSceneSwitcher.action.sequence.restart="到达列表末尾后,从开头重新启动"
|
AdvSceneSwitcher.action.sequence.restart="到达列表末尾后,从开头重新启动"
|
||||||
@@ -662,6 +658,8 @@ AdvSceneSwitcher.action.midi.entry="发送消息到 {{device}}:"
|
|||||||
AdvSceneSwitcher.action.midi.entry.listen="将MIDI消息选择设置为 {{listenDevices}} 上传入的消息: {{listenButton}}"
|
AdvSceneSwitcher.action.midi.entry.listen="将MIDI消息选择设置为 {{listenDevices}} 上传入的消息: {{listenButton}}"
|
||||||
AdvSceneSwitcher.action.osc="打开声音控制"
|
AdvSceneSwitcher.action.osc="打开声音控制"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.noSettingsButtons="未找到按钮!"
|
||||||
|
|
||||||
; Transition Tab
|
; Transition Tab
|
||||||
AdvSceneSwitcher.transitionTab.title="转场特效"
|
AdvSceneSwitcher.transitionTab.title="转场特效"
|
||||||
AdvSceneSwitcher.transitionTab.transitionForAToB="当自动从场景A切换到场景B时使用的转场特效"
|
AdvSceneSwitcher.transitionTab.transitionForAToB="当自动从场景A切换到场景B时使用的转场特效"
|
||||||
|
|||||||
@@ -902,6 +902,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="runMacroInParallel">
|
<widget class="QCheckBox" name="runMacroInParallel">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>AdvSceneSwitcher.macroTab.runInParallel</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
@@ -922,6 +925,9 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="runMacroOnChange">
|
<widget class="QCheckBox" name="runMacroOnChange">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>AdvSceneSwitcher.macroTab.onChange</string>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
@@ -1596,104 +1602,6 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="variableTab">
|
|
||||||
<attribute name="title">
|
|
||||||
<string>AdvSceneSwitcher.variableTab.title</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_33">
|
|
||||||
<item>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_25">
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QTableWidget" name="variables">
|
|
||||||
<property name="editTriggers">
|
|
||||||
<set>QAbstractItemView::NoEditTriggers</set>
|
|
||||||
</property>
|
|
||||||
<property name="selectionBehavior">
|
|
||||||
<enum>QAbstractItemView::SelectRows</enum>
|
|
||||||
</property>
|
|
||||||
<property name="showGrid">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="cornerButtonEnabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<attribute name="verticalHeaderVisible">
|
|
||||||
<bool>false</bool>
|
|
||||||
</attribute>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="variablesHelp">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.variableTab.help</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignCenter</set>
|
|
||||||
</property>
|
|
||||||
<property name="wordWrap">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_30">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="variableAdd">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>22</width>
|
|
||||||
<height>22</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>AdvSceneSwitcher.variableTab.tooltip.variableAddButton</string>
|
|
||||||
</property>
|
|
||||||
<property name="flat">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="themeID" stdset="0">
|
|
||||||
<string notr="true">addIconSmall</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="variableRemove">
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>22</width>
|
|
||||||
<height>22</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>AdvSceneSwitcher.variableTab.tooltip.variableRemoveButton</string>
|
|
||||||
</property>
|
|
||||||
<property name="flat">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="themeID" stdset="0">
|
|
||||||
<string notr="true">removeIconSmall</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_211">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="networkTab">
|
<widget class="QWidget" name="networkTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>AdvSceneSwitcher.networkTab.title</string>
|
<string>AdvSceneSwitcher.networkTab.title</string>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "status-control.hpp"
|
#include "status-control.hpp"
|
||||||
#include "switcher-data.hpp"
|
#include "switcher-data.hpp"
|
||||||
#include "ui-helpers.hpp"
|
#include "ui-helpers.hpp"
|
||||||
|
#include "tab-helpers.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ AdvSceneSwitcher::~AdvSceneSwitcher()
|
|||||||
{
|
{
|
||||||
if (switcher) {
|
if (switcher) {
|
||||||
switcher->settingsWindowOpened = false;
|
switcher->settingsWindowOpened = false;
|
||||||
switcher->lastOpenedTab = ui->tabWidget->currentIndex();
|
SaveLastOpenedTab(ui->tabWidget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,11 +113,11 @@ void AdvSceneSwitcher::LoadUI()
|
|||||||
SetupSceneGroupTab();
|
SetupSceneGroupTab();
|
||||||
SetupTriggerTab();
|
SetupTriggerTab();
|
||||||
SetupMacroTab();
|
SetupMacroTab();
|
||||||
SetupVariableTab();
|
SetupOtherTabs(ui->tabWidget);
|
||||||
|
|
||||||
SetDeprecationWarnings();
|
SetDeprecationWarnings();
|
||||||
SetTabOrder();
|
SetTabOrder(ui->tabWidget);
|
||||||
SetCurrentTab();
|
SetCurrentTab(ui->tabWidget);
|
||||||
RestoreWindowGeo();
|
RestoreWindowGeo();
|
||||||
CheckFirstTimeSetup();
|
CheckFirstTimeSetup();
|
||||||
|
|
||||||
@@ -135,6 +136,17 @@ bool AdvSceneSwitcher::eventFilter(QObject *obj, QEvent *event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SetElseActionsStateToVisible();
|
SetElseActionsStateToVisible();
|
||||||
|
} else if (eventType == QEvent::KeyPress) {
|
||||||
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||||
|
auto pressedKey = keyEvent->key();
|
||||||
|
|
||||||
|
if (obj == ui->macros && ui->macros->isVisible()) {
|
||||||
|
if (pressedKey == Qt::Key_F2) {
|
||||||
|
RenameSelectedMacro();
|
||||||
|
} else if (pressedKey == Qt::Key_Delete) {
|
||||||
|
RemoveSelectedMacros();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return QDialog::eventFilter(obj, event);
|
return QDialog::eventFilter(obj, event);
|
||||||
@@ -228,7 +240,7 @@ void SwitcherData::Thread()
|
|||||||
if (duration.count() < 1) {
|
if (duration.count() < 1) {
|
||||||
blog(LOG_INFO,
|
blog(LOG_INFO,
|
||||||
"detected busy loop - refusing to sleep less than 1ms");
|
"detected busy loop - refusing to sleep less than 1ms");
|
||||||
duration = std::chrono::milliseconds(50);
|
duration = std::chrono::milliseconds(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,9 +522,7 @@ bool SwitcherData::AnySceneTransitionStarted()
|
|||||||
extern "C" EXPORT void FreeSceneSwitcher()
|
extern "C" EXPORT void FreeSceneSwitcher()
|
||||||
{
|
{
|
||||||
PlatformCleanup();
|
PlatformCleanup();
|
||||||
for (const auto &cleanupStep : switcher->pluginCleanupSteps) {
|
RunPluginCleanupSteps();
|
||||||
cleanupStep();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete switcher;
|
delete switcher;
|
||||||
switcher = nullptr;
|
switcher = nullptr;
|
||||||
@@ -742,13 +752,6 @@ QWidget *GetSettingsWindow()
|
|||||||
|
|
||||||
void SetupActionQueues();
|
void SetupActionQueues();
|
||||||
|
|
||||||
extern "C" EXPORT void RunPluginPostLoadSteps()
|
|
||||||
{
|
|
||||||
for (const auto &postLoadStep : switcher->pluginPostLoadSteps) {
|
|
||||||
postLoadStep();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module,
|
extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module,
|
||||||
translateFunc translate)
|
translateFunc translate)
|
||||||
{
|
{
|
||||||
@@ -762,9 +765,7 @@ extern "C" EXPORT void InitSceneSwitcher(obs_module_t *module,
|
|||||||
SetupDock();
|
SetupDock();
|
||||||
SetupActionQueues();
|
SetupActionQueues();
|
||||||
|
|
||||||
for (const auto &initStep : switcher->pluginInitSteps) {
|
RunPluginInitSteps();
|
||||||
initStep();
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
|
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
|
||||||
obs_frontend_add_event_callback(OBSEvent, switcher);
|
obs_frontend_add_event_callback(OBSEvent, switcher);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class MacroActionEdit;
|
|||||||
class MacroConditionEdit;
|
class MacroConditionEdit;
|
||||||
class Duration;
|
class Duration;
|
||||||
class SequenceWidget;
|
class SequenceWidget;
|
||||||
|
enum class LogicType;
|
||||||
struct SceneGroup;
|
struct SceneGroup;
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
@@ -34,8 +35,6 @@ public:
|
|||||||
|
|
||||||
void LoadUI();
|
void LoadUI();
|
||||||
|
|
||||||
void SetTabOrder();
|
|
||||||
void SetCurrentTab();
|
|
||||||
void RestoreWindowGeo();
|
void RestoreWindowGeo();
|
||||||
void CheckFirstTimeSetup();
|
void CheckFirstTimeSetup();
|
||||||
|
|
||||||
@@ -59,7 +58,6 @@ public slots:
|
|||||||
void on_autoStartEvent_currentIndexChanged(int index);
|
void on_autoStartEvent_currentIndexChanged(int index);
|
||||||
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
|
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
|
||||||
void on_checkInterval_valueChanged(int value);
|
void on_checkInterval_valueChanged(int value);
|
||||||
void on_tabMoved(int from, int to);
|
|
||||||
void on_tabWidget_currentChanged(int index);
|
void on_tabWidget_currentChanged(int index);
|
||||||
void on_exportSettings_clicked();
|
void on_exportSettings_clicked();
|
||||||
void on_importSettings_clicked();
|
void on_importSettings_clicked();
|
||||||
@@ -81,6 +79,7 @@ public:
|
|||||||
bool AddNewMacro(std::shared_ptr<Macro> &res, std::string &name,
|
bool AddNewMacro(std::shared_ptr<Macro> &res, std::string &name,
|
||||||
std::string format = "");
|
std::string format = "");
|
||||||
void RemoveMacro(std::shared_ptr<Macro> &);
|
void RemoveMacro(std::shared_ptr<Macro> &);
|
||||||
|
void RemoveSelectedMacros();
|
||||||
void RenameMacro(std::shared_ptr<Macro> &, const QString &name);
|
void RenameMacro(std::shared_ptr<Macro> &, const QString &name);
|
||||||
std::shared_ptr<Macro> GetSelectedMacro();
|
std::shared_ptr<Macro> GetSelectedMacro();
|
||||||
std::vector<std::shared_ptr<Macro>> GetSelectedMacros();
|
std::vector<std::shared_ptr<Macro>> GetSelectedMacros();
|
||||||
@@ -135,7 +134,7 @@ public slots:
|
|||||||
void ShowMacroElseActionsContextMenu(const QPoint &);
|
void ShowMacroElseActionsContextMenu(const QPoint &);
|
||||||
void ShowMacroConditionsContextMenu(const QPoint &);
|
void ShowMacroConditionsContextMenu(const QPoint &);
|
||||||
void CopyMacro();
|
void CopyMacro();
|
||||||
void RenameCurrentMacro();
|
void RenameSelectedMacro();
|
||||||
void ExportMacros();
|
void ExportMacros();
|
||||||
void ImportMacros();
|
void ImportMacros();
|
||||||
void ExpandAllActions();
|
void ExpandAllActions();
|
||||||
@@ -154,12 +153,16 @@ public slots:
|
|||||||
void SetElseActionsStateToVisible();
|
void SetElseActionsStateToVisible();
|
||||||
void MacroActionSelectionChanged(int idx);
|
void MacroActionSelectionChanged(int idx);
|
||||||
void MacroActionReorder(int to, int target);
|
void MacroActionReorder(int to, int target);
|
||||||
|
void AddMacroAction(Macro *macro, int idx, const std::string &id,
|
||||||
|
obs_data_t *data);
|
||||||
void AddMacroAction(int idx);
|
void AddMacroAction(int idx);
|
||||||
void RemoveMacroAction(int idx);
|
void RemoveMacroAction(int idx);
|
||||||
void MoveMacroActionUp(int idx);
|
void MoveMacroActionUp(int idx);
|
||||||
void MoveMacroActionDown(int idx);
|
void MoveMacroActionDown(int idx);
|
||||||
void MacroElseActionSelectionChanged(int idx);
|
void MacroElseActionSelectionChanged(int idx);
|
||||||
void MacroElseActionReorder(int to, int target);
|
void MacroElseActionReorder(int to, int target);
|
||||||
|
void AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
||||||
|
obs_data_t *data);
|
||||||
void AddMacroElseAction(int idx);
|
void AddMacroElseAction(int idx);
|
||||||
void RemoveMacroElseAction(int idx);
|
void RemoveMacroElseAction(int idx);
|
||||||
void SwapElseActions(Macro *m, int pos1, int pos2);
|
void SwapElseActions(Macro *m, int pos1, int pos2);
|
||||||
@@ -168,16 +171,16 @@ public slots:
|
|||||||
void MacroConditionSelectionChanged(int idx);
|
void MacroConditionSelectionChanged(int idx);
|
||||||
void MacroConditionReorder(int to, int target);
|
void MacroConditionReorder(int to, int target);
|
||||||
void AddMacroCondition(int idx);
|
void AddMacroCondition(int idx);
|
||||||
|
void AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
||||||
|
obs_data_t *data, LogicType logic);
|
||||||
void RemoveMacroCondition(int idx);
|
void RemoveMacroCondition(int idx);
|
||||||
void MoveMacroConditionUp(int idx);
|
void MoveMacroConditionUp(int idx);
|
||||||
void MoveMacroConditionDown(int idx);
|
void MoveMacroConditionDown(int idx);
|
||||||
void FadeOutActionControls();
|
|
||||||
void FadeOutConditionControls();
|
|
||||||
void ResetOpacityActionControls();
|
|
||||||
void ResetOpacityConditionControls();
|
|
||||||
void HighlightControls();
|
void HighlightControls();
|
||||||
void HighlightOnChange();
|
void HighlightOnChange();
|
||||||
void on_macroProperties_clicked();
|
void on_macroProperties_clicked();
|
||||||
|
void CopyMacroSegment();
|
||||||
|
void PasteMacroSegment();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void MacroAdded(const QString &name);
|
void MacroAdded(const QString &name);
|
||||||
@@ -186,9 +189,6 @@ signals:
|
|||||||
void MacroSegmentOrderChanged();
|
void MacroSegmentOrderChanged();
|
||||||
void SegmentTempVarsChanged();
|
void SegmentTempVarsChanged();
|
||||||
void HighlightMacrosChanged(bool value);
|
void HighlightMacrosChanged(bool value);
|
||||||
void HighlightActionsChanged(bool value);
|
|
||||||
void HighlightElseActionsChanged(bool value);
|
|
||||||
void HighlightConditionsChanged(bool value);
|
|
||||||
|
|
||||||
void ConnectionAdded(const QString &);
|
void ConnectionAdded(const QString &);
|
||||||
void ConnectionRenamed(const QString &oldName, const QString &newName);
|
void ConnectionRenamed(const QString &oldName, const QString &newName);
|
||||||
@@ -208,16 +208,6 @@ private:
|
|||||||
|
|
||||||
/* --- End of macro tab section --- */
|
/* --- End of macro tab section --- */
|
||||||
|
|
||||||
/* --- Begin of variable tab section --- */
|
|
||||||
public:
|
|
||||||
void SetupVariableTab();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void on_variableAdd_clicked();
|
|
||||||
void on_variableRemove_clicked();
|
|
||||||
|
|
||||||
/* --- End of variable tab section --- */
|
|
||||||
|
|
||||||
/* --- Begin of legacy tab section --- */
|
/* --- Begin of legacy tab section --- */
|
||||||
public:
|
public:
|
||||||
void ClearFrames(QListWidget *list);
|
void ClearFrames(QListWidget *list);
|
||||||
|
|||||||
120
lib/general.cpp
120
lib/general.cpp
@@ -9,6 +9,7 @@
|
|||||||
#include "splitter-helpers.hpp"
|
#include "splitter-helpers.hpp"
|
||||||
#include "status-control.hpp"
|
#include "status-control.hpp"
|
||||||
#include "switcher-data.hpp"
|
#include "switcher-data.hpp"
|
||||||
|
#include "tab-helpers.hpp"
|
||||||
#include "ui-helpers.hpp"
|
#include "ui-helpers.hpp"
|
||||||
#include "utility.hpp"
|
#include "utility.hpp"
|
||||||
#include "variable.hpp"
|
#include "variable.hpp"
|
||||||
@@ -19,17 +20,6 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
static constexpr std::array<const char *, 19> tabNames = {
|
|
||||||
"generalTab", "macroTab", "variableTab",
|
|
||||||
"windowTitleTab", "executableTab", "screenRegionTab",
|
|
||||||
"mediaTab", "fileTab", "randomTab",
|
|
||||||
"timeTab", "idleTab", "sceneSequenceTab",
|
|
||||||
"audioTab", "videoTab", "networkTab",
|
|
||||||
"sceneGroupTab", "transitionsTab", "pauseTab",
|
|
||||||
"sceneTriggerTab"};
|
|
||||||
|
|
||||||
static std::vector<int> tabOrder = std::vector<int>(tabNames.size());
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::reject()
|
void AdvSceneSwitcher::reject()
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
@@ -244,14 +234,7 @@ void AdvSceneSwitcher::on_hideLegacyTabs_stateChanged(int state)
|
|||||||
|
|
||||||
for (int idx = 0; idx < ui->tabWidget->count(); idx++) {
|
for (int idx = 0; idx < ui->tabWidget->count(); idx++) {
|
||||||
if (isLegacyTab(ui->tabWidget->tabText(idx))) {
|
if (isLegacyTab(ui->tabWidget->tabText(idx))) {
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
// TODO: Switch to setTabVisible() once QT 5.15 is more wide spread
|
|
||||||
ui->tabWidget->setTabEnabled(idx, !state);
|
|
||||||
ui->tabWidget->setStyleSheet(
|
|
||||||
"QTabBar::tab::disabled {width: 0; height: 0; margin: 0; padding: 0; border: none;} ");
|
|
||||||
#else
|
|
||||||
ui->tabWidget->setTabVisible(idx, !state);
|
ui->tabWidget->setTabVisible(idx, !state);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,67 +346,6 @@ void AdvSceneSwitcher::on_importSettings_clicked()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int findTabIndex(QTabWidget *tabWidget, int pos)
|
|
||||||
{
|
|
||||||
int at = -1;
|
|
||||||
QString tabName = tabNames.at(pos);
|
|
||||||
QWidget *page = tabWidget->findChild<QWidget *>(tabName);
|
|
||||||
if (page) {
|
|
||||||
at = tabWidget->indexOf(page);
|
|
||||||
}
|
|
||||||
if (at == -1) {
|
|
||||||
blog(LOG_INFO, "failed to find tab %s",
|
|
||||||
tabName.toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
return at;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool tabWidgetOrderValid()
|
|
||||||
{
|
|
||||||
auto tmp = std::vector<int>(tabNames.size());
|
|
||||||
std::iota(tmp.begin(), tmp.end(), 0);
|
|
||||||
|
|
||||||
for (auto &p : tmp) {
|
|
||||||
auto it = std::find(tabOrder.begin(), tabOrder.end(), p);
|
|
||||||
if (it == tabOrder.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void resetTabWidgetOrder()
|
|
||||||
{
|
|
||||||
tabOrder = std::vector<int>(tabNames.size());
|
|
||||||
std::iota(tabOrder.begin(), tabOrder.end(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::SetTabOrder()
|
|
||||||
{
|
|
||||||
if (!tabWidgetOrderValid()) {
|
|
||||||
resetTabWidgetOrder();
|
|
||||||
}
|
|
||||||
|
|
||||||
QTabBar *bar = ui->tabWidget->tabBar();
|
|
||||||
for (int i = 0; i < bar->count(); ++i) {
|
|
||||||
int curPos = findTabIndex(ui->tabWidget, tabOrder[i]);
|
|
||||||
|
|
||||||
if (i != curPos && curPos != -1) {
|
|
||||||
bar->moveTab(curPos, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(bar, &QTabBar::tabMoved, this, &AdvSceneSwitcher::on_tabMoved);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::SetCurrentTab()
|
|
||||||
{
|
|
||||||
if (switcher->lastOpenedTab >= 0) {
|
|
||||||
ui->tabWidget->setCurrentIndex(switcher->lastOpenedTab);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool windowPosValid(QPoint pos)
|
static bool windowPosValid(QPoint pos)
|
||||||
{
|
{
|
||||||
return !!QGuiApplication::screenAt(pos);
|
return !!QGuiApplication::screenAt(pos);
|
||||||
@@ -446,17 +368,12 @@ void AdvSceneSwitcher::CheckFirstTimeSetup()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_tabMoved(int from, int to)
|
void AdvSceneSwitcher::on_tabWidget_currentChanged(int)
|
||||||
{
|
{
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::swap(tabOrder[from], tabOrder[to]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_tabWidget_currentChanged(int)
|
|
||||||
{
|
|
||||||
switcher->showFrame = false;
|
switcher->showFrame = false;
|
||||||
ClearFrames(ui->screenRegionSwitches);
|
ClearFrames(ui->screenRegionSwitches);
|
||||||
SetShowFrames();
|
SetShowFrames();
|
||||||
@@ -537,7 +454,7 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
|||||||
RunPostLoadSteps();
|
RunPostLoadSteps();
|
||||||
|
|
||||||
// Reset on startup and scene collection change
|
// Reset on startup and scene collection change
|
||||||
switcher->lastOpenedTab = -1;
|
ResetLastOpenedTab();
|
||||||
startupLoadDone = true;
|
startupLoadDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,13 +602,7 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
|||||||
|
|
||||||
void SwitcherData::SaveUISettings(obs_data_t *obj)
|
void SwitcherData::SaveUISettings(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
OBSDataArrayAutoRelease tabWidgetOrder = obs_data_array_create();
|
SaveTabOrder(obj);
|
||||||
for (size_t i = 0; i < tabNames.size(); i++) {
|
|
||||||
OBSDataAutoRelease entry = obs_data_create();
|
|
||||||
obs_data_set_int(entry, tabNames[i], tabOrder[i]);
|
|
||||||
obs_data_array_push_back(tabWidgetOrder, entry);
|
|
||||||
}
|
|
||||||
obs_data_set_array(obj, "tabWidgetOrder", tabWidgetOrder);
|
|
||||||
|
|
||||||
obs_data_set_bool(obj, "saveWindowGeo", saveWindowGeo);
|
obs_data_set_bool(obj, "saveWindowGeo", saveWindowGeo);
|
||||||
obs_data_set_int(obj, "windowPosX", windowPos.x());
|
obs_data_set_int(obj, "windowPosX", windowPos.x());
|
||||||
@@ -705,28 +616,7 @@ void SwitcherData::SaveUISettings(obs_data_t *obj)
|
|||||||
|
|
||||||
void SwitcherData::LoadUISettings(obs_data_t *obj)
|
void SwitcherData::LoadUISettings(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
OBSDataArrayAutoRelease defaultTabWidgetOrder = obs_data_array_create();
|
LoadTabOrder(obj);
|
||||||
for (size_t i = 0; i < tabNames.size(); i++) {
|
|
||||||
OBSDataAutoRelease entry = obs_data_create();
|
|
||||||
obs_data_set_default_int(entry, tabNames[i], i);
|
|
||||||
obs_data_array_push_back(defaultTabWidgetOrder, entry);
|
|
||||||
}
|
|
||||||
obs_data_set_default_array(obj, "tabWidgetOrder",
|
|
||||||
defaultTabWidgetOrder);
|
|
||||||
|
|
||||||
tabOrder.clear();
|
|
||||||
OBSDataArrayAutoRelease tabWidgetOrder =
|
|
||||||
obs_data_get_array(obj, "tabWidgetOrder");
|
|
||||||
for (size_t i = 0; i < tabNames.size(); i++) {
|
|
||||||
OBSDataAutoRelease entry =
|
|
||||||
obs_data_array_item(tabWidgetOrder, i);
|
|
||||||
tabOrder.emplace_back(
|
|
||||||
(int)(obs_data_get_int(entry, tabNames[i])));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tabWidgetOrderValid()) {
|
|
||||||
resetTabWidgetOrder();
|
|
||||||
}
|
|
||||||
|
|
||||||
saveWindowGeo = obs_data_get_bool(obj, "saveWindowGeo");
|
saveWindowGeo = obs_data_get_bool(obj, "saveWindowGeo");
|
||||||
windowPos = {(int)obs_data_get_int(obj, "windowPosX"),
|
windowPos = {(int)obs_data_get_int(obj, "windowPosX"),
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ void AdvSceneSwitcher::on_sceneGroupAdd_clicked()
|
|||||||
placeHolderText = format.arg(++i);
|
placeHolderText = format.arg(++i);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool accepted = AdvSSNameDialog::AskForName(
|
bool accepted = NameDialog::AskForName(
|
||||||
this, obs_module_text("AdvSceneSwitcher.sceneGroupTab.add"),
|
this, obs_module_text("AdvSceneSwitcher.sceneGroupTab.add"),
|
||||||
obs_module_text("AdvSceneSwitcher.sceneGroupTab.add"), name,
|
obs_module_text("AdvSceneSwitcher.sceneGroupTab.add"), name,
|
||||||
placeHolderText);
|
placeHolderText);
|
||||||
|
|||||||
@@ -437,10 +437,8 @@ AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
|
|||||||
audioVolumeThreshold->setMaximum(100);
|
audioVolumeThreshold->setMaximum(100);
|
||||||
audioVolumeThreshold->setMinimum(0);
|
audioVolumeThreshold->setMinimum(0);
|
||||||
|
|
||||||
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
QWidget::connect(volMeter->GetSlider(), &DoubleSlider::DoubleValChanged,
|
||||||
audioVolumeThreshold, SLOT(setValue(int)));
|
[=](double) { SyncSliderAndValueSelection(true); });
|
||||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
|
||||||
volMeter->GetSlider(), SLOT(setValue(int)));
|
|
||||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), this,
|
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), this,
|
||||||
SLOT(VolumeThresholdChanged(int)));
|
SLOT(VolumeThresholdChanged(int)));
|
||||||
QWidget::connect(condition, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(condition, SIGNAL(currentIndexChanged(int)), this,
|
||||||
@@ -487,6 +485,7 @@ AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
|
|||||||
switchData = s;
|
switchData = s;
|
||||||
|
|
||||||
loading = false;
|
loading = false;
|
||||||
|
SyncSliderAndValueSelection(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioSwitch *AudioSwitchWidget::getSwitchData()
|
AudioSwitch *AudioSwitchWidget::getSwitchData()
|
||||||
@@ -509,6 +508,21 @@ void AudioSwitchWidget::swapSwitchData(AudioSwitchWidget *s1,
|
|||||||
s2->setSwitchData(t);
|
s2->setSwitchData(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioSwitchWidget::SyncSliderAndValueSelection(bool sliderMoved)
|
||||||
|
{
|
||||||
|
if (loading || !switchData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sliderMoved) {
|
||||||
|
auto sliderPosition = volMeter->GetSlider()->DoubleValue();
|
||||||
|
audioVolumeThreshold->setValue(sliderPosition);
|
||||||
|
} else {
|
||||||
|
volMeter->GetSlider()->SetDoubleVal(
|
||||||
|
switchData->volumeThreshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AudioSwitchWidget::UpdateVolmeterSource()
|
void AudioSwitchWidget::UpdateVolmeterSource()
|
||||||
{
|
{
|
||||||
delete volMeter;
|
delete volMeter;
|
||||||
@@ -520,10 +534,8 @@ void AudioSwitchWidget::UpdateVolmeterSource()
|
|||||||
QLayout *layout = this->layout();
|
QLayout *layout = this->layout();
|
||||||
layout->addWidget(volMeter);
|
layout->addWidget(volMeter);
|
||||||
|
|
||||||
QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)),
|
QWidget::connect(volMeter->GetSlider(), &DoubleSlider::DoubleValChanged,
|
||||||
audioVolumeThreshold, SLOT(setValue(int)));
|
[=](double) { SyncSliderAndValueSelection(true); });
|
||||||
QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)),
|
|
||||||
volMeter->GetSlider(), SLOT(setValue(int)));
|
|
||||||
|
|
||||||
// Slider will default to 0 so set it manually once
|
// Slider will default to 0 so set it manually once
|
||||||
volMeter->GetSlider()->setValue(switchData->volumeThreshold);
|
volMeter->GetSlider()->setValue(switchData->volumeThreshold);
|
||||||
@@ -547,8 +559,11 @@ void AudioSwitchWidget::VolumeThresholdChanged(int vol)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
{
|
||||||
switchData->volumeThreshold = vol;
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switchData->volumeThreshold = vol;
|
||||||
|
}
|
||||||
|
SyncSliderAndValueSelection(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioSwitchWidget::ConditionChanged(int cond)
|
void AudioSwitchWidget::ConditionChanged(int cond)
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ private slots:
|
|||||||
void ConditionChanged(int cond);
|
void ConditionChanged(int cond);
|
||||||
void DurationChanged(const Duration &);
|
void DurationChanged(const Duration &);
|
||||||
void IgnoreInactiveChanged(int state);
|
void IgnoreInactiveChanged(int state);
|
||||||
|
void SyncSliderAndValueSelection(bool sliderMoved);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QComboBox *audioSources;
|
QComboBox *audioSources;
|
||||||
|
|||||||
@@ -132,6 +132,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
QRunnable *CreateFunctionRunnable(std::function<void()> func);
|
QRunnable *CreateFunctionRunnable(std::function<void()> func);
|
||||||
}
|
} // namespace Compatability
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -29,8 +29,7 @@ static inline void populateActionSelection(QComboBox *list)
|
|||||||
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||||
std::shared_ptr<MacroAction> *entryData,
|
std::shared_ptr<MacroAction> *entryData,
|
||||||
const std::string &id)
|
const std::string &id)
|
||||||
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightActions,
|
: MacroSegmentEdit(parent),
|
||||||
parent),
|
|
||||||
_actionSelection(new FilterComboBox()),
|
_actionSelection(new FilterComboBox()),
|
||||||
_enable(new SwitchButton()),
|
_enable(new SwitchButton()),
|
||||||
_entryData(entryData)
|
_entryData(entryData)
|
||||||
@@ -40,8 +39,6 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
|||||||
SLOT(ActionSelectionChanged(const QString &)));
|
SLOT(ActionSelectionChanged(const QString &)));
|
||||||
QWidget::connect(_enable, SIGNAL(checked(bool)), this,
|
QWidget::connect(_enable, SIGNAL(checked(bool)), this,
|
||||||
SLOT(ActionEnableChanged(bool)));
|
SLOT(ActionEnableChanged(bool)));
|
||||||
QWidget::connect(window(), SIGNAL(HighlightActionsChanged(bool)), this,
|
|
||||||
SLOT(EnableHighlight(bool)));
|
|
||||||
QWidget::connect(&_actionStateTimer, SIGNAL(timeout()), this,
|
QWidget::connect(&_actionStateTimer, SIGNAL(timeout()), this,
|
||||||
SLOT(UpdateActionState()));
|
SLOT(UpdateActionState()));
|
||||||
|
|
||||||
@@ -161,33 +158,20 @@ std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
|||||||
return *_entryData;
|
return *_entryData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::AddMacroAction(int idx)
|
void AdvSceneSwitcher::AddMacroAction(Macro *macro, int idx,
|
||||||
|
const std::string &id, obs_data_t *data)
|
||||||
{
|
{
|
||||||
auto macro = GetSelectedMacro();
|
|
||||||
if (!macro) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx < 0 || idx > (int)macro->Actions().size()) {
|
if (idx < 0 || idx > (int)macro->Actions().size()) {
|
||||||
|
assert(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string id;
|
|
||||||
if (idx - 1 >= 0) {
|
|
||||||
id = macro->Actions().at(idx - 1)->GetId();
|
|
||||||
} else {
|
|
||||||
id = MacroAction::GetDefaultID();
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
macro->Actions().emplace(
|
macro->Actions().emplace(macro->Actions().begin() + idx,
|
||||||
macro->Actions().begin() + idx,
|
MacroActionFactory::Create(id, macro));
|
||||||
MacroActionFactory::Create(id, macro.get()));
|
if (data) {
|
||||||
if (idx - 1 >= 0) {
|
|
||||||
auto data = obs_data_create();
|
|
||||||
macro->Actions().at(idx - 1)->Save(data);
|
|
||||||
macro->Actions().at(idx)->Load(data);
|
macro->Actions().at(idx)->Load(data);
|
||||||
obs_data_release(data);
|
|
||||||
}
|
}
|
||||||
macro->Actions().at(idx)->PostLoad();
|
macro->Actions().at(idx)->PostLoad();
|
||||||
RunPostLoadSteps();
|
RunPostLoadSteps();
|
||||||
@@ -198,9 +182,37 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
|
|||||||
SetActionData(*macro);
|
SetActionData(*macro);
|
||||||
}
|
}
|
||||||
HighlightAction(idx);
|
HighlightAction(idx);
|
||||||
|
ui->actionsList->SetHelpMsgVisible(false);
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::AddMacroAction(int idx)
|
||||||
|
{
|
||||||
|
auto macro = GetSelectedMacro();
|
||||||
|
if (!macro) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx < 0 || idx > (int)macro->Actions().size()) {
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string id;
|
||||||
|
if (idx - 1 >= 0) {
|
||||||
|
id = macro->Actions().at(idx - 1)->GetId();
|
||||||
|
} else {
|
||||||
|
id = MacroAction::GetDefaultID();
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSDataAutoRelease data;
|
||||||
|
if (idx - 1 >= 0) {
|
||||||
|
data = obs_data_create();
|
||||||
|
macro->Actions().at(idx - 1)->Save(data);
|
||||||
|
}
|
||||||
|
AddMacroAction(macro.get(), idx, id, data);
|
||||||
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_actionAdd_clicked()
|
void AdvSceneSwitcher::on_actionAdd_clicked()
|
||||||
{
|
{
|
||||||
auto macro = GetSelectedMacro();
|
auto macro = GetSelectedMacro();
|
||||||
@@ -216,7 +228,6 @@ void AdvSceneSwitcher::on_actionAdd_clicked()
|
|||||||
if (currentActionIdx != -1) {
|
if (currentActionIdx != -1) {
|
||||||
MacroActionSelectionChanged(currentActionIdx + 1);
|
MacroActionSelectionChanged(currentActionIdx + 1);
|
||||||
}
|
}
|
||||||
ui->actionsList->SetHelpMsgVisible(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::RemoveMacroAction(int idx)
|
void AdvSceneSwitcher::RemoveMacroAction(int idx)
|
||||||
@@ -311,7 +322,6 @@ void AdvSceneSwitcher::on_elseActionAdd_clicked()
|
|||||||
if (currentElseActionIdx != -1) {
|
if (currentElseActionIdx != -1) {
|
||||||
MacroElseActionSelectionChanged(currentElseActionIdx + 1);
|
MacroElseActionSelectionChanged(currentElseActionIdx + 1);
|
||||||
}
|
}
|
||||||
ui->elseActionsList->SetHelpMsgVisible(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_elseActionRemove_clicked()
|
void AdvSceneSwitcher::on_elseActionRemove_clicked()
|
||||||
@@ -450,31 +460,21 @@ void AdvSceneSwitcher::MacroElseActionReorder(int to, int from)
|
|||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::AddMacroElseAction(int idx)
|
void AdvSceneSwitcher::AddMacroElseAction(Macro *macro, int idx,
|
||||||
|
const std::string &id,
|
||||||
|
obs_data_t *data)
|
||||||
{
|
{
|
||||||
auto macro = GetSelectedMacro();
|
|
||||||
if (!macro) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
|
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
|
||||||
|
assert(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string id;
|
|
||||||
if (idx - 1 >= 0) {
|
|
||||||
id = macro->ElseActions().at(idx - 1)->GetId();
|
|
||||||
} else {
|
|
||||||
id = MacroAction::GetDefaultID();
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
macro->ElseActions().emplace(
|
macro->ElseActions().emplace(macro->ElseActions().begin() + idx,
|
||||||
macro->ElseActions().begin() + idx,
|
MacroActionFactory::Create(id,
|
||||||
MacroActionFactory::Create(id, macro.get()));
|
macro));
|
||||||
if (idx - 1 >= 0) {
|
if (data) {
|
||||||
OBSDataAutoRelease data = obs_data_create();
|
|
||||||
macro->ElseActions().at(idx - 1)->Save(data);
|
|
||||||
macro->ElseActions().at(idx)->Load(data);
|
macro->ElseActions().at(idx)->Load(data);
|
||||||
}
|
}
|
||||||
macro->ElseActions().at(idx)->PostLoad();
|
macro->ElseActions().at(idx)->PostLoad();
|
||||||
@@ -486,9 +486,37 @@ void AdvSceneSwitcher::AddMacroElseAction(int idx)
|
|||||||
SetElseActionData(*macro);
|
SetElseActionData(*macro);
|
||||||
}
|
}
|
||||||
HighlightElseAction(idx);
|
HighlightElseAction(idx);
|
||||||
|
ui->elseActionsList->SetHelpMsgVisible(false);
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::AddMacroElseAction(int idx)
|
||||||
|
{
|
||||||
|
auto macro = GetSelectedMacro();
|
||||||
|
if (!macro) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx < 0 || idx > (int)macro->ElseActions().size()) {
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string id;
|
||||||
|
if (idx - 1 >= 0) {
|
||||||
|
id = macro->ElseActions().at(idx - 1)->GetId();
|
||||||
|
} else {
|
||||||
|
id = MacroAction::GetDefaultID();
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSDataAutoRelease data;
|
||||||
|
if (idx - 1 >= 0) {
|
||||||
|
data = obs_data_create();
|
||||||
|
macro->ElseActions().at(idx - 1)->Save(data);
|
||||||
|
}
|
||||||
|
AddMacroElseAction(macro.get(), idx, id, data);
|
||||||
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::RemoveMacroElseAction(int idx)
|
void AdvSceneSwitcher::RemoveMacroElseAction(int idx)
|
||||||
{
|
{
|
||||||
auto macro = GetSelectedMacro();
|
auto macro = GetSelectedMacro();
|
||||||
@@ -507,7 +535,7 @@ void AdvSceneSwitcher::RemoveMacroElseAction(int idx)
|
|||||||
SetMacroAbortWait(true);
|
SetMacroAbortWait(true);
|
||||||
GetMacroWaitCV().notify_all();
|
GetMacroWaitCV().notify_all();
|
||||||
macro->UpdateElseActionIndices();
|
macro->UpdateElseActionIndices();
|
||||||
SetActionData(*macro);
|
SetElseActionData(*macro);
|
||||||
}
|
}
|
||||||
MacroElseActionSelectionChanged(-1);
|
MacroElseActionSelectionChanged(-1);
|
||||||
lastInteracted = MacroSection::ELSE_ACTIONS;
|
lastInteracted = MacroSection::ELSE_ACTIONS;
|
||||||
|
|||||||
@@ -48,9 +48,7 @@ bool MacroActionMacro::PerformAction()
|
|||||||
macro->ResetRunCount();
|
macro->ResetRunCount();
|
||||||
break;
|
break;
|
||||||
case Action::RUN:
|
case Action::RUN:
|
||||||
if (!macro->Paused()) {
|
RunActions(macro.get());
|
||||||
macro->PerformActions(true, false, true);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Action::STOP:
|
case Action::STOP:
|
||||||
macro->Stop();
|
macro->Stop();
|
||||||
@@ -127,6 +125,7 @@ bool MacroActionMacro::Save(obs_data_t *obj) const
|
|||||||
_macro.Save(obj);
|
_macro.Save(obj);
|
||||||
_actionIndex.Save(obj, "actionIndex");
|
_actionIndex.Save(obj, "actionIndex");
|
||||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||||
|
_runOptions.Save(obj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,6 +136,15 @@ bool MacroActionMacro::Load(obs_data_t *obj)
|
|||||||
_actionIndex.Load(obj, "actionIndex");
|
_actionIndex.Load(obj, "actionIndex");
|
||||||
_action = static_cast<MacroActionMacro::Action>(
|
_action = static_cast<MacroActionMacro::Action>(
|
||||||
obs_data_get_int(obj, "action"));
|
obs_data_get_int(obj, "action"));
|
||||||
|
_runOptions.Load(obj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionMacro::PostLoad()
|
||||||
|
{
|
||||||
|
MacroRefAction::PostLoad();
|
||||||
|
MacroAction::PostLoad();
|
||||||
|
_runOptions.macro.PostLoad();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,11 +168,55 @@ void MacroActionMacro::ResolveVariablesToFixedValues()
|
|||||||
_actionIndex.ResolveVariables();
|
_actionIndex.ResolveVariables();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void populateActionSelection(QComboBox *list)
|
void MacroActionMacro::RunActions(Macro *actionMacro) const
|
||||||
{
|
{
|
||||||
for (auto entry : actionTypes) {
|
if (_runOptions.skipWhenPaused && actionMacro->Paused()) {
|
||||||
list->addItem(obs_module_text(entry.second.c_str()));
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_runOptions.logic == RunOptions::Logic::IGNORE_CONDITIONS) {
|
||||||
|
actionMacro->PerformActions(!_runOptions.runElseActions, false,
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto conditionMacro = _runOptions.macro.GetMacro();
|
||||||
|
if (!conditionMacro) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_runOptions.logic == RunOptions::Logic::CONDITIONS &&
|
||||||
|
conditionMacro->Matched()) ||
|
||||||
|
(_runOptions.logic == RunOptions::Logic::INVERT_CONDITIONS &&
|
||||||
|
!conditionMacro->Matched())) {
|
||||||
|
actionMacro->PerformActions(!_runOptions.runElseActions, false,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void populateActionSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
for (const auto &[_, name] : actionTypes) {
|
||||||
|
list->addItem(obs_module_text(name.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void populateConditionBehaviorSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.macro.type.run.conditions.ignore"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.macro.type.run.conditions.true"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.macro.type.run.conditions.false"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void populateActionTypeSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.macro.type.run.actionType.regular"));
|
||||||
|
list->addItem(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.macro.type.run.actionType.else"));
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroActionMacroEdit::MacroActionMacroEdit(
|
MacroActionMacroEdit::MacroActionMacroEdit(
|
||||||
@@ -173,9 +225,20 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
|||||||
_macros(new MacroSelection(parent)),
|
_macros(new MacroSelection(parent)),
|
||||||
_actionIndex(new MacroSegmentSelection(
|
_actionIndex(new MacroSegmentSelection(
|
||||||
this, MacroSegmentSelection::Type::ACTION)),
|
this, MacroSegmentSelection::Type::ACTION)),
|
||||||
_actions(new QComboBox())
|
_actions(new QComboBox()),
|
||||||
|
_conditionMacros(new MacroSelection(parent)),
|
||||||
|
_conditionBehaviors(new QComboBox()),
|
||||||
|
_actionTypes(new QComboBox()),
|
||||||
|
_skipWhenPaused(new QCheckBox(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.macro.type.run.skipWhenPaused"))),
|
||||||
|
_entryLayout(new QHBoxLayout()),
|
||||||
|
_conditionLayout(new QHBoxLayout())
|
||||||
{
|
{
|
||||||
populateActionSelection(_actions);
|
populateActionSelection(_actions);
|
||||||
|
populateConditionBehaviorSelection(_conditionBehaviors);
|
||||||
|
populateActionTypeSelection(_actionTypes);
|
||||||
|
|
||||||
|
_conditionMacros->HideSelectedMacro();
|
||||||
|
|
||||||
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
|
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
|
||||||
this, SLOT(MacroChanged(const QString &)));
|
this, SLOT(MacroChanged(const QString &)));
|
||||||
@@ -184,15 +247,21 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
|||||||
QWidget::connect(_actionIndex,
|
QWidget::connect(_actionIndex,
|
||||||
SIGNAL(SelectionChanged(const IntVariable &)), this,
|
SIGNAL(SelectionChanged(const IntVariable &)), this,
|
||||||
SLOT(ActionIndexChanged(const IntVariable &)));
|
SLOT(ActionIndexChanged(const IntVariable &)));
|
||||||
|
QWidget::connect(_conditionMacros,
|
||||||
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
|
SLOT(ConditionMacroChanged(const QString &)));
|
||||||
|
QWidget::connect(_conditionBehaviors, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(ConditionBehaviorChanged(int)));
|
||||||
|
QWidget::connect(_actionTypes, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ActionTypeChanged(int)));
|
||||||
|
QWidget::connect(_skipWhenPaused, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(SkipWhenPausedChanged(int)));
|
||||||
|
|
||||||
auto mainLayout = new QHBoxLayout;
|
auto layout = new QVBoxLayout();
|
||||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.macro.entry"),
|
layout->addLayout(_entryLayout);
|
||||||
mainLayout,
|
layout->addLayout(_conditionLayout);
|
||||||
{{"{{actions}}", _actions},
|
layout->addWidget(_skipWhenPaused);
|
||||||
{"{{actionIndex}}", _actionIndex},
|
setLayout(layout);
|
||||||
{"{{macros}}", _macros}});
|
|
||||||
setLayout(mainLayout);
|
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
UpdateEntryData();
|
UpdateEntryData();
|
||||||
_loading = false;
|
_loading = false;
|
||||||
@@ -207,6 +276,12 @@ void MacroActionMacroEdit::UpdateEntryData()
|
|||||||
_actionIndex->SetValue(_entryData->_actionIndex);
|
_actionIndex->SetValue(_entryData->_actionIndex);
|
||||||
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
|
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
|
||||||
_macros->SetCurrentMacro(_entryData->_macro);
|
_macros->SetCurrentMacro(_entryData->_macro);
|
||||||
|
_conditionMacros->SetCurrentMacro(_entryData->_runOptions.macro);
|
||||||
|
_conditionBehaviors->setCurrentIndex(
|
||||||
|
static_cast<int>(_entryData->_runOptions.logic));
|
||||||
|
_actionTypes->setCurrentIndex(
|
||||||
|
_entryData->_runOptions.runElseActions ? 1 : 0);
|
||||||
|
_skipWhenPaused->setChecked(_entryData->_runOptions.skipWhenPaused);
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,8 +319,88 @@ void MacroActionMacroEdit::ActionIndexChanged(const IntVariable &value)
|
|||||||
_entryData->_actionIndex = value;
|
_entryData->_actionIndex = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionMacroEdit::ConditionMacroChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->_runOptions.macro = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMacroEdit::ConditionBehaviorChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->_runOptions.logic =
|
||||||
|
static_cast<MacroActionMacro::RunOptions::Logic>(value);
|
||||||
|
SetWidgetVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMacroEdit::ActionTypeChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->_runOptions.runElseActions = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMacroEdit::SkipWhenPausedChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->_runOptions.skipWhenPaused = value;
|
||||||
|
}
|
||||||
|
|
||||||
void MacroActionMacroEdit::SetWidgetVisibility()
|
void MacroActionMacroEdit::SetWidgetVisibility()
|
||||||
{
|
{
|
||||||
|
_entryLayout->removeWidget(_actions);
|
||||||
|
_entryLayout->removeWidget(_actionIndex);
|
||||||
|
_entryLayout->removeWidget(_macros);
|
||||||
|
_entryLayout->removeWidget(_actionTypes);
|
||||||
|
_conditionLayout->removeWidget(_conditionBehaviors);
|
||||||
|
_conditionLayout->removeWidget(_conditionMacros);
|
||||||
|
|
||||||
|
ClearLayout(_entryLayout);
|
||||||
|
ClearLayout(_conditionLayout);
|
||||||
|
|
||||||
|
const std::unordered_map<std::string, QWidget *> placeholders = {
|
||||||
|
{"{{actions}}", _actions},
|
||||||
|
{"{{actionIndex}}", _actionIndex},
|
||||||
|
{"{{macros}}", _macros},
|
||||||
|
{"{{actionTypes}}", _actionTypes},
|
||||||
|
{"{{conditionBehaviors}}", _conditionBehaviors},
|
||||||
|
{"{{conditionMacros}}", _conditionMacros},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
PlaceWidgets(
|
||||||
|
obs_module_text(
|
||||||
|
_entryData->_action == MacroActionMacro::Action::RUN
|
||||||
|
? "AdvSceneSwitcher.action.macro.entry.run"
|
||||||
|
: "AdvSceneSwitcher.action.macro.entry.other"),
|
||||||
|
_entryLayout, placeholders);
|
||||||
|
|
||||||
|
if (_entryData->_runOptions.logic ==
|
||||||
|
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS) {
|
||||||
|
_conditionLayout->addWidget(_conditionBehaviors);
|
||||||
|
_conditionLayout->addStretch();
|
||||||
|
} else {
|
||||||
|
PlaceWidgets(
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.macro.entry.run.condition"),
|
||||||
|
_conditionLayout, placeholders);
|
||||||
|
}
|
||||||
|
|
||||||
if (_entryData->_action == MacroActionMacro::Action::RUN ||
|
if (_entryData->_action == MacroActionMacro::Action::RUN ||
|
||||||
_entryData->_action == MacroActionMacro::Action::STOP) {
|
_entryData->_action == MacroActionMacro::Action::STOP) {
|
||||||
_macros->HideSelectedMacro();
|
_macros->HideSelectedMacro();
|
||||||
@@ -260,6 +415,42 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
|||||||
MacroActionMacro::Action::ENABLE_ACTION ||
|
MacroActionMacro::Action::ENABLE_ACTION ||
|
||||||
_entryData->_action == MacroActionMacro::Action::TOGGLE_ACTION;
|
_entryData->_action == MacroActionMacro::Action::TOGGLE_ACTION;
|
||||||
_actionIndex->setVisible(isModifyingActionState);
|
_actionIndex->setVisible(isModifyingActionState);
|
||||||
|
|
||||||
|
SetLayoutVisible(_conditionLayout,
|
||||||
|
_entryData->_action == MacroActionMacro::Action::RUN);
|
||||||
|
_conditionMacros->setVisible(
|
||||||
|
_entryData->_action == MacroActionMacro::Action::RUN &&
|
||||||
|
_entryData->_runOptions.logic !=
|
||||||
|
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS);
|
||||||
|
_actionTypes->setVisible(_entryData->_action ==
|
||||||
|
MacroActionMacro::Action::RUN);
|
||||||
|
_skipWhenPaused->setVisible(_entryData->_action ==
|
||||||
|
MacroActionMacro::Action::RUN);
|
||||||
|
|
||||||
|
adjustSize();
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMacro::RunOptions::Save(obs_data_t *obj) const
|
||||||
|
{
|
||||||
|
OBSDataAutoRelease data = obs_data_create();
|
||||||
|
obs_data_set_int(data, "logic", static_cast<int>(logic));
|
||||||
|
obs_data_set_bool(data, "runElseActions", runElseActions);
|
||||||
|
obs_data_set_bool(data, "skipWhenPaused", skipWhenPaused);
|
||||||
|
macro.Save(data);
|
||||||
|
obs_data_set_obj(obj, "runOptions", data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMacro::RunOptions::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
if (!obs_data_has_user_value(obj, "runOptions")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OBSDataAutoRelease data = obs_data_get_obj(obj, "runOptions");
|
||||||
|
logic = static_cast<Logic>(obs_data_get_int(data, "logic"));
|
||||||
|
runElseActions = obs_data_get_bool(data, "runElseActions");
|
||||||
|
skipWhenPaused = obs_data_get_bool(data, "skipWhenPaused");
|
||||||
|
macro.Load(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "macro-selection.hpp"
|
#include "macro-selection.hpp"
|
||||||
#include "macro-segment-selection.hpp"
|
#include "macro-segment-selection.hpp"
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -14,12 +15,27 @@ public:
|
|||||||
void LogAction() const;
|
void LogAction() const;
|
||||||
bool Save(obs_data_t *obj) const;
|
bool Save(obs_data_t *obj) const;
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
|
bool PostLoad();
|
||||||
std::string GetShortDesc() const;
|
std::string GetShortDesc() const;
|
||||||
std::string GetId() const { return id; };
|
std::string GetId() const { return id; };
|
||||||
static std::shared_ptr<MacroAction> Create(Macro *m);
|
static std::shared_ptr<MacroAction> Create(Macro *m);
|
||||||
std::shared_ptr<MacroAction> Copy() const;
|
std::shared_ptr<MacroAction> Copy() const;
|
||||||
void ResolveVariablesToFixedValues();
|
void ResolveVariablesToFixedValues();
|
||||||
|
|
||||||
|
struct RunOptions {
|
||||||
|
void Save(obs_data_t *obj) const;
|
||||||
|
void Load(obs_data_t *obj);
|
||||||
|
enum class Logic {
|
||||||
|
IGNORE_CONDITIONS,
|
||||||
|
CONDITIONS,
|
||||||
|
INVERT_CONDITIONS,
|
||||||
|
};
|
||||||
|
Logic logic;
|
||||||
|
bool runElseActions = false;
|
||||||
|
bool skipWhenPaused = true;
|
||||||
|
MacroRef macro;
|
||||||
|
};
|
||||||
|
|
||||||
enum class Action {
|
enum class Action {
|
||||||
PAUSE,
|
PAUSE,
|
||||||
UNPAUSE,
|
UNPAUSE,
|
||||||
@@ -32,8 +48,11 @@ public:
|
|||||||
};
|
};
|
||||||
Action _action = Action::PAUSE;
|
Action _action = Action::PAUSE;
|
||||||
IntVariable _actionIndex = 1;
|
IntVariable _actionIndex = 1;
|
||||||
|
RunOptions _runOptions = {};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void RunActions(Macro *actionMacro) const;
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const std::string id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
@@ -58,18 +77,28 @@ private slots:
|
|||||||
void MacroChanged(const QString &text);
|
void MacroChanged(const QString &text);
|
||||||
void ActionChanged(int value);
|
void ActionChanged(int value);
|
||||||
void ActionIndexChanged(const IntVariable &value);
|
void ActionIndexChanged(const IntVariable &value);
|
||||||
|
void ConditionMacroChanged(const QString &text);
|
||||||
|
void ConditionBehaviorChanged(int value);
|
||||||
|
void ActionTypeChanged(int value);
|
||||||
|
void SkipWhenPausedChanged(int value);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
|
||||||
protected:
|
|
||||||
MacroSelection *_macros;
|
|
||||||
MacroSegmentSelection *_actionIndex;
|
|
||||||
QComboBox *_actions;
|
|
||||||
std::shared_ptr<MacroActionMacro> _entryData;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetWidgetVisibility();
|
void SetWidgetVisibility();
|
||||||
|
|
||||||
|
MacroSelection *_macros;
|
||||||
|
MacroSegmentSelection *_actionIndex;
|
||||||
|
QComboBox *_actions;
|
||||||
|
MacroSelection *_conditionMacros;
|
||||||
|
QComboBox *_conditionBehaviors;
|
||||||
|
QComboBox *_actionTypes;
|
||||||
|
QCheckBox *_skipWhenPaused;
|
||||||
|
QHBoxLayout *_entryLayout;
|
||||||
|
QHBoxLayout *_conditionLayout;
|
||||||
|
|
||||||
|
std::shared_ptr<MacroActionMacro> _entryData;
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,9 @@ void MacroActionQueue::AddActions(ActionQueue *queue)
|
|||||||
|
|
||||||
auto actions = *GetMacroActions(macro.get());
|
auto actions = *GetMacroActions(macro.get());
|
||||||
for (const auto &action : actions) {
|
for (const auto &action : actions) {
|
||||||
queue->Add(action);
|
if (action->Enabled()) {
|
||||||
|
queue->Add(action);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ const static std::map<MacroActionVariable::Type, std::string> actionTypes = {
|
|||||||
"AdvSceneSwitcher.action.variable.type.setToTempvar"},
|
"AdvSceneSwitcher.action.variable.type.setToTempvar"},
|
||||||
{MacroActionVariable::Type::SCENE_ITEM_NAME,
|
{MacroActionVariable::Type::SCENE_ITEM_NAME,
|
||||||
"AdvSceneSwitcher.action.variable.type.sceneItemName"},
|
"AdvSceneSwitcher.action.variable.type.sceneItemName"},
|
||||||
|
{MacroActionVariable::Type::PAD,
|
||||||
|
"AdvSceneSwitcher.action.variable.type.padValue"},
|
||||||
|
{MacroActionVariable::Type::TRUNCATE,
|
||||||
|
"AdvSceneSwitcher.action.variable.type.truncateValue"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void apppend(Variable &var, const std::string &value)
|
static void apppend(Variable &var, const std::string &value)
|
||||||
@@ -217,6 +221,38 @@ static void askForInput(void *param)
|
|||||||
parameters->resultReady = true;
|
parameters->resultReady = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::string truncate(const std::string &input,
|
||||||
|
MacroActionVariable::Direction direction,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
if (input.length() <= length) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (direction == MacroActionVariable::Direction::RIGHT) {
|
||||||
|
return input.substr(0, length);
|
||||||
|
} else {
|
||||||
|
return input.substr(input.length() - length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string pad(const std::string &input,
|
||||||
|
MacroActionVariable::Direction direction, size_t length,
|
||||||
|
char paddingChar)
|
||||||
|
{
|
||||||
|
if (input.length() >= length) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (direction == MacroActionVariable::Direction::RIGHT) {
|
||||||
|
return input +
|
||||||
|
std::string(length - input.length(), paddingChar);
|
||||||
|
} else {
|
||||||
|
return std::string(length - input.length(), paddingChar) +
|
||||||
|
input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroActionVariable::PerformAction()
|
bool MacroActionVariable::PerformAction()
|
||||||
{
|
{
|
||||||
auto var = _variable.lock();
|
auto var = _variable.lock();
|
||||||
@@ -311,7 +347,10 @@ bool MacroActionVariable::PerformAction()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case Type::ENV_VARIABLE: {
|
case Type::ENV_VARIABLE: {
|
||||||
var->SetValue(std::getenv(_envVariableName.c_str()));
|
auto value = std::getenv(_envVariableName.c_str());
|
||||||
|
if (value) {
|
||||||
|
var->SetValue(value);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case Type::SCENE_ITEM_COUNT: {
|
case Type::SCENE_ITEM_COUNT: {
|
||||||
@@ -345,6 +384,14 @@ bool MacroActionVariable::PerformAction()
|
|||||||
case Type::SCENE_ITEM_NAME:
|
case Type::SCENE_ITEM_NAME:
|
||||||
SetToSceneItemName(var.get());
|
SetToSceneItemName(var.get());
|
||||||
return true;
|
return true;
|
||||||
|
case Type::PAD:
|
||||||
|
var->SetValue(pad(var->Value(), _direction, _stringLength,
|
||||||
|
_paddingChar));
|
||||||
|
return true;
|
||||||
|
case Type::TRUNCATE:
|
||||||
|
var->SetValue(
|
||||||
|
truncate(var->Value(), _direction, _stringLength));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -378,6 +425,9 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
|||||||
_scene.Save(obj);
|
_scene.Save(obj);
|
||||||
_tempVar.Save(obj);
|
_tempVar.Save(obj);
|
||||||
_sceneItemIndex.Save(obj, "sceneItemIndex");
|
_sceneItemIndex.Save(obj, "sceneItemIndex");
|
||||||
|
obs_data_set_int(obj, "direction", static_cast<int>(_direction));
|
||||||
|
_stringLength.Save(obj, "stringLength");
|
||||||
|
obs_data_set_int(obj, "paddingChar", _paddingChar);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,6 +459,13 @@ bool MacroActionVariable::Load(obs_data_t *obj)
|
|||||||
_scene.Load(obj);
|
_scene.Load(obj);
|
||||||
_tempVar.Load(obj, GetMacro());
|
_tempVar.Load(obj, GetMacro());
|
||||||
_sceneItemIndex.Load(obj, "sceneItemIndex");
|
_sceneItemIndex.Load(obj, "sceneItemIndex");
|
||||||
|
_direction = static_cast<Direction>(obs_data_get_int(obj, "direction"));
|
||||||
|
_stringLength.Load(obj, "stringLength");
|
||||||
|
if (obs_data_has_user_value(obj, "paddingChar")) {
|
||||||
|
_paddingChar = obs_data_get_int(obj, "paddingChar");
|
||||||
|
} else {
|
||||||
|
_paddingChar = ' ';
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -527,6 +584,16 @@ static inline void populateTypeSelection(QComboBox *list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void populateDirectionSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItems(
|
||||||
|
QStringList()
|
||||||
|
<< obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.variable.truncateOrPadDirection.left")
|
||||||
|
<< obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.variable.truncateOrPadDirection.right"));
|
||||||
|
}
|
||||||
|
|
||||||
MacroActionVariableEdit::MacroActionVariableEdit(
|
MacroActionVariableEdit::MacroActionVariableEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroActionVariable> entryData)
|
QWidget *parent, std::shared_ptr<MacroActionVariable> entryData)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
@@ -564,6 +631,9 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
true)),
|
true)),
|
||||||
_tempVars(new TempVariableSelection(this)),
|
_tempVars(new TempVariableSelection(this)),
|
||||||
_sceneItemIndex(new VariableSpinBox()),
|
_sceneItemIndex(new VariableSpinBox()),
|
||||||
|
_direction(new QComboBox()),
|
||||||
|
_stringLength(new VariableSpinBox()),
|
||||||
|
_paddingCharSelection(new SingleCharSelection()),
|
||||||
_entryLayout(new QHBoxLayout())
|
_entryLayout(new QHBoxLayout())
|
||||||
{
|
{
|
||||||
_numValue->setMinimum(-9999999999);
|
_numValue->setMinimum(-9999999999);
|
||||||
@@ -583,7 +653,9 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
_inputPrompt->setSizePolicy(QSizePolicy::MinimumExpanding,
|
_inputPrompt->setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||||
QSizePolicy::Preferred);
|
QSizePolicy::Preferred);
|
||||||
_sceneItemIndex->setMinimum(1);
|
_sceneItemIndex->setMinimum(1);
|
||||||
|
_stringLength->setMaximum(999);
|
||||||
populateTypeSelection(_actions);
|
populateTypeSelection(_actions);
|
||||||
|
populateDirectionSelection(_direction);
|
||||||
|
|
||||||
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
||||||
this, SLOT(VariableChanged(const QString &)));
|
this, SLOT(VariableChanged(const QString &)));
|
||||||
@@ -639,8 +711,17 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
_sceneItemIndex,
|
_sceneItemIndex,
|
||||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||||
this, SLOT(SceneItemIndexChanged(const NumberVariable<int> &)));
|
this, SLOT(SceneItemIndexChanged(const NumberVariable<int> &)));
|
||||||
|
QWidget::connect(_direction, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(DirectionChanged(int)));
|
||||||
|
QWidget::connect(
|
||||||
|
_stringLength,
|
||||||
|
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||||
|
this, SLOT(StringLengthChanged(const NumberVariable<int> &)));
|
||||||
|
QWidget::connect(_paddingCharSelection,
|
||||||
|
SIGNAL(CharChanged(const QString &)), this,
|
||||||
|
SLOT(CharSelectionChanged(const QString &)));
|
||||||
|
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{variables}}", _variables},
|
{"{{variables}}", _variables},
|
||||||
{"{{variables2}}", _variables2},
|
{"{{variables2}}", _variables2},
|
||||||
{"{{actions}}", _actions},
|
{"{{actions}}", _actions},
|
||||||
@@ -662,9 +743,13 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
{"{{scenes}}", _scenes},
|
{"{{scenes}}", _scenes},
|
||||||
{"{{tempVars}}", _tempVars},
|
{"{{tempVars}}", _tempVars},
|
||||||
{"{{sceneItemIndex}}", _sceneItemIndex},
|
{"{{sceneItemIndex}}", _sceneItemIndex},
|
||||||
|
{"{{direction}}", _direction},
|
||||||
|
{"{{stringLength}}", _stringLength},
|
||||||
|
{"{{paddingCharSelection}}", _paddingCharSelection},
|
||||||
};
|
};
|
||||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.variable.entry"),
|
PlaceWidgets(
|
||||||
_entryLayout, widgetPlaceholders);
|
obs_module_text("AdvSceneSwitcher.action.variable.entry.other"),
|
||||||
|
_entryLayout, widgetPlaceholders);
|
||||||
|
|
||||||
PlaceWidgets(
|
PlaceWidgets(
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
@@ -757,6 +842,10 @@ void MacroActionVariableEdit::UpdateEntryData()
|
|||||||
_scenes->SetScene(_entryData->_scene);
|
_scenes->SetScene(_entryData->_scene);
|
||||||
_tempVars->SetVariable(_entryData->_tempVar);
|
_tempVars->SetVariable(_entryData->_tempVar);
|
||||||
_sceneItemIndex->SetValue(_entryData->_sceneItemIndex);
|
_sceneItemIndex->SetValue(_entryData->_sceneItemIndex);
|
||||||
|
_direction->setCurrentIndex(static_cast<int>(_entryData->_direction));
|
||||||
|
_stringLength->SetValue(_entryData->_stringLength);
|
||||||
|
_paddingCharSelection->setText(
|
||||||
|
QChar::fromLatin1(_entryData->_paddingChar));
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1126,12 +1215,84 @@ void MacroActionVariableEdit::SceneItemIndexChanged(
|
|||||||
_entryData->_sceneItemIndex = value;
|
_entryData->_sceneItemIndex = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionVariableEdit::DirectionChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->_direction =
|
||||||
|
static_cast<MacroActionVariable::Direction>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionVariableEdit::StringLengthChanged(
|
||||||
|
const NumberVariable<int> &value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->_stringLength = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionVariableEdit::CharSelectionChanged(const QString &character)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
if (character.isEmpty()) {
|
||||||
|
_entryData->_paddingChar = ' ';
|
||||||
|
} else {
|
||||||
|
_entryData->_paddingChar = character.toStdString().at(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MacroActionVariableEdit::SetWidgetVisibility()
|
void MacroActionVariableEdit::SetWidgetVisibility()
|
||||||
{
|
{
|
||||||
if (!_entryData) {
|
if (!_entryData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{variables}}", _variables},
|
||||||
|
{"{{variables2}}", _variables2},
|
||||||
|
{"{{actions}}", _actions},
|
||||||
|
{"{{strValue}}", _strValue},
|
||||||
|
{"{{numValue}}", _numValue},
|
||||||
|
{"{{segmentIndex}}", _segmentIdx},
|
||||||
|
{"{{mathExpression}}", _mathExpression},
|
||||||
|
{"{{envVariableName}}", _envVariable},
|
||||||
|
{"{{scenes}}", _scenes},
|
||||||
|
{"{{tempVars}}", _tempVars},
|
||||||
|
{"{{sceneItemIndex}}", _sceneItemIndex},
|
||||||
|
{"{{direction}}", _direction},
|
||||||
|
{"{{stringLength}}", _stringLength},
|
||||||
|
{"{{paddingCharSelection}}", _paddingCharSelection},
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *layoutString = "";
|
||||||
|
if (_entryData->_type == MacroActionVariable::Type::PAD) {
|
||||||
|
layoutString = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.variable.entry.pad");
|
||||||
|
} else if (_entryData->_type == MacroActionVariable::Type::TRUNCATE) {
|
||||||
|
layoutString = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.variable.entry.truncate");
|
||||||
|
} else {
|
||||||
|
layoutString = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.variable.entry.other");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &[_, widget] : widgetPlaceholders) {
|
||||||
|
_entryLayout->removeWidget(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearLayout(_entryLayout);
|
||||||
|
PlaceWidgets(layoutString, _entryLayout, widgetPlaceholders);
|
||||||
|
|
||||||
if (_entryData->_type == MacroActionVariable::Type::SET_FIXED_VALUE ||
|
if (_entryData->_type == MacroActionVariable::Type::SET_FIXED_VALUE ||
|
||||||
_entryData->_type == MacroActionVariable::Type::APPEND ||
|
_entryData->_type == MacroActionVariable::Type::APPEND ||
|
||||||
_entryData->_type == MacroActionVariable::Type::MATH_EXPRESSION ||
|
_entryData->_type == MacroActionVariable::Type::MATH_EXPRESSION ||
|
||||||
@@ -1222,6 +1383,14 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
|||||||
MacroActionVariable::Type::SET_TO_TEMPVAR);
|
MacroActionVariable::Type::SET_TO_TEMPVAR);
|
||||||
_sceneItemIndex->setVisible(_entryData->_type ==
|
_sceneItemIndex->setVisible(_entryData->_type ==
|
||||||
MacroActionVariable::Type::SCENE_ITEM_NAME);
|
MacroActionVariable::Type::SCENE_ITEM_NAME);
|
||||||
|
_direction->setVisible(
|
||||||
|
_entryData->_type == MacroActionVariable::Type::PAD ||
|
||||||
|
_entryData->_type == MacroActionVariable::Type::TRUNCATE);
|
||||||
|
_stringLength->setVisible(
|
||||||
|
_entryData->_type == MacroActionVariable::Type::PAD ||
|
||||||
|
_entryData->_type == MacroActionVariable::Type::TRUNCATE);
|
||||||
|
_paddingCharSelection->setVisible(_entryData->_type ==
|
||||||
|
MacroActionVariable::Type::PAD);
|
||||||
adjustSize();
|
adjustSize();
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "regex-config.hpp"
|
#include "regex-config.hpp"
|
||||||
#include "resizing-text-edit.hpp"
|
#include "resizing-text-edit.hpp"
|
||||||
#include "scene-selection.hpp"
|
#include "scene-selection.hpp"
|
||||||
|
#include "single-char-selection.hpp"
|
||||||
#include "variable-line-edit.hpp"
|
#include "variable-line-edit.hpp"
|
||||||
#include "variable-text-edit.hpp"
|
#include "variable-text-edit.hpp"
|
||||||
#include "variable-spinbox.hpp"
|
#include "variable-spinbox.hpp"
|
||||||
@@ -17,7 +18,7 @@ public:
|
|||||||
bool PerformAction();
|
bool PerformAction();
|
||||||
bool Save(obs_data_t *obj) const;
|
bool Save(obs_data_t *obj) const;
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
bool PostLoad() override;
|
bool PostLoad();
|
||||||
std::string GetShortDesc() const;
|
std::string GetShortDesc() const;
|
||||||
std::string GetId() const { return id; };
|
std::string GetId() const { return id; };
|
||||||
static std::shared_ptr<MacroAction> Create(Macro *m);
|
static std::shared_ptr<MacroAction> Create(Macro *m);
|
||||||
@@ -45,6 +46,8 @@ public:
|
|||||||
EXTRACT_JSON,
|
EXTRACT_JSON,
|
||||||
SET_TO_TEMPVAR,
|
SET_TO_TEMPVAR,
|
||||||
SCENE_ITEM_NAME,
|
SCENE_ITEM_NAME,
|
||||||
|
PAD,
|
||||||
|
TRUNCATE,
|
||||||
};
|
};
|
||||||
|
|
||||||
Type _type = Type::SET_FIXED_VALUE;
|
Type _type = Type::SET_FIXED_VALUE;
|
||||||
@@ -79,6 +82,11 @@ public:
|
|||||||
TempVariableRef _tempVar;
|
TempVariableRef _tempVar;
|
||||||
IntVariable _sceneItemIndex = 1;
|
IntVariable _sceneItemIndex = 1;
|
||||||
|
|
||||||
|
enum class Direction { LEFT, RIGHT };
|
||||||
|
Direction _direction = Direction::LEFT;
|
||||||
|
IntVariable _stringLength = 1;
|
||||||
|
char _paddingChar = '0';
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DecrementCurrentSegmentVariableRef();
|
void DecrementCurrentSegmentVariableRef();
|
||||||
void HandleIndexSubString(Variable *);
|
void HandleIndexSubString(Variable *);
|
||||||
@@ -135,6 +143,9 @@ private slots:
|
|||||||
void SceneChanged(const SceneSelection &);
|
void SceneChanged(const SceneSelection &);
|
||||||
void SelectionChanged(const TempVariableRef &var);
|
void SelectionChanged(const TempVariableRef &var);
|
||||||
void SceneItemIndexChanged(const NumberVariable<int> &);
|
void SceneItemIndexChanged(const NumberVariable<int> &);
|
||||||
|
void DirectionChanged(int);
|
||||||
|
void StringLengthChanged(const NumberVariable<int> &);
|
||||||
|
void CharSelectionChanged(const QString &);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
@@ -175,6 +186,9 @@ private:
|
|||||||
SceneSelectionWidget *_scenes;
|
SceneSelectionWidget *_scenes;
|
||||||
TempVariableSelection *_tempVars;
|
TempVariableSelection *_tempVars;
|
||||||
VariableSpinBox *_sceneItemIndex;
|
VariableSpinBox *_sceneItemIndex;
|
||||||
|
QComboBox *_direction;
|
||||||
|
VariableSpinBox *_stringLength;
|
||||||
|
SingleCharSelection *_paddingCharSelection;
|
||||||
QHBoxLayout *_entryLayout;
|
QHBoxLayout *_entryLayout;
|
||||||
|
|
||||||
std::shared_ptr<MacroActionVariable> _entryData;
|
std::shared_ptr<MacroActionVariable> _entryData;
|
||||||
|
|||||||
@@ -121,8 +121,7 @@ void DurationModifierEdit::Collapse(bool collapse)
|
|||||||
MacroConditionEdit::MacroConditionEdit(
|
MacroConditionEdit::MacroConditionEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
||||||
const std::string &id, bool root)
|
const std::string &id, bool root)
|
||||||
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightConditions,
|
: MacroSegmentEdit(parent),
|
||||||
parent),
|
|
||||||
_logicSelection(new QComboBox()),
|
_logicSelection(new QComboBox()),
|
||||||
_conditionSelection(new FilterComboBox()),
|
_conditionSelection(new FilterComboBox()),
|
||||||
_dur(new DurationModifierEdit()),
|
_dur(new DurationModifierEdit()),
|
||||||
@@ -139,8 +138,6 @@ MacroConditionEdit::MacroConditionEdit(
|
|||||||
QWidget::connect(_dur, SIGNAL(ModifierChanged(DurationModifier::Type)),
|
QWidget::connect(_dur, SIGNAL(ModifierChanged(DurationModifier::Type)),
|
||||||
this,
|
this,
|
||||||
SLOT(DurationModifierChanged(DurationModifier::Type)));
|
SLOT(DurationModifierChanged(DurationModifier::Type)));
|
||||||
QWidget::connect(window(), SIGNAL(HighlightConditionsChanged(bool)),
|
|
||||||
this, SLOT(EnableHighlight(bool)));
|
|
||||||
|
|
||||||
populateLogicSelection(_logicSelection, root);
|
populateLogicSelection(_logicSelection, root);
|
||||||
populateConditionSelection(_conditionSelection);
|
populateConditionSelection(_conditionSelection);
|
||||||
@@ -299,6 +296,7 @@ void AdvSceneSwitcher::AddMacroCondition(int idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (idx < 0 || idx > (int)macro->Conditions().size()) {
|
if (idx < 0 || idx > (int)macro->Conditions().size()) {
|
||||||
|
assert(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,16 +313,31 @@ void AdvSceneSwitcher::AddMacroCondition(int idx)
|
|||||||
id = MacroCondition::GetDefaultID();
|
id = MacroCondition::GetDefaultID();
|
||||||
logic = LogicType::ROOT_NONE;
|
logic = LogicType::ROOT_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OBSDataAutoRelease data;
|
||||||
|
if (idx - 1 >= 0) {
|
||||||
|
data = obs_data_create();
|
||||||
|
macro->Conditions().at(idx - 1)->Save(data);
|
||||||
|
}
|
||||||
|
AddMacroCondition(macro.get(), idx, id, data.Get(), logic);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::AddMacroCondition(Macro *macro, int idx,
|
||||||
|
const std::string &id,
|
||||||
|
obs_data_t *data, LogicType logic)
|
||||||
|
{
|
||||||
|
if (idx < 0 || idx > (int)macro->Conditions().size()) {
|
||||||
|
assert(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
auto cond = macro->Conditions().emplace(
|
auto cond = macro->Conditions().emplace(
|
||||||
macro->Conditions().begin() + idx,
|
macro->Conditions().begin() + idx,
|
||||||
MacroConditionFactory::Create(id, macro.get()));
|
MacroConditionFactory::Create(id, macro));
|
||||||
if (idx - 1 >= 0) {
|
if (data) {
|
||||||
auto data = obs_data_create();
|
|
||||||
macro->Conditions().at(idx - 1)->Save(data);
|
|
||||||
macro->Conditions().at(idx)->Load(data);
|
macro->Conditions().at(idx)->Load(data);
|
||||||
obs_data_release(data);
|
|
||||||
}
|
}
|
||||||
macro->Conditions().at(idx)->PostLoad();
|
macro->Conditions().at(idx)->PostLoad();
|
||||||
RunPostLoadSteps();
|
RunPostLoadSteps();
|
||||||
@@ -337,6 +350,7 @@ void AdvSceneSwitcher::AddMacroCondition(int idx)
|
|||||||
SetConditionData(*macro);
|
SetConditionData(*macro);
|
||||||
}
|
}
|
||||||
HighlightCondition(idx);
|
HighlightCondition(idx);
|
||||||
|
ui->conditionsList->SetHelpMsgVisible(false);
|
||||||
emit(MacroSegmentOrderChanged());
|
emit(MacroSegmentOrderChanged());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +369,6 @@ void AdvSceneSwitcher::on_conditionAdd_clicked()
|
|||||||
if (currentConditionIdx != -1) {
|
if (currentConditionIdx != -1) {
|
||||||
MacroConditionSelectionChanged(currentConditionIdx + 1);
|
MacroConditionSelectionChanged(currentConditionIdx + 1);
|
||||||
}
|
}
|
||||||
ui->conditionsList->SetHelpMsgVisible(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::RemoveMacroCondition(int idx)
|
void AdvSceneSwitcher::RemoveMacroCondition(int idx)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public:
|
|||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj) const;
|
bool Save(obs_data_t *obj) const;
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
bool PostLoad() override;
|
bool PostLoad();
|
||||||
std::string GetShortDesc() const;
|
std::string GetShortDesc() const;
|
||||||
std::string GetId() const { return id; };
|
std::string GetId() const { return id; };
|
||||||
static std::shared_ptr<MacroCondition> Create(Macro *m)
|
static std::shared_ptr<MacroCondition> Create(Macro *m)
|
||||||
|
|||||||
@@ -8,8 +8,13 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
|
static bool usePlainText = false;
|
||||||
|
|
||||||
MacroExportImportDialog::MacroExportImportDialog(Type type)
|
MacroExportImportDialog::MacroExportImportDialog(Type type)
|
||||||
: QDialog(nullptr), _importExportString(new QPlainTextEdit(this))
|
: QDialog(nullptr),
|
||||||
|
_importExportString(new QPlainTextEdit(this)),
|
||||||
|
_usePlainText(new QCheckBox(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.macroTab.export.usePlainText")))
|
||||||
{
|
{
|
||||||
_importExportString->setReadOnly(type == Type::EXPORT_MACRO);
|
_importExportString->setReadOnly(type == Type::EXPORT_MACRO);
|
||||||
auto label = new QLabel(obs_module_text(
|
auto label = new QLabel(obs_module_text(
|
||||||
@@ -29,9 +34,15 @@ MacroExportImportDialog::MacroExportImportDialog(Type type)
|
|||||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
buttons->setCenterButtons(true);
|
buttons->setCenterButtons(true);
|
||||||
|
|
||||||
|
_usePlainText->setChecked(usePlainText);
|
||||||
|
_usePlainText->setVisible(type == Type::EXPORT_MACRO);
|
||||||
|
connect(_usePlainText, &QCheckBox::stateChanged, this,
|
||||||
|
&MacroExportImportDialog::UsePlainTextChanged);
|
||||||
|
|
||||||
auto layout = new QVBoxLayout;
|
auto layout = new QVBoxLayout;
|
||||||
layout->addWidget(label);
|
layout->addWidget(label);
|
||||||
layout->addWidget(_importExportString);
|
layout->addWidget(_importExportString);
|
||||||
|
layout->addWidget(_usePlainText);
|
||||||
layout->addWidget(buttons);
|
layout->addWidget(buttons);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
@@ -64,6 +75,21 @@ void MacroExportImportDialog::ExportMacros(const QString &json)
|
|||||||
dialog.exec();
|
dialog.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroExportImportDialog::UsePlainTextChanged(int value)
|
||||||
|
{
|
||||||
|
if (usePlainText == (!!value)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto current = _importExportString->toPlainText();
|
||||||
|
if (usePlainText) {
|
||||||
|
_importExportString->setPlainText(compressMacroString(current));
|
||||||
|
} else {
|
||||||
|
_importExportString->setPlainText(
|
||||||
|
decompressMacroString(current));
|
||||||
|
}
|
||||||
|
usePlainText = value;
|
||||||
|
}
|
||||||
|
|
||||||
static bool isValidData(const QString &json)
|
static bool isValidData(const QString &json)
|
||||||
{
|
{
|
||||||
OBSDataAutoRelease data =
|
OBSDataAutoRelease data =
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <QCheckBox>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QPlainTextEdit>
|
#include <QPlainTextEdit>
|
||||||
|
|
||||||
@@ -13,8 +14,12 @@ public:
|
|||||||
static void ExportMacros(const QString &json);
|
static void ExportMacros(const QString &json);
|
||||||
static bool ImportMacros(QString &json);
|
static bool ImportMacros(QString &json);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void UsePlainTextChanged(int);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPlainTextEdit *_importExportString;
|
QPlainTextEdit *_importExportString;
|
||||||
|
QCheckBox *_usePlainText;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ MacroPropertiesDialog::MacroPropertiesDialog(QWidget *parent,
|
|||||||
"AdvSceneSwitcher.macroTab.currentDisableHotkeys"))),
|
"AdvSceneSwitcher.macroTab.currentDisableHotkeys"))),
|
||||||
_currentSkipOnStartup(new QCheckBox(obs_module_text(
|
_currentSkipOnStartup(new QCheckBox(obs_module_text(
|
||||||
"AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup"))),
|
"AdvSceneSwitcher.macroTab.currentSkipExecutionOnStartup"))),
|
||||||
|
_currentStopActionsIfNotDone(new QCheckBox(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.macroTab.currentStopActionsIfNotDone"))),
|
||||||
_currentMacroRegisterDock(new QCheckBox(obs_module_text(
|
_currentMacroRegisterDock(new QCheckBox(obs_module_text(
|
||||||
"AdvSceneSwitcher.macroTab.currentRegisterDock"))),
|
"AdvSceneSwitcher.macroTab.currentRegisterDock"))),
|
||||||
_currentMacroDockAddRunButton(new QCheckBox(obs_module_text(
|
_currentMacroDockAddRunButton(new QCheckBox(obs_module_text(
|
||||||
@@ -96,6 +98,7 @@ MacroPropertiesDialog::MacroPropertiesDialog(QWidget *parent,
|
|||||||
obs_module_text("AdvSceneSwitcher.macroTab.generalSettings"));
|
obs_module_text("AdvSceneSwitcher.macroTab.generalSettings"));
|
||||||
auto generalLayout = new QVBoxLayout;
|
auto generalLayout = new QVBoxLayout;
|
||||||
generalLayout->addWidget(_currentSkipOnStartup);
|
generalLayout->addWidget(_currentSkipOnStartup);
|
||||||
|
generalLayout->addWidget(_currentStopActionsIfNotDone);
|
||||||
generalOptions->setLayout(generalLayout);
|
generalOptions->setLayout(generalLayout);
|
||||||
|
|
||||||
int row = 0;
|
int row = 0;
|
||||||
@@ -184,14 +187,17 @@ MacroPropertiesDialog::MacroPropertiesDialog(QWidget *parent,
|
|||||||
_conditions->setChecked(prop._highlightConditions);
|
_conditions->setChecked(prop._highlightConditions);
|
||||||
_actions->setChecked(prop._highlightActions);
|
_actions->setChecked(prop._highlightActions);
|
||||||
_newMacroRegisterHotkeys->setChecked(prop._newMacroRegisterHotkeys);
|
_newMacroRegisterHotkeys->setChecked(prop._newMacroRegisterHotkeys);
|
||||||
|
|
||||||
if (!macro || macro->IsGroup()) {
|
if (!macro || macro->IsGroup()) {
|
||||||
hotkeyOptions->hide();
|
hotkeyOptions->hide();
|
||||||
generalOptions->hide();
|
generalOptions->hide();
|
||||||
_dockOptions->hide();
|
_dockOptions->hide();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_currentMacroRegisterHotkeys->setChecked(macro->PauseHotkeysEnabled());
|
_currentMacroRegisterHotkeys->setChecked(macro->PauseHotkeysEnabled());
|
||||||
_currentSkipOnStartup->setChecked(macro->SkipExecOnStart());
|
_currentSkipOnStartup->setChecked(macro->SkipExecOnStart());
|
||||||
|
_currentStopActionsIfNotDone->setChecked(macro->StopActionsIfNotDone());
|
||||||
const bool dockEnabled = macro->DockEnabled();
|
const bool dockEnabled = macro->DockEnabled();
|
||||||
_currentMacroRegisterDock->setChecked(dockEnabled);
|
_currentMacroRegisterDock->setChecked(dockEnabled);
|
||||||
_currentMacroDockAddRunButton->setChecked(macro->DockHasRunButton());
|
_currentMacroDockAddRunButton->setChecked(macro->DockHasRunButton());
|
||||||
@@ -260,6 +266,7 @@ void MacroPropertiesDialog::DockEnableChanged(int enabled)
|
|||||||
SetGridLayoutRowVisible(
|
SetGridLayoutRowVisible(
|
||||||
_dockLayout, _conditionsFalseTextRow,
|
_dockLayout, _conditionsFalseTextRow,
|
||||||
enabled && _currentMacroDockAddStatusLabel->isChecked());
|
enabled && _currentMacroDockAddStatusLabel->isChecked());
|
||||||
|
|
||||||
Resize();
|
Resize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,6 +317,8 @@ bool MacroPropertiesDialog::AskForSettings(QWidget *parent,
|
|||||||
macro->EnablePauseHotkeys(
|
macro->EnablePauseHotkeys(
|
||||||
dialog._currentMacroRegisterHotkeys->isChecked());
|
dialog._currentMacroRegisterHotkeys->isChecked());
|
||||||
macro->SetSkipExecOnStart(dialog._currentSkipOnStartup->isChecked());
|
macro->SetSkipExecOnStart(dialog._currentSkipOnStartup->isChecked());
|
||||||
|
macro->SetStopActionsIfNotDone(
|
||||||
|
dialog._currentStopActionsIfNotDone->isChecked());
|
||||||
macro->EnableDock(dialog._currentMacroRegisterDock->isChecked());
|
macro->EnableDock(dialog._currentMacroRegisterDock->isChecked());
|
||||||
macro->SetDockHasRunButton(
|
macro->SetDockHasRunButton(
|
||||||
dialog._currentMacroDockAddRunButton->isChecked());
|
dialog._currentMacroDockAddRunButton->isChecked());
|
||||||
@@ -328,6 +337,7 @@ bool MacroPropertiesDialog::AskForSettings(QWidget *parent,
|
|||||||
dialog._conditionsTrueStatusText->text().toStdString());
|
dialog._conditionsTrueStatusText->text().toStdString());
|
||||||
macro->SetConditionsFalseStatusText(
|
macro->SetConditionsFalseStatusText(
|
||||||
dialog._conditionsFalseStatusText->text().toStdString());
|
dialog._conditionsFalseStatusText->text().toStdString());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ private:
|
|||||||
// Current macro specific settings
|
// Current macro specific settings
|
||||||
QCheckBox *_currentMacroRegisterHotkeys;
|
QCheckBox *_currentMacroRegisterHotkeys;
|
||||||
QCheckBox *_currentSkipOnStartup;
|
QCheckBox *_currentSkipOnStartup;
|
||||||
|
QCheckBox *_currentStopActionsIfNotDone;
|
||||||
QCheckBox *_currentMacroRegisterDock;
|
QCheckBox *_currentMacroRegisterDock;
|
||||||
QCheckBox *_currentMacroDockAddRunButton;
|
QCheckBox *_currentMacroDockAddRunButton;
|
||||||
QCheckBox *_currentMacroDockAddPauseButton;
|
QCheckBox *_currentMacroDockAddPauseButton;
|
||||||
|
|||||||
104
lib/macro/macro-segment-copy-paste.cpp
Normal file
104
lib/macro/macro-segment-copy-paste.cpp
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#include "advanced-scene-switcher.hpp"
|
||||||
|
#include "macro.hpp"
|
||||||
|
|
||||||
|
#include <QShortcut>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
struct MacroSegmentCopyInfo {
|
||||||
|
enum class Type { NONE, CONDITION, ACTION, ELSE };
|
||||||
|
Type type = Type::NONE;
|
||||||
|
std::shared_ptr<MacroSegment> segment;
|
||||||
|
};
|
||||||
|
static MacroSegmentCopyInfo copyInfo;
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::CopyMacroSegment()
|
||||||
|
{
|
||||||
|
copyInfo.segment.reset();
|
||||||
|
copyInfo.type = MacroSegmentCopyInfo::Type::NONE;
|
||||||
|
|
||||||
|
if (currentConditionIdx == -1 && currentActionIdx == -1 &&
|
||||||
|
currentElseActionIdx == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto macro = GetSelectedMacro();
|
||||||
|
if (!macro) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentConditionIdx != -1) {
|
||||||
|
copyInfo.type = MacroSegmentCopyInfo::Type::CONDITION;
|
||||||
|
copyInfo.segment = macro->Conditions().at(currentConditionIdx);
|
||||||
|
} else if (currentActionIdx != -1) {
|
||||||
|
copyInfo.type = MacroSegmentCopyInfo::Type::ACTION;
|
||||||
|
copyInfo.segment = macro->Actions().at(currentActionIdx);
|
||||||
|
} else if (currentElseActionIdx != -1) {
|
||||||
|
copyInfo.type = MacroSegmentCopyInfo::Type::ELSE;
|
||||||
|
copyInfo.segment =
|
||||||
|
macro->ElseActions().at(currentElseActionIdx);
|
||||||
|
} else {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::PasteMacroSegment()
|
||||||
|
{
|
||||||
|
if (copyInfo.type == MacroSegmentCopyInfo::Type::NONE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto macro = GetSelectedMacro();
|
||||||
|
if (!macro || !copyInfo.segment) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSDataAutoRelease data = obs_data_create();
|
||||||
|
copyInfo.segment->Save(data);
|
||||||
|
|
||||||
|
switch (copyInfo.type) {
|
||||||
|
case MacroSegmentCopyInfo::Type::CONDITION: {
|
||||||
|
const auto condition = std::static_pointer_cast<MacroCondition>(
|
||||||
|
copyInfo.segment);
|
||||||
|
auto logic = condition->GetLogicType();
|
||||||
|
if (logic > LogicType::ROOT_LAST &&
|
||||||
|
macro->Conditions().empty()) {
|
||||||
|
logic = LogicType::ROOT_NONE;
|
||||||
|
}
|
||||||
|
if (logic < LogicType::ROOT_LAST &&
|
||||||
|
!macro->Conditions().empty()) {
|
||||||
|
logic = LogicType::OR;
|
||||||
|
}
|
||||||
|
AddMacroCondition(macro.get(), macro->Conditions().size(),
|
||||||
|
copyInfo.segment->GetId(), data.Get(), logic);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case MacroSegmentCopyInfo::Type::ACTION:
|
||||||
|
AddMacroAction(macro.get(), macro->Actions().size(),
|
||||||
|
copyInfo.segment->GetId(), data.Get());
|
||||||
|
break;
|
||||||
|
case MacroSegmentCopyInfo::Type::ELSE:
|
||||||
|
AddMacroElseAction(macro.get(), macro->ElseActions().size(),
|
||||||
|
copyInfo.segment->GetId(), data.Get());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroSegmentIsInClipboard()
|
||||||
|
{
|
||||||
|
return copyInfo.type != MacroSegmentCopyInfo::Type::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupSegmentCopyPasteShortcutHandlers(AdvSceneSwitcher *window)
|
||||||
|
{
|
||||||
|
auto copyShortcut = new QShortcut(QKeySequence("Ctrl+C"), window);
|
||||||
|
QWidget::connect(copyShortcut, &QShortcut::activated, window,
|
||||||
|
&AdvSceneSwitcher::CopyMacroSegment);
|
||||||
|
auto pasteShortcut = new QShortcut(QKeySequence("Ctrl+V"), window);
|
||||||
|
QWidget::connect(pasteShortcut, &QShortcut::activated, window,
|
||||||
|
&AdvSceneSwitcher::PasteMacroSegment);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
8
lib/macro/macro-segment-copy-paste.hpp
Normal file
8
lib/macro/macro-segment-copy-paste.hpp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace advss {
|
||||||
|
|
||||||
|
class AdvSceneSwitcher;
|
||||||
|
|
||||||
|
bool MacroSegmentIsInClipboard();
|
||||||
|
void SetupSegmentCopyPasteShortcutHandlers(AdvSceneSwitcher *window);
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -176,7 +176,8 @@ bool MacroSegmentList::eventFilter(QObject *object, QEvent *event)
|
|||||||
|
|
||||||
void MacroSegmentList::mousePressEvent(QMouseEvent *event)
|
void MacroSegmentList::mousePressEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (event->button() == Qt::LeftButton) {
|
if (event->button() == Qt::LeftButton ||
|
||||||
|
event->button() == Qt::RightButton) {
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
_dragPosition = GetDragIndex(event->globalPos());
|
_dragPosition = GetDragIndex(event->globalPos());
|
||||||
#else
|
#else
|
||||||
@@ -246,6 +247,11 @@ MacroSegmentEdit *MacroSegmentList::WidgetAt(int idx)
|
|||||||
return static_cast<MacroSegmentEdit *>(item->widget());
|
return static_cast<MacroSegmentEdit *>(item->widget());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MacroSegmentEdit *MacroSegmentList::WidgetAt(const QPoint &pos)
|
||||||
|
{
|
||||||
|
return WidgetAt(GetSegmentIndexFromPos(mapToGlobal(pos)));
|
||||||
|
}
|
||||||
|
|
||||||
void MacroSegmentList::HideLastDropLine()
|
void MacroSegmentList::HideLastDropLine()
|
||||||
{
|
{
|
||||||
if (_dropLineIdx >= 0 && _dropLineIdx < _contentLayout->count()) {
|
if (_dropLineIdx >= 0 && _dropLineIdx < _contentLayout->count()) {
|
||||||
@@ -319,7 +325,7 @@ QRect MacroSegmentList::GetContentItemRectWithPadding(int idx)
|
|||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MacroSegmentList::GetWidgetIdx(const QPoint &pos)
|
int MacroSegmentList::GetSegmentIndexFromPos(const QPoint &pos)
|
||||||
{
|
{
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
for (int i = 0; i < _contentLayout->count(); ++i) {
|
for (int i = 0; i < _contentLayout->count(); ++i) {
|
||||||
@@ -359,7 +365,7 @@ void MacroSegmentList::CheckScroll()
|
|||||||
|
|
||||||
void MacroSegmentList::CheckDropLine(const QPoint &pos)
|
void MacroSegmentList::CheckDropLine(const QPoint &pos)
|
||||||
{
|
{
|
||||||
int idx = GetWidgetIdx(pos);
|
int idx = GetSegmentIndexFromPos(pos);
|
||||||
if (idx == _dragPosition) {
|
if (idx == _dragPosition) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -410,7 +416,7 @@ bool MacroSegmentList::IsInListArea(const QPoint &pos)
|
|||||||
|
|
||||||
int MacroSegmentList::GetDropIndex(const QPoint &pos)
|
int MacroSegmentList::GetDropIndex(const QPoint &pos)
|
||||||
{
|
{
|
||||||
int idx = GetWidgetIdx(pos);
|
int idx = GetSegmentIndexFromPos(pos);
|
||||||
if (idx == _dragPosition) {
|
if (idx == _dragPosition) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ public:
|
|||||||
void SetHelpMsg(const QString &msg);
|
void SetHelpMsg(const QString &msg);
|
||||||
void SetHelpMsgVisible(bool visible);
|
void SetHelpMsgVisible(bool visible);
|
||||||
MacroSegmentEdit *WidgetAt(int idx);
|
MacroSegmentEdit *WidgetAt(int idx);
|
||||||
|
MacroSegmentEdit *WidgetAt(const QPoint &);
|
||||||
void Insert(int idx, MacroSegmentEdit *widget);
|
void Insert(int idx, MacroSegmentEdit *widget);
|
||||||
void Add(QWidget *widget);
|
void Add(QWidget *widget);
|
||||||
void Remove(int idx);
|
void Remove(int idx);
|
||||||
@@ -44,7 +45,7 @@ protected:
|
|||||||
private:
|
private:
|
||||||
int GetDragIndex(const QPoint &);
|
int GetDragIndex(const QPoint &);
|
||||||
int GetDropIndex(const QPoint &);
|
int GetDropIndex(const QPoint &);
|
||||||
int GetWidgetIdx(const QPoint &);
|
int GetSegmentIndexFromPos(const QPoint &);
|
||||||
void CheckScroll();
|
void CheckScroll();
|
||||||
void CheckDropLine(const QPoint &);
|
void CheckDropLine(const QPoint &);
|
||||||
bool IsInListArea(const QPoint &);
|
bool IsInListArea(const QPoint &);
|
||||||
|
|||||||
@@ -13,19 +13,37 @@
|
|||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
MacroSegment::MacroSegment(Macro *m, bool supportsVariableValue)
|
MacroSegment::MacroSegment(Macro *m, bool supportsVariableValue)
|
||||||
: _macro(m), _supportsVariableValue(supportsVariableValue)
|
: _macro(m),
|
||||||
|
_supportsVariableValue(supportsVariableValue)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroSegment::Save(obs_data_t *obj) const
|
bool MacroSegment::Save(obs_data_t *obj) const
|
||||||
{
|
{
|
||||||
obs_data_set_bool(obj, "collapsed", static_cast<int>(_collapsed));
|
OBSDataAutoRelease data = obs_data_create();
|
||||||
|
obs_data_set_bool(data, "collapsed", _collapsed);
|
||||||
|
obs_data_set_bool(data, "useCustomLabel", _useCustomLabel);
|
||||||
|
obs_data_set_string(data, "customLabel", _customLabel.c_str());
|
||||||
|
obs_data_set_obj(obj, "segmentSettings", data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroSegment::Load(obs_data_t *obj)
|
bool MacroSegment::Load(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
_collapsed = obs_data_get_bool(obj, "collapsed");
|
// TODO: remove this fallback at some point
|
||||||
|
if (obs_data_has_user_value(obj, "segmentSettings")) {
|
||||||
|
OBSDataAutoRelease data =
|
||||||
|
obs_data_get_obj(obj, "segmentSettings");
|
||||||
|
_collapsed = obs_data_get_bool(data, "collapsed");
|
||||||
|
_useCustomLabel = obs_data_get_bool(data, "useCustomLabel");
|
||||||
|
_customLabel = obs_data_get_string(data, "customLabel");
|
||||||
|
} else {
|
||||||
|
_collapsed = obs_data_get_bool(obj, "collapsed");
|
||||||
|
_useCustomLabel = false;
|
||||||
|
_customLabel = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.macroTab.segment.defaultCustomLabel");
|
||||||
|
}
|
||||||
|
|
||||||
ClearAvailableTempvars();
|
ClearAvailableTempvars();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -41,12 +59,12 @@ std::string MacroSegment::GetShortDesc() const
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroSegment::SetHighlight()
|
void MacroSegment::EnableHighlight()
|
||||||
{
|
{
|
||||||
_highlight = true;
|
_highlight = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroSegment::Highlight()
|
bool MacroSegment::GetHighlightAndReset()
|
||||||
{
|
{
|
||||||
if (_highlight) {
|
if (_highlight) {
|
||||||
_highlight = false;
|
_highlight = false;
|
||||||
@@ -176,7 +194,7 @@ void DecrementVariableRef(MacroSegment *segment)
|
|||||||
segment->_variableRefs--;
|
segment->_variableRefs--;
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroSegmentEdit::MacroSegmentEdit(bool highlight, QWidget *parent)
|
MacroSegmentEdit::MacroSegmentEdit(QWidget *parent)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
_section(new Section(300)),
|
_section(new Section(300)),
|
||||||
_headerInfo(new QLabel()),
|
_headerInfo(new QLabel()),
|
||||||
@@ -185,8 +203,7 @@ MacroSegmentEdit::MacroSegmentEdit(bool highlight, QWidget *parent)
|
|||||||
_noBorderframe(new QFrame),
|
_noBorderframe(new QFrame),
|
||||||
_borderFrame(new QFrame),
|
_borderFrame(new QFrame),
|
||||||
_dropLineAbove(new QFrame),
|
_dropLineAbove(new QFrame),
|
||||||
_dropLineBelow(new QFrame),
|
_dropLineBelow(new QFrame)
|
||||||
_showHighlight(highlight)
|
|
||||||
{
|
{
|
||||||
_dropLineAbove->setLineWidth(3);
|
_dropLineAbove->setLineWidth(3);
|
||||||
_dropLineAbove->setFixedHeight(11);
|
_dropLineAbove->setFixedHeight(11);
|
||||||
@@ -264,10 +281,6 @@ MacroSegmentEdit::MacroSegmentEdit(bool highlight, QWidget *parent)
|
|||||||
|
|
||||||
// Enable dragging while clicking on the header text
|
// Enable dragging while clicking on the header text
|
||||||
_headerInfo->installEventFilter(this);
|
_headerInfo->installEventFilter(this);
|
||||||
|
|
||||||
_timer.setInterval(1500);
|
|
||||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(Highlight()));
|
|
||||||
_timer.start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroSegmentEdit::eventFilter(QObject *obj, QEvent *ev)
|
bool MacroSegmentEdit::eventFilter(QObject *obj, QEvent *ev)
|
||||||
@@ -295,6 +308,12 @@ bool MacroSegmentEdit::eventFilter(QObject *obj, QEvent *ev)
|
|||||||
|
|
||||||
void MacroSegmentEdit::HeaderInfoChanged(const QString &text)
|
void MacroSegmentEdit::HeaderInfoChanged(const QString &text)
|
||||||
{
|
{
|
||||||
|
if (Data() && Data()->GetUseCustomLabel()) {
|
||||||
|
_headerInfo->show();
|
||||||
|
_headerInfo->setText(
|
||||||
|
QString::fromStdString(Data()->GetCustomLabel()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
_headerInfo->setVisible(!text.isEmpty());
|
_headerInfo->setVisible(!text.isEmpty());
|
||||||
_headerInfo->setText(text);
|
_headerInfo->setText(text);
|
||||||
}
|
}
|
||||||
@@ -306,22 +325,6 @@ void MacroSegmentEdit::Collapsed(bool collapsed)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroSegmentEdit::Highlight()
|
|
||||||
{
|
|
||||||
if (!Data()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_showHighlight && Data()->Highlight()) {
|
|
||||||
PulseWidget(this, Qt::green, QColor(0, 0, 0, 0), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroSegmentEdit::EnableHighlight(bool value)
|
|
||||||
{
|
|
||||||
_showHighlight = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroSegmentEdit::SetFocusPolicyOfWidgets()
|
void MacroSegmentEdit::SetFocusPolicyOfWidgets()
|
||||||
{
|
{
|
||||||
QList<QWidget *> widgets = this->findChildren<QWidget *>();
|
QList<QWidget *> widgets = this->findChildren<QWidget *>();
|
||||||
|
|||||||
@@ -28,13 +28,17 @@ public:
|
|||||||
int GetIndex() const { return _idx; }
|
int GetIndex() const { return _idx; }
|
||||||
void SetCollapsed(bool collapsed) { _collapsed = collapsed; }
|
void SetCollapsed(bool collapsed) { _collapsed = collapsed; }
|
||||||
bool GetCollapsed() const { return _collapsed; }
|
bool GetCollapsed() const { return _collapsed; }
|
||||||
|
void SetUseCustomLabel(bool enable) { _useCustomLabel = enable; }
|
||||||
|
bool GetUseCustomLabel() const { return _useCustomLabel; }
|
||||||
|
void SetCustomLabel(const std::string &label) { _customLabel = label; }
|
||||||
|
std::string GetCustomLabel() const { return _customLabel; }
|
||||||
virtual bool Save(obs_data_t *obj) const = 0;
|
virtual bool Save(obs_data_t *obj) const = 0;
|
||||||
virtual bool Load(obs_data_t *obj) = 0;
|
virtual bool Load(obs_data_t *obj) = 0;
|
||||||
virtual bool PostLoad();
|
virtual bool PostLoad();
|
||||||
virtual std::string GetShortDesc() const;
|
virtual std::string GetShortDesc() const;
|
||||||
virtual std::string GetId() const = 0;
|
virtual std::string GetId() const = 0;
|
||||||
void SetHighlight();
|
void EnableHighlight();
|
||||||
bool Highlight();
|
bool GetHighlightAndReset();
|
||||||
virtual std::string GetVariableValue() const;
|
virtual std::string GetVariableValue() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -63,6 +67,11 @@ private:
|
|||||||
bool _highlight = false;
|
bool _highlight = false;
|
||||||
bool _collapsed = false;
|
bool _collapsed = false;
|
||||||
|
|
||||||
|
// Custom header labels
|
||||||
|
bool _useCustomLabel = false;
|
||||||
|
std::string _customLabel = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.macroTab.segment.defaultCustomLabel");
|
||||||
|
|
||||||
// Variable helpers
|
// Variable helpers
|
||||||
const bool _supportsVariableValue = false;
|
const bool _supportsVariableValue = false;
|
||||||
int _variableRefs = 0;
|
int _variableRefs = 0;
|
||||||
@@ -78,7 +87,7 @@ class MacroSegmentEdit : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MacroSegmentEdit(bool highlight, QWidget *parent = nullptr);
|
MacroSegmentEdit(QWidget *parent = nullptr);
|
||||||
// Use this function to avoid accidental edits when scrolling through
|
// Use this function to avoid accidental edits when scrolling through
|
||||||
// list of actions and conditions
|
// list of actions and conditions
|
||||||
void SetFocusPolicyOfWidgets();
|
void SetFocusPolicyOfWidgets();
|
||||||
@@ -86,11 +95,11 @@ public:
|
|||||||
void SetSelected(bool);
|
void SetSelected(bool);
|
||||||
virtual std::shared_ptr<MacroSegment> Data() const = 0;
|
virtual std::shared_ptr<MacroSegment> Data() const = 0;
|
||||||
|
|
||||||
protected slots:
|
public slots:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
void Collapsed(bool);
|
void Collapsed(bool);
|
||||||
void Highlight();
|
|
||||||
void EnableHighlight(bool);
|
|
||||||
signals:
|
signals:
|
||||||
void MacroAdded(const QString &name);
|
void MacroAdded(const QString &name);
|
||||||
void MacroRemoved(const QString &name);
|
void MacroRemoved(const QString &name);
|
||||||
@@ -132,9 +141,6 @@ private:
|
|||||||
QFrame *_dropLineAbove;
|
QFrame *_dropLineAbove;
|
||||||
QFrame *_dropLineBelow;
|
QFrame *_dropLineBelow;
|
||||||
|
|
||||||
bool _showHighlight;
|
|
||||||
QTimer _timer;
|
|
||||||
|
|
||||||
friend class MacroSegmentList;
|
friend class MacroSegmentList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,9 @@ void MacroSelection::MacroRename(const QString &oldName, const QString &newName)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroSelectionDialog::MacroSelectionDialog(QWidget *)
|
MacroSelectionDialog::MacroSelectionDialog(QWidget *parent)
|
||||||
|
: QDialog(parent),
|
||||||
|
_macroSelection(new MacroSelection(this))
|
||||||
{
|
{
|
||||||
setModal(true);
|
setModal(true);
|
||||||
setWindowModality(Qt::WindowModality::ApplicationModal);
|
setWindowModality(Qt::WindowModality::ApplicationModal);
|
||||||
@@ -103,21 +105,20 @@ MacroSelectionDialog::MacroSelectionDialog(QWidget *)
|
|||||||
setMinimumWidth(350);
|
setMinimumWidth(350);
|
||||||
setMinimumHeight(70);
|
setMinimumHeight(70);
|
||||||
|
|
||||||
QDialogButtonBox *buttonbox = new QDialogButtonBox(
|
auto buttonbox = new QDialogButtonBox(QDialogButtonBox::Ok |
|
||||||
QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
QDialogButtonBox::Cancel);
|
||||||
|
|
||||||
buttonbox->setCenterButtons(true);
|
buttonbox->setCenterButtons(true);
|
||||||
connect(buttonbox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
connect(buttonbox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
|
||||||
_macroSelection = new MacroSelection(window());
|
auto selectionLayout = new QHBoxLayout;
|
||||||
auto *selectionLayout = new QHBoxLayout;
|
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{macroSelection}}", _macroSelection},
|
{"{{macroSelection}}", _macroSelection},
|
||||||
};
|
};
|
||||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.askForMacro"),
|
PlaceWidgets(obs_module_text("AdvSceneSwitcher.askForMacro"),
|
||||||
selectionLayout, widgetPlaceholders);
|
selectionLayout, widgetPlaceholders);
|
||||||
auto *layout = new QVBoxLayout();
|
auto layout = new QVBoxLayout();
|
||||||
layout->addLayout(selectionLayout);
|
layout->addLayout(selectionLayout);
|
||||||
layout->addWidget(buttonbox);
|
layout->addWidget(buttonbox);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
@@ -125,7 +126,7 @@ MacroSelectionDialog::MacroSelectionDialog(QWidget *)
|
|||||||
|
|
||||||
bool MacroSelectionDialog::AskForMacro(QWidget *parent, std::string ¯oName)
|
bool MacroSelectionDialog::AskForMacro(QWidget *parent, std::string ¯oName)
|
||||||
{
|
{
|
||||||
MacroSelectionDialog dialog(parent);
|
MacroSelectionDialog dialog(GetSettingsWindow());
|
||||||
dialog.setWindowTitle(obs_module_text("AdvSceneSwitcher.windowTitle"));
|
dialog.setWindowTitle(obs_module_text("AdvSceneSwitcher.windowTitle"));
|
||||||
|
|
||||||
if (dialog.exec() != DialogCode::Accepted) {
|
if (dialog.exec() != DialogCode::Accepted) {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
#include "advanced-scene-switcher.hpp"
|
#include "advanced-scene-switcher.hpp"
|
||||||
|
#include "action-queue.hpp"
|
||||||
#include "macro-action-edit.hpp"
|
#include "macro-action-edit.hpp"
|
||||||
#include "macro-condition-edit.hpp"
|
#include "macro-condition-edit.hpp"
|
||||||
#include "macro-export-import-dialog.hpp"
|
#include "macro-export-import-dialog.hpp"
|
||||||
#include "macro-properties.hpp"
|
#include "macro-properties.hpp"
|
||||||
|
#include "macro-segment-copy-paste.hpp"
|
||||||
#include "macro-tree.hpp"
|
#include "macro-tree.hpp"
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
#include "math-helpers.hpp"
|
#include "math-helpers.hpp"
|
||||||
@@ -29,6 +31,25 @@ static bool macroNameExists(const std::string &name)
|
|||||||
return !!GetMacroByName(name.c_str());
|
return !!GetMacroByName(name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool newMacroNameIsValid(const std::string &name)
|
||||||
|
{
|
||||||
|
if (!macroNameExists(name)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto macro = GetMacroByName(name.c_str());
|
||||||
|
if (!macro) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString fmt = obs_module_text(
|
||||||
|
macro->IsGroup() ? "AdvSceneSwitcher.macroTab.groupNameExists"
|
||||||
|
: "AdvSceneSwitcher.macroTab.macroNameExists");
|
||||||
|
|
||||||
|
DisplayMessage(fmt.arg(QString::fromStdString(name)));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool AdvSceneSwitcher::AddNewMacro(std::shared_ptr<Macro> &res,
|
bool AdvSceneSwitcher::AddNewMacro(std::shared_ptr<Macro> &res,
|
||||||
std::string &name, std::string format)
|
std::string &name, std::string format)
|
||||||
{
|
{
|
||||||
@@ -47,7 +68,7 @@ bool AdvSceneSwitcher::AddNewMacro(std::shared_ptr<Macro> &res,
|
|||||||
placeHolderText = fmt.arg(++i);
|
placeHolderText = fmt.arg(++i);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool accepted = AdvSSNameDialog::AskForName(
|
bool accepted = NameDialog::AskForName(
|
||||||
this, obs_module_text("AdvSceneSwitcher.macroTab.add"),
|
this, obs_module_text("AdvSceneSwitcher.macroTab.add"),
|
||||||
obs_module_text("AdvSceneSwitcher.macroTab.name"), name,
|
obs_module_text("AdvSceneSwitcher.macroTab.name"), name,
|
||||||
placeHolderText);
|
placeHolderText);
|
||||||
@@ -60,9 +81,7 @@ bool AdvSceneSwitcher::AddNewMacro(std::shared_ptr<Macro> &res,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (macroNameExists(name)) {
|
if (!newMacroNameIsValid(name)) {
|
||||||
DisplayMessage(
|
|
||||||
obs_module_text("AdvSceneSwitcher.macroTab.exists"));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +112,7 @@ void AdvSceneSwitcher::RemoveMacro(std::shared_ptr<Macro> ¯o)
|
|||||||
auto name = QString::fromStdString(macro->Name());
|
auto name = QString::fromStdString(macro->Name());
|
||||||
if (macro->IsGroup() && macro->GroupSize() > 0) {
|
if (macro->IsGroup() && macro->GroupSize() > 0) {
|
||||||
QString deleteWarning = obs_module_text(
|
QString deleteWarning = obs_module_text(
|
||||||
"AdvSceneSwitcher.macroTab.groupDeleteConfirm");
|
"AdvSceneSwitcher.macroTab.removeGroupPopup.text");
|
||||||
if (!DisplayMessage(deleteWarning.arg(name), true)) {
|
if (!DisplayMessage(deleteWarning.arg(name), true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -103,6 +122,41 @@ void AdvSceneSwitcher::RemoveMacro(std::shared_ptr<Macro> ¯o)
|
|||||||
emit MacroRemoved(name);
|
emit MacroRemoved(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::RemoveSelectedMacros()
|
||||||
|
{
|
||||||
|
auto macros = GetSelectedMacros();
|
||||||
|
if (macros.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int macroCount = macros.size();
|
||||||
|
if (macroCount == 1) {
|
||||||
|
QString deleteWarning = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text");
|
||||||
|
auto macro = macros.at(0);
|
||||||
|
deleteWarning = deleteWarning.arg(
|
||||||
|
QString::fromStdString(macro->Name()));
|
||||||
|
|
||||||
|
if ((!macro->IsGroup() || macro->GroupSize() == 0) &&
|
||||||
|
!DisplayMessage(deleteWarning, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveMacro(macro);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString deleteWarning = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.macroTab.removeMultipleMacrosPopup.text");
|
||||||
|
if (!DisplayMessage(deleteWarning.arg(macroCount), true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto ¯o : macros) {
|
||||||
|
RemoveMacro(macro);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::RenameMacro(std::shared_ptr<Macro> ¯o,
|
void AdvSceneSwitcher::RenameMacro(std::shared_ptr<Macro> ¯o,
|
||||||
const QString &name)
|
const QString &name)
|
||||||
{
|
{
|
||||||
@@ -116,32 +170,7 @@ void AdvSceneSwitcher::RenameMacro(std::shared_ptr<Macro> ¯o,
|
|||||||
|
|
||||||
void AdvSceneSwitcher::on_macroRemove_clicked()
|
void AdvSceneSwitcher::on_macroRemove_clicked()
|
||||||
{
|
{
|
||||||
auto macros = GetSelectedMacros();
|
RemoveSelectedMacros();
|
||||||
if (macros.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (macros.size() == 1) {
|
|
||||||
QString deleteWarning = obs_module_text(
|
|
||||||
"AdvSceneSwitcher.macroTab.deleteSingleMacroConfirmation");
|
|
||||||
if (!DisplayMessage(deleteWarning.arg(QString::fromStdString(
|
|
||||||
macros.at(0)->Name())),
|
|
||||||
true)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
RemoveMacro(macros.at(0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString deleteWarning = obs_module_text(
|
|
||||||
"AdvSceneSwitcher.macroTab.deleteMultipleMacrosConfirmation");
|
|
||||||
if (!DisplayMessage(deleteWarning.arg(macros.size()), true)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto ¯o : macros) {
|
|
||||||
RemoveMacro(macro);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_macroUp_clicked()
|
void AdvSceneSwitcher::on_macroUp_clicked()
|
||||||
@@ -162,32 +191,26 @@ void AdvSceneSwitcher::on_macroDown_clicked()
|
|||||||
ui->macros->Down(macro);
|
ui->macros->Down(macro);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool newMacroNameValid(const std::string &name)
|
void AdvSceneSwitcher::RenameSelectedMacro()
|
||||||
{
|
|
||||||
if (!macroNameExists(name)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
DisplayMessage(obs_module_text("AdvSceneSwitcher.macroTab.exists"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::RenameCurrentMacro()
|
|
||||||
{
|
{
|
||||||
auto macro = GetSelectedMacro();
|
auto macro = GetSelectedMacro();
|
||||||
if (!macro) {
|
if (!macro) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string oldName = macro->Name();
|
std::string oldName = macro->Name();
|
||||||
std::string name;
|
std::string name;
|
||||||
if (!AdvSSNameDialog::AskForName(
|
if (!NameDialog::AskForName(
|
||||||
this, obs_module_text("AdvSceneSwitcher.windowTitle"),
|
this, obs_module_text("AdvSceneSwitcher.windowTitle"),
|
||||||
obs_module_text("AdvSceneSwitcher.item.newName"), name,
|
obs_module_text("AdvSceneSwitcher.item.newName"), name,
|
||||||
QString::fromStdString(oldName))) {
|
QString::fromStdString(oldName))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (name.empty() || name == oldName || !newMacroNameValid(name)) {
|
|
||||||
|
if (name.empty() || name == oldName || !newMacroNameIsValid(name)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RenameMacro(macro, QString::fromStdString(name));
|
RenameMacro(macro, QString::fromStdString(name));
|
||||||
|
|
||||||
const QSignalBlocker b(ui->macroName);
|
const QSignalBlocker b(ui->macroName);
|
||||||
@@ -248,6 +271,7 @@ void AdvSceneSwitcher::ExportMacros()
|
|||||||
}
|
}
|
||||||
obs_data_set_array(data, "macros", macroArray);
|
obs_data_set_array(data, "macros", macroArray);
|
||||||
SaveVariables(data);
|
SaveVariables(data);
|
||||||
|
SaveActionQueues(data);
|
||||||
obs_data_set_string(data, "version", g_GIT_TAG);
|
obs_data_set_string(data, "version", g_GIT_TAG);
|
||||||
auto json = obs_data_get_json(data);
|
auto json = obs_data_get_json(data);
|
||||||
QString exportString(json);
|
QString exportString(json);
|
||||||
@@ -347,8 +371,11 @@ bool AdvSceneSwitcher::ResolveMacroImportNameConflict(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::string newName;
|
std::string newName;
|
||||||
bool accepted = AdvSSNameDialog::AskForName(
|
bool accepted = NameDialog::AskForName(
|
||||||
this, obs_module_text("AdvSceneSwitcher.macroTab.add"),
|
this,
|
||||||
|
obs_module_text(macro->IsGroup()
|
||||||
|
? "AdvSceneSwitcher.macroTab.addGroup"
|
||||||
|
: "AdvSceneSwitcher.macroTab.add"),
|
||||||
obs_module_text("AdvSceneSwitcher.macroTab.name"), newName,
|
obs_module_text("AdvSceneSwitcher.macroTab.name"), newName,
|
||||||
placeHolderText);
|
placeHolderText);
|
||||||
|
|
||||||
@@ -360,9 +387,7 @@ bool AdvSceneSwitcher::ResolveMacroImportNameConflict(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (macroNameExists(newName)) {
|
if (!newMacroNameIsValid(newName)) {
|
||||||
DisplayMessage(
|
|
||||||
obs_module_text("AdvSceneSwitcher.macroTab.exists"));
|
|
||||||
return ResolveMacroImportNameConflict(macro);
|
return ResolveMacroImportNameConflict(macro);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,26 +395,6 @@ bool AdvSceneSwitcher::ResolveMacroImportNameConflict(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool variableWithNameExists(const std::string &name)
|
|
||||||
{
|
|
||||||
return !!GetVariableByName(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void importVariables(obs_data_t *obj)
|
|
||||||
{
|
|
||||||
OBSDataArrayAutoRelease array = obs_data_get_array(obj, "variables");
|
|
||||||
size_t count = obs_data_array_count(array);
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
|
||||||
OBSDataAutoRelease data = obs_data_array_item(array, i);
|
|
||||||
auto var = Variable::Create();
|
|
||||||
var->Load(data);
|
|
||||||
if (variableWithNameExists(var->Name())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
GetVariables().emplace_back(var);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::ImportMacros()
|
void AdvSceneSwitcher::ImportMacros()
|
||||||
{
|
{
|
||||||
QString json;
|
QString json;
|
||||||
@@ -404,7 +409,8 @@ void AdvSceneSwitcher::ImportMacros()
|
|||||||
ImportMacros();
|
ImportMacros();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
importVariables(data);
|
ImportVariables(data);
|
||||||
|
ImportQueues(data);
|
||||||
|
|
||||||
auto version = obs_data_get_string(data, "version");
|
auto version = obs_data_get_string(data, "version");
|
||||||
if (strcmp(version, g_GIT_TAG) != 0) {
|
if (strcmp(version, g_GIT_TAG) != 0) {
|
||||||
@@ -425,6 +431,7 @@ void AdvSceneSwitcher::ImportMacros()
|
|||||||
OBSDataAutoRelease array_obj = obs_data_array_item(array, i);
|
OBSDataAutoRelease array_obj = obs_data_array_item(array, i);
|
||||||
auto macro = std::make_shared<Macro>();
|
auto macro = std::make_shared<Macro>();
|
||||||
macro->Load(array_obj);
|
macro->Load(array_obj);
|
||||||
|
RunPostLoadSteps();
|
||||||
|
|
||||||
if (macroNameExists(macro->Name()) &&
|
if (macroNameExists(macro->Name()) &&
|
||||||
!ResolveMacroImportNameConflict(macro)) {
|
!ResolveMacroImportNameConflict(macro)) {
|
||||||
@@ -469,7 +476,7 @@ void AdvSceneSwitcher::on_macroName_editingFinished()
|
|||||||
QString oldName = QString::fromStdString(macro->Name());
|
QString oldName = QString::fromStdString(macro->Name());
|
||||||
|
|
||||||
if (newName.isEmpty() || newName == oldName ||
|
if (newName.isEmpty() || newName == oldName ||
|
||||||
!newMacroNameValid(newName.toStdString())) {
|
!newMacroNameIsValid(newName.toStdString())) {
|
||||||
ui->macroName->setText(oldName);
|
ui->macroName->setText(oldName);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -761,8 +768,6 @@ void AdvSceneSwitcher::on_macroProperties_clicked()
|
|||||||
}
|
}
|
||||||
GetGlobalMacroProperties() = prop;
|
GetGlobalMacroProperties() = prop;
|
||||||
emit HighlightMacrosChanged(prop._highlightExecuted);
|
emit HighlightMacrosChanged(prop._highlightExecuted);
|
||||||
emit HighlightActionsChanged(prop._highlightActions);
|
|
||||||
emit HighlightConditionsChanged(prop._highlightConditions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void moveControlsToSplitter(QSplitter *splitter, int idx,
|
static void moveControlsToSplitter(QSplitter *splitter, int idx,
|
||||||
@@ -777,7 +782,7 @@ static void moveControlsToSplitter(QSplitter *splitter, int idx,
|
|||||||
splitter->setStyleSheet("QSplitter::handle {background: transparent;}");
|
splitter->setStyleSheet("QSplitter::handle {background: transparent;}");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldRestoreSplitter(const QList<int> &pos)
|
static bool shouldRestoreSplitter(const QList<int> &pos)
|
||||||
{
|
{
|
||||||
if (pos.size() == 0) {
|
if (pos.size() == 0) {
|
||||||
return false;
|
return false;
|
||||||
@@ -791,9 +796,40 @@ bool shouldRestoreSplitter(const QList<int> &pos)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void runSegmentHighligtChecksHelper(MacroSegmentList *list)
|
||||||
|
{
|
||||||
|
MacroSegmentEdit *widget = nullptr;
|
||||||
|
for (int i = 0; (widget = list->WidgetAt(i)); i++) {
|
||||||
|
if (widget->Data() && widget->Data()->GetHighlightAndReset()) {
|
||||||
|
list->Highlight(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void runSegmentHighligtChecks(AdvSceneSwitcher *ss)
|
||||||
|
{
|
||||||
|
if (!ss || !HighlightUIElementsEnabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto macro = ss->GetSelectedMacro();
|
||||||
|
if (!macro) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &properties = GetGlobalMacroProperties();
|
||||||
|
if (properties._highlightConditions) {
|
||||||
|
runSegmentHighligtChecksHelper(ss->ui->conditionsList);
|
||||||
|
}
|
||||||
|
if (properties._highlightActions) {
|
||||||
|
runSegmentHighligtChecksHelper(ss->ui->actionsList);
|
||||||
|
runSegmentHighligtChecksHelper(ss->ui->elseActionsList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::SetupMacroTab()
|
void AdvSceneSwitcher::SetupMacroTab()
|
||||||
{
|
{
|
||||||
ui->macroElseActions->installEventFilter(this);
|
ui->macroElseActions->installEventFilter(this);
|
||||||
|
ui->macros->installEventFilter(this);
|
||||||
|
|
||||||
if (GetMacros().size() == 0 && !switcher->disableHints) {
|
if (GetMacros().size() == 0 && !switcher->disableHints) {
|
||||||
addPulse = PulseWidget(ui->macroAdd, QColor(Qt::green));
|
addPulse = PulseWidget(ui->macroAdd, QColor(Qt::green));
|
||||||
@@ -884,6 +920,14 @@ void AdvSceneSwitcher::SetupMacroTab()
|
|||||||
switcher->macroListMacroEditSplitterPosition);
|
switcher->macroListMacroEditSplitterPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetupSegmentCopyPasteShortcutHandlers(this);
|
||||||
|
|
||||||
|
// Macro segment highlight
|
||||||
|
auto timer = new QTimer(this);
|
||||||
|
connect(timer, &QTimer::timeout,
|
||||||
|
[this]() { runSegmentHighligtChecks(this); });
|
||||||
|
timer->start(1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::ShowMacroContextMenu(const QPoint &pos)
|
void AdvSceneSwitcher::ShowMacroContextMenu(const QPoint &pos)
|
||||||
@@ -917,7 +961,7 @@ void AdvSceneSwitcher::ShowMacroContextMenu(const QPoint &pos)
|
|||||||
|
|
||||||
auto rename = menu.addAction(
|
auto rename = menu.addAction(
|
||||||
obs_module_text("AdvSceneSwitcher.macroTab.rename"), this,
|
obs_module_text("AdvSceneSwitcher.macroTab.rename"), this,
|
||||||
&AdvSceneSwitcher::RenameCurrentMacro);
|
&AdvSceneSwitcher::RenameSelectedMacro);
|
||||||
rename->setEnabled(ui->macros->SingleItemSelected());
|
rename->setEnabled(ui->macros->SingleItemSelected());
|
||||||
|
|
||||||
auto remove = menu.addAction(
|
auto remove = menu.addAction(
|
||||||
@@ -936,49 +980,107 @@ void AdvSceneSwitcher::ShowMacroContextMenu(const QPoint &pos)
|
|||||||
menu.exec(globalPos);
|
menu.exec(globalPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handleCustomLabelChange(MacroSegmentEdit *segmentEdit,
|
||||||
|
QAction *contextMenuOption)
|
||||||
|
{
|
||||||
|
bool enable = contextMenuOption->isChecked();
|
||||||
|
auto segment = segmentEdit->Data();
|
||||||
|
segment->SetUseCustomLabel(enable);
|
||||||
|
if (!enable) {
|
||||||
|
segmentEdit->HeaderInfoChanged(
|
||||||
|
QString::fromStdString(segment->GetShortDesc()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string label;
|
||||||
|
bool accepted = NameDialog::AskForName(
|
||||||
|
GetSettingsWindow(),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.macroTab.segment.setCustomLabel"),
|
||||||
|
"", label, QString::fromStdString(segment->GetCustomLabel()));
|
||||||
|
if (!accepted) {
|
||||||
|
segment->SetUseCustomLabel(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
segment->SetCustomLabel(label);
|
||||||
|
segmentEdit->HeaderInfoChanged("");
|
||||||
|
}
|
||||||
|
|
||||||
static void setupConextMenu(AdvSceneSwitcher *ss, const QPoint &pos,
|
static void setupConextMenu(AdvSceneSwitcher *ss, const QPoint &pos,
|
||||||
std::function<void(AdvSceneSwitcher *)> expand,
|
std::function<void(AdvSceneSwitcher *)> expand,
|
||||||
std::function<void(AdvSceneSwitcher *)> collapse,
|
std::function<void(AdvSceneSwitcher *)> collapse,
|
||||||
std::function<void(AdvSceneSwitcher *)> maximize,
|
std::function<void(AdvSceneSwitcher *)> maximize,
|
||||||
std::function<void(AdvSceneSwitcher *)> minimize)
|
std::function<void(AdvSceneSwitcher *)> minimize,
|
||||||
|
MacroSegmentList *list)
|
||||||
{
|
{
|
||||||
QMenu menu;
|
QMenu menu;
|
||||||
|
auto segmentEdit = list->WidgetAt(pos);
|
||||||
|
|
||||||
|
auto copy = menu.addAction(
|
||||||
|
obs_module_text("AdvSceneSwitcher.macroTab.segment.copy"), ss,
|
||||||
|
[ss]() { ss->CopyMacroSegment(); });
|
||||||
|
copy->setEnabled(!!segmentEdit);
|
||||||
|
auto paste = menu.addAction(
|
||||||
|
obs_module_text("AdvSceneSwitcher.macroTab.segment.paste"), ss,
|
||||||
|
[ss]() { ss->PasteMacroSegment(); });
|
||||||
|
paste->setEnabled(MacroSegmentIsInClipboard());
|
||||||
|
|
||||||
|
menu.addSeparator();
|
||||||
|
|
||||||
|
if (segmentEdit) {
|
||||||
|
auto customLabel = menu.addAction(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.macroTab.segment.useCustomLabel"));
|
||||||
|
customLabel->setCheckable(true);
|
||||||
|
auto segment = segmentEdit ? segmentEdit->Data() : nullptr;
|
||||||
|
customLabel->setChecked(segment &&
|
||||||
|
segment->GetUseCustomLabel());
|
||||||
|
QWidget::connect(customLabel, &QAction::triggered,
|
||||||
|
std::bind(handleCustomLabelChange, segmentEdit,
|
||||||
|
customLabel));
|
||||||
|
}
|
||||||
|
|
||||||
|
menu.addSeparator();
|
||||||
|
|
||||||
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.expandAll"),
|
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.expandAll"),
|
||||||
ss, [ss, expand]() { expand(ss); });
|
ss, [ss, expand]() { expand(ss); });
|
||||||
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.collapseAll"),
|
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.collapseAll"),
|
||||||
ss, [ss, collapse]() { collapse(ss); });
|
ss, [ss, collapse]() { collapse(ss); });
|
||||||
|
|
||||||
|
menu.addSeparator();
|
||||||
|
|
||||||
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.maximize"),
|
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.maximize"),
|
||||||
ss, [ss, maximize]() { maximize(ss); });
|
ss, [ss, maximize]() { maximize(ss); });
|
||||||
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.minimize"),
|
menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.minimize"),
|
||||||
ss, [ss, minimize]() { minimize(ss); });
|
ss, [ss, minimize]() { minimize(ss); });
|
||||||
menu.exec(pos);
|
|
||||||
|
menu.exec(list->mapToGlobal(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::ShowMacroActionsContextMenu(const QPoint &pos)
|
void AdvSceneSwitcher::ShowMacroActionsContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
setupConextMenu(this, ui->actionsList->mapToGlobal(pos),
|
setupConextMenu(this, pos, &AdvSceneSwitcher::ExpandAllActions,
|
||||||
&AdvSceneSwitcher::ExpandAllActions,
|
|
||||||
&AdvSceneSwitcher::CollapseAllActions,
|
&AdvSceneSwitcher::CollapseAllActions,
|
||||||
&AdvSceneSwitcher::MaximizeActions,
|
&AdvSceneSwitcher::MaximizeActions,
|
||||||
&AdvSceneSwitcher::MinimizeActions);
|
&AdvSceneSwitcher::MinimizeActions, ui->actionsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::ShowMacroElseActionsContextMenu(const QPoint &pos)
|
void AdvSceneSwitcher::ShowMacroElseActionsContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
setupConextMenu(this, ui->elseActionsList->mapToGlobal(pos),
|
setupConextMenu(this, pos, &AdvSceneSwitcher::ExpandAllElseActions,
|
||||||
&AdvSceneSwitcher::ExpandAllElseActions,
|
|
||||||
&AdvSceneSwitcher::CollapseAllElseActions,
|
&AdvSceneSwitcher::CollapseAllElseActions,
|
||||||
&AdvSceneSwitcher::MaximizeElseActions,
|
&AdvSceneSwitcher::MaximizeElseActions,
|
||||||
&AdvSceneSwitcher::MinimizeElseActions);
|
&AdvSceneSwitcher::MinimizeElseActions,
|
||||||
|
ui->elseActionsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::ShowMacroConditionsContextMenu(const QPoint &pos)
|
void AdvSceneSwitcher::ShowMacroConditionsContextMenu(const QPoint &pos)
|
||||||
{
|
{
|
||||||
setupConextMenu(this, ui->conditionsList->mapToGlobal(pos),
|
setupConextMenu(this, pos, &AdvSceneSwitcher::ExpandAllConditions,
|
||||||
&AdvSceneSwitcher::ExpandAllConditions,
|
|
||||||
&AdvSceneSwitcher::CollapseAllConditions,
|
&AdvSceneSwitcher::CollapseAllConditions,
|
||||||
&AdvSceneSwitcher::MaximizeConditions,
|
&AdvSceneSwitcher::MaximizeConditions,
|
||||||
&AdvSceneSwitcher::MinimizeConditions);
|
&AdvSceneSwitcher::MinimizeConditions,
|
||||||
|
ui->conditionsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::CopyMacro()
|
void AdvSceneSwitcher::CopyMacro()
|
||||||
@@ -1296,58 +1398,47 @@ static void fade(QWidget *widget, bool fadeOut)
|
|||||||
animation->start(QPropertyAnimation::DeleteWhenStopped);
|
animation->start(QPropertyAnimation::DeleteWhenStopped);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::FadeOutActionControls()
|
void fadeWidgets(const std::vector<QWidget *> &widgets, bool fadeOut)
|
||||||
{
|
{
|
||||||
fade(ui->actionAdd, true);
|
for (const auto &widget : widgets) {
|
||||||
fade(ui->actionRemove, true);
|
fade(widget, fadeOut);
|
||||||
fade(ui->actionTop, true);
|
}
|
||||||
fade(ui->actionUp, true);
|
|
||||||
fade(ui->actionDown, true);
|
|
||||||
fade(ui->actionBottom, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::FadeOutConditionControls()
|
|
||||||
{
|
|
||||||
fade(ui->conditionAdd, true);
|
|
||||||
fade(ui->conditionRemove, true);
|
|
||||||
fade(ui->conditionTop, true);
|
|
||||||
fade(ui->conditionUp, true);
|
|
||||||
fade(ui->conditionDown, true);
|
|
||||||
fade(ui->conditionBottom, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::ResetOpacityActionControls()
|
|
||||||
{
|
|
||||||
fade(ui->actionAdd, false);
|
|
||||||
fade(ui->actionRemove, false);
|
|
||||||
fade(ui->actionTop, false);
|
|
||||||
fade(ui->actionUp, false);
|
|
||||||
fade(ui->actionDown, false);
|
|
||||||
fade(ui->actionBottom, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::ResetOpacityConditionControls()
|
|
||||||
{
|
|
||||||
fade(ui->conditionAdd, false);
|
|
||||||
fade(ui->conditionRemove, false);
|
|
||||||
fade(ui->conditionTop, false);
|
|
||||||
fade(ui->conditionUp, false);
|
|
||||||
fade(ui->conditionDown, false);
|
|
||||||
fade(ui->conditionBottom, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::HighlightControls()
|
void AdvSceneSwitcher::HighlightControls()
|
||||||
{
|
{
|
||||||
if ((currentActionIdx == -1 && currentConditionIdx == -1) ||
|
const std::vector<QWidget *> conditionControls{
|
||||||
(currentActionIdx != -1 && currentConditionIdx != -1)) {
|
ui->conditionAdd, ui->conditionRemove, ui->conditionTop,
|
||||||
ResetOpacityActionControls();
|
ui->conditionUp, ui->conditionDown, ui->conditionBottom,
|
||||||
ResetOpacityConditionControls();
|
};
|
||||||
|
const std::vector<QWidget *> actionControls{
|
||||||
|
ui->actionAdd, ui->actionRemove, ui->actionTop,
|
||||||
|
ui->actionUp, ui->actionDown, ui->actionBottom,
|
||||||
|
};
|
||||||
|
const std::vector<QWidget *> elseActionControls{
|
||||||
|
ui->elseActionAdd, ui->elseActionRemove, ui->elseActionTop,
|
||||||
|
ui->elseActionUp, ui->elseActionDown, ui->elseActionBottom,
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((currentActionIdx == -1 && currentConditionIdx == -1 &&
|
||||||
|
currentElseActionIdx == -1)) {
|
||||||
|
fadeWidgets(conditionControls, false);
|
||||||
|
fadeWidgets(actionControls, false);
|
||||||
|
fadeWidgets(elseActionControls, false);
|
||||||
|
} else if (currentConditionIdx != -1) {
|
||||||
|
fadeWidgets(conditionControls, false);
|
||||||
|
fadeWidgets(actionControls, true);
|
||||||
|
fadeWidgets(elseActionControls, true);
|
||||||
} else if (currentActionIdx != -1) {
|
} else if (currentActionIdx != -1) {
|
||||||
FadeOutConditionControls();
|
fadeWidgets(conditionControls, true);
|
||||||
ResetOpacityActionControls();
|
fadeWidgets(actionControls, false);
|
||||||
|
fadeWidgets(elseActionControls, true);
|
||||||
|
} else if (currentElseActionIdx != -1) {
|
||||||
|
fadeWidgets(conditionControls, true);
|
||||||
|
fadeWidgets(actionControls, true);
|
||||||
|
fadeWidgets(elseActionControls, false);
|
||||||
} else {
|
} else {
|
||||||
FadeOutActionControls();
|
assert(false);
|
||||||
ResetOpacityConditionControls();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ void MacroTreeItem::Update(bool force)
|
|||||||
|
|
||||||
} else if (_type == Type::Group) {
|
} else if (_type == Type::Group) {
|
||||||
_expand = new SourceTreeSubItemCheckBox();
|
_expand = new SourceTreeSubItemCheckBox();
|
||||||
|
_expand->setProperty("sourceTreeSubItem", true);
|
||||||
_expand->setSizePolicy(QSizePolicy::Maximum,
|
_expand->setSizePolicy(QSizePolicy::Maximum,
|
||||||
QSizePolicy::Maximum);
|
QSizePolicy::Maximum);
|
||||||
_expand->setMaximumSize(10, 16);
|
_expand->setMaximumSize(10, 16);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class QSpacerItem;
|
|||||||
class QHBoxLayout;
|
class QHBoxLayout;
|
||||||
|
|
||||||
// Only used to enable applying "SourceTreeSubItemCheckBox" stylesheet
|
// Only used to enable applying "SourceTreeSubItemCheckBox" stylesheet
|
||||||
|
// Can be removed once the minimum supported OBS version is greater than 30.1
|
||||||
class SourceTreeSubItemCheckBox : public QCheckBox {
|
class SourceTreeSubItemCheckBox : public QCheckBox {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -137,37 +137,37 @@ bool Macro::CeckMatch()
|
|||||||
case LogicType::AND:
|
case LogicType::AND:
|
||||||
_matched = _matched && cond;
|
_matched = _matched && cond;
|
||||||
if (cond) {
|
if (cond) {
|
||||||
c->SetHighlight();
|
c->EnableHighlight();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LogicType::OR:
|
case LogicType::OR:
|
||||||
_matched = _matched || cond;
|
_matched = _matched || cond;
|
||||||
if (cond) {
|
if (cond) {
|
||||||
c->SetHighlight();
|
c->EnableHighlight();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LogicType::AND_NOT:
|
case LogicType::AND_NOT:
|
||||||
_matched = _matched && !cond;
|
_matched = _matched && !cond;
|
||||||
if (!cond) {
|
if (!cond) {
|
||||||
c->SetHighlight();
|
c->EnableHighlight();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LogicType::OR_NOT:
|
case LogicType::OR_NOT:
|
||||||
_matched = _matched || !cond;
|
_matched = _matched || !cond;
|
||||||
if (!cond) {
|
if (!cond) {
|
||||||
c->SetHighlight();
|
c->EnableHighlight();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LogicType::ROOT_NONE:
|
case LogicType::ROOT_NONE:
|
||||||
_matched = cond;
|
_matched = cond;
|
||||||
if (cond) {
|
if (cond) {
|
||||||
c->SetHighlight();
|
c->EnableHighlight();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LogicType::ROOT_NOT:
|
case LogicType::ROOT_NOT:
|
||||||
_matched = !cond;
|
_matched = !cond;
|
||||||
if (!cond) {
|
if (!cond) {
|
||||||
c->SetHighlight();
|
c->EnableHighlight();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -193,9 +193,17 @@ bool Macro::CeckMatch()
|
|||||||
bool Macro::PerformActions(bool match, bool forceParallel, bool ignorePause)
|
bool Macro::PerformActions(bool match, bool forceParallel, bool ignorePause)
|
||||||
{
|
{
|
||||||
if (!_done) {
|
if (!_done) {
|
||||||
vblog(LOG_INFO, "macro %s already running", _name.c_str());
|
vblog(LOG_INFO, "Macro %s already running", _name.c_str());
|
||||||
return !forceParallel;
|
|
||||||
|
if (!_stopActionsIfNotDone) {
|
||||||
|
return !forceParallel;
|
||||||
|
}
|
||||||
|
|
||||||
|
Stop();
|
||||||
|
vblog(LOG_INFO, "Stopped macro %s actions to rerun them",
|
||||||
|
_name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<bool(bool)> runFunc =
|
std::function<bool(bool)> runFunc =
|
||||||
match ? std::bind(&Macro::RunActions, this,
|
match ? std::bind(&Macro::RunActions, this,
|
||||||
std::placeholders::_1)
|
std::placeholders::_1)
|
||||||
@@ -213,6 +221,7 @@ bool Macro::PerformActions(bool match, bool forceParallel, bool ignorePause)
|
|||||||
} else {
|
} else {
|
||||||
ret = runFunc(ignorePause);
|
ret = runFunc(ignorePause);
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastExecutionTime = std::chrono::high_resolution_clock::now();
|
_lastExecutionTime = std::chrono::high_resolution_clock::now();
|
||||||
auto group = _parent.lock();
|
auto group = _parent.lock();
|
||||||
if (group) {
|
if (group) {
|
||||||
@@ -304,7 +313,7 @@ bool Macro::RunActionsHelper(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (action->Enabled()) {
|
if (action->Enabled()) {
|
||||||
action->SetHighlight();
|
action->EnableHighlight();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_done = true;
|
_done = true;
|
||||||
@@ -550,6 +559,7 @@ bool Macro::Save(obs_data_t *obj) const
|
|||||||
obs_data_set_bool(obj, "parallel", _runInParallel);
|
obs_data_set_bool(obj, "parallel", _runInParallel);
|
||||||
obs_data_set_bool(obj, "onChange", _performActionsOnChange);
|
obs_data_set_bool(obj, "onChange", _performActionsOnChange);
|
||||||
obs_data_set_bool(obj, "skipExecOnStart", _skipExecOnStart);
|
obs_data_set_bool(obj, "skipExecOnStart", _skipExecOnStart);
|
||||||
|
obs_data_set_bool(obj, "stopActionsIfNotDone", _stopActionsIfNotDone);
|
||||||
|
|
||||||
obs_data_set_bool(obj, "group", _isGroup);
|
obs_data_set_bool(obj, "group", _isGroup);
|
||||||
if (_isGroup) {
|
if (_isGroup) {
|
||||||
@@ -644,6 +654,7 @@ bool Macro::Load(obs_data_t *obj)
|
|||||||
_runInParallel = obs_data_get_bool(obj, "parallel");
|
_runInParallel = obs_data_get_bool(obj, "parallel");
|
||||||
_performActionsOnChange = obs_data_get_bool(obj, "onChange");
|
_performActionsOnChange = obs_data_get_bool(obj, "onChange");
|
||||||
_skipExecOnStart = obs_data_get_bool(obj, "skipExecOnStart");
|
_skipExecOnStart = obs_data_get_bool(obj, "skipExecOnStart");
|
||||||
|
_stopActionsIfNotDone = obs_data_get_bool(obj, "stopActionsIfNotDone");
|
||||||
|
|
||||||
_isGroup = obs_data_get_bool(obj, "group");
|
_isGroup = obs_data_get_bool(obj, "group");
|
||||||
if (_isGroup) {
|
if (_isGroup) {
|
||||||
@@ -651,6 +662,7 @@ bool Macro::Load(obs_data_t *obj)
|
|||||||
obs_data_get_obj(obj, "groupData");
|
obs_data_get_obj(obj, "groupData");
|
||||||
_isCollapsed = obs_data_get_bool(groupData, "collapsed");
|
_isCollapsed = obs_data_get_bool(groupData, "collapsed");
|
||||||
_groupSize = obs_data_get_int(groupData, "size");
|
_groupSize = obs_data_get_int(groupData, "size");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -735,6 +747,7 @@ bool Macro::Load(obs_data_t *obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
UpdateElseActionIndices();
|
UpdateElseActionIndices();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -806,10 +819,10 @@ void Macro::ResetUIHelpers()
|
|||||||
{
|
{
|
||||||
_onPreventedActionExecution = false;
|
_onPreventedActionExecution = false;
|
||||||
for (auto c : _conditions) {
|
for (auto c : _conditions) {
|
||||||
c->Highlight();
|
c->GetHighlightAndReset();
|
||||||
}
|
}
|
||||||
for (auto a : _actions) {
|
for (auto a : _actions) {
|
||||||
a->Highlight();
|
a->GetHighlightAndReset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class Macro {
|
|||||||
public:
|
public:
|
||||||
Macro(const std::string &name = "", const bool addHotkey = false);
|
Macro(const std::string &name = "", const bool addHotkey = false);
|
||||||
virtual ~Macro();
|
virtual ~Macro();
|
||||||
|
|
||||||
bool CeckMatch();
|
bool CeckMatch();
|
||||||
bool PerformActions(bool match, bool forceParallel = false,
|
bool PerformActions(bool match, bool forceParallel = false,
|
||||||
bool ignorePause = false);
|
bool ignorePause = false);
|
||||||
@@ -42,6 +43,11 @@ public:
|
|||||||
bool MatchOnChange() const { return _performActionsOnChange; }
|
bool MatchOnChange() const { return _performActionsOnChange; }
|
||||||
void SetSkipExecOnStart(bool skip) { _skipExecOnStart = skip; }
|
void SetSkipExecOnStart(bool skip) { _skipExecOnStart = skip; }
|
||||||
bool SkipExecOnStart() const { return _skipExecOnStart; }
|
bool SkipExecOnStart() const { return _skipExecOnStart; }
|
||||||
|
void SetStopActionsIfNotDone(bool stopActionsIfNotDone)
|
||||||
|
{
|
||||||
|
_stopActionsIfNotDone = stopActionsIfNotDone;
|
||||||
|
}
|
||||||
|
bool StopActionsIfNotDone() const { return _stopActionsIfNotDone; }
|
||||||
int RunCount() const { return _runCount; };
|
int RunCount() const { return _runCount; };
|
||||||
void ResetRunCount() { _runCount = 0; };
|
void ResetRunCount() { _runCount = 0; };
|
||||||
void ResetTimers();
|
void ResetTimers();
|
||||||
@@ -168,6 +174,7 @@ private:
|
|||||||
bool _conditionSateChanged = false;
|
bool _conditionSateChanged = false;
|
||||||
bool _performActionsOnChange = true;
|
bool _performActionsOnChange = true;
|
||||||
bool _skipExecOnStart = false;
|
bool _skipExecOnStart = false;
|
||||||
|
bool _stopActionsIfNotDone = false;
|
||||||
bool _paused = false;
|
bool _paused = false;
|
||||||
int _runCount = 0;
|
int _runCount = 0;
|
||||||
bool _registerHotkeys = true;
|
bool _registerHotkeys = true;
|
||||||
|
|||||||
260
lib/queue/action-queue-tab.cpp
Normal file
260
lib/queue/action-queue-tab.cpp
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
#include "action-queue-tab.hpp"
|
||||||
|
#include "action-queue.hpp"
|
||||||
|
#include "log-helper.hpp"
|
||||||
|
#include "obs-module-helper.hpp"
|
||||||
|
#include "plugin-state-helpers.hpp"
|
||||||
|
#include "sync-helpers.hpp"
|
||||||
|
#include "tab-helpers.hpp"
|
||||||
|
#include "ui-helpers.hpp"
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
static bool registerTab();
|
||||||
|
static void setupTab(QTabWidget *);
|
||||||
|
static bool registerTabDone = registerTab();
|
||||||
|
|
||||||
|
static ActionQueueTable *tabWidget = nullptr;
|
||||||
|
|
||||||
|
static bool registerTab()
|
||||||
|
{
|
||||||
|
AddPluginInitStep([]() {
|
||||||
|
AddSetupTabCallback("actionQueueTab", ActionQueueTable::Create,
|
||||||
|
setupTab);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setTabVisible(QTabWidget *tabWidget, bool visible)
|
||||||
|
{
|
||||||
|
SetTabVisibleByName(
|
||||||
|
tabWidget, visible,
|
||||||
|
obs_module_text("AdvSceneSwitcher.actionQueueTab.title"));
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionQueueTable *ActionQueueTable::Create()
|
||||||
|
{
|
||||||
|
tabWidget = new ActionQueueTable();
|
||||||
|
return tabWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionQueueTable::Add()
|
||||||
|
{
|
||||||
|
auto newQueue = std::make_shared<ActionQueue>();
|
||||||
|
auto accepted =
|
||||||
|
ActionQueueSettingsDialog::AskForSettings(this, *newQueue);
|
||||||
|
if (!accepted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto lock = LockContext();
|
||||||
|
auto &queues = GetActionQueues();
|
||||||
|
queues.emplace_back(newQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionQueueSignalManager::Instance()->Add(
|
||||||
|
QString::fromStdString(newQueue->Name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static QStringList getCellLabels(ActionQueue *queue, bool addName = true)
|
||||||
|
{
|
||||||
|
assert(queue);
|
||||||
|
|
||||||
|
auto result = QStringList();
|
||||||
|
if (addName) {
|
||||||
|
result << QString::fromStdString(queue->Name());
|
||||||
|
}
|
||||||
|
result << QString::number(queue->Size())
|
||||||
|
<< QString::fromStdString(obs_module_text(
|
||||||
|
queue->IsRunning()
|
||||||
|
? "AdvSceneSwitcher.actionQueueTab.yes"
|
||||||
|
: "AdvSceneSwitcher.actionQueueTab.yes"))
|
||||||
|
<< QString::fromStdString(obs_module_text(
|
||||||
|
queue->RunsOnStartup()
|
||||||
|
? "AdvSceneSwitcher.actionQueueTab.yes"
|
||||||
|
: "AdvSceneSwitcher.actionQueueTab.yes"));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateQueueStatus(QTableWidget *table)
|
||||||
|
{
|
||||||
|
for (int row = 0; row < table->rowCount(); row++) {
|
||||||
|
auto item = table->item(row, 0);
|
||||||
|
if (!item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto weakQueue = GetWeakActionQueueByQString(item->text());
|
||||||
|
auto queue = weakQueue.lock();
|
||||||
|
if (!queue) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateItemTableRow(table, row,
|
||||||
|
getCellLabels(queue.get(), false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void openSettingsDialog()
|
||||||
|
{
|
||||||
|
auto selectedRows =
|
||||||
|
tabWidget->Table()->selectionModel()->selectedRows();
|
||||||
|
if (selectedRows.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cell = tabWidget->Table()->item(selectedRows.last().row(), 0);
|
||||||
|
if (!cell) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto weakQueue = GetWeakActionQueueByQString(cell->text());
|
||||||
|
auto queue = weakQueue.lock();
|
||||||
|
if (!queue) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto oldName = queue->Name();
|
||||||
|
bool accepted = ActionQueueSettingsDialog::AskForSettings(
|
||||||
|
tabWidget->Table(), *queue.get());
|
||||||
|
if (accepted && oldName != queue->Name()) {
|
||||||
|
ActionQueueSignalManager::Instance()->Rename(
|
||||||
|
QString::fromStdString(oldName),
|
||||||
|
QString::fromStdString(queue->Name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void removeQueuesWithNames(const QStringList &queueNames)
|
||||||
|
{
|
||||||
|
for (const auto &name : queueNames) {
|
||||||
|
auto queue = GetWeakActionQueueByQString(name).lock();
|
||||||
|
if (!queue) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &queues = GetActionQueues();
|
||||||
|
queues.erase(
|
||||||
|
std::remove_if(
|
||||||
|
queues.begin(), queues.end(),
|
||||||
|
[queue](const std::shared_ptr<Item> &item) {
|
||||||
|
return item == queue;
|
||||||
|
}),
|
||||||
|
queues.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionQueueTable::Remove()
|
||||||
|
{
|
||||||
|
auto selectedRows =
|
||||||
|
tabWidget->Table()->selectionModel()->selectedRows();
|
||||||
|
if (selectedRows.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList queueNames;
|
||||||
|
for (const auto &row : selectedRows) {
|
||||||
|
auto cell = tabWidget->Table()->item(row.row(), 0);
|
||||||
|
if (!cell) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
queueNames << cell->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
int queueNameCount = queueNames.size();
|
||||||
|
if (queueNameCount == 1) {
|
||||||
|
QString deleteWarning = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.actionQueueTab.removeSingleQueuePopup.text");
|
||||||
|
if (!DisplayMessage(deleteWarning.arg(queueNames.at(0)),
|
||||||
|
true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QString deleteWarning = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.actionQueueTab.removeMultipleQueuesPopup.text");
|
||||||
|
if (!DisplayMessage(deleteWarning.arg(queueNameCount), true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto lock = LockContext();
|
||||||
|
RemoveItemsByName(GetActionQueues(), queueNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &name : queueNames) {
|
||||||
|
ActionQueueSignalManager::Instance()->Remove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActionQueueTable::ActionQueueTable(QTabWidget *parent)
|
||||||
|
: ResourceTable(
|
||||||
|
parent,
|
||||||
|
obs_module_text("AdvSceneSwitcher.actionQueueTab.help"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.actionQueueTab.queueAddButton.tooltip"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.actionQueueTab.queueRemoveButton.tooltip"),
|
||||||
|
QStringList()
|
||||||
|
<< obs_module_text(
|
||||||
|
"AdvSceneSwitcher.actionQueueTab.name.header")
|
||||||
|
<< obs_module_text(
|
||||||
|
"AdvSceneSwitcher.actionQueueTab.size.header")
|
||||||
|
<< obs_module_text(
|
||||||
|
"AdvSceneSwitcher.actionQueueTab.isRunning.header")
|
||||||
|
<< obs_module_text(
|
||||||
|
"AdvSceneSwitcher.actionQueueTab.runOnStartup.header"),
|
||||||
|
openSettingsDialog)
|
||||||
|
{
|
||||||
|
for (const auto &queue : GetActionQueues()) {
|
||||||
|
auto q = std::static_pointer_cast<ActionQueue>(queue);
|
||||||
|
AddItemTableRow(Table(), getCellLabels(q.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
SetHelpVisible(GetActionQueues().empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setupTab(QTabWidget *tab)
|
||||||
|
{
|
||||||
|
if (GetActionQueues().empty()) {
|
||||||
|
setTabVisible(tab, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::connect(ActionQueueSignalManager::Instance(),
|
||||||
|
&ActionQueueSignalManager::Rename,
|
||||||
|
[](const QString &oldName, const QString &newName) {
|
||||||
|
RenameItemTableRow(tabWidget->Table(), oldName,
|
||||||
|
newName);
|
||||||
|
});
|
||||||
|
QWidget::connect(
|
||||||
|
ActionQueueSignalManager::Instance(),
|
||||||
|
&ActionQueueSignalManager::Add, [tab](const QString &name) {
|
||||||
|
AddItemTableRow(
|
||||||
|
tabWidget->Table(),
|
||||||
|
getCellLabels(GetWeakActionQueueByQString(name)
|
||||||
|
.lock()
|
||||||
|
.get()));
|
||||||
|
tabWidget->SetHelpVisible(false);
|
||||||
|
tabWidget->HighlightAddButton(false);
|
||||||
|
setTabVisible(tab, true);
|
||||||
|
});
|
||||||
|
QWidget::connect(ActionQueueSignalManager::Instance(),
|
||||||
|
&ActionQueueSignalManager::Remove,
|
||||||
|
[](const QString &name) {
|
||||||
|
RemoveItemTableRow(tabWidget->Table(), name);
|
||||||
|
if (tabWidget->Table()->rowCount() == 0) {
|
||||||
|
tabWidget->SetHelpVisible(true);
|
||||||
|
tabWidget->HighlightAddButton(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
auto timer = new QTimer(tabWidget);
|
||||||
|
timer->setInterval(1000);
|
||||||
|
QWidget::connect(timer, &QTimer::timeout,
|
||||||
|
[]() { updateQueueStatus(tabWidget->Table()); });
|
||||||
|
timer->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
20
lib/queue/action-queue-tab.hpp
Normal file
20
lib/queue/action-queue-tab.hpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "resource-table.hpp"
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
class ActionQueueTable final : public ResourceTable {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static ActionQueueTable *Create();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void Add();
|
||||||
|
void Remove();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ActionQueueTable(QTabWidget *parent = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -6,6 +6,11 @@ namespace advss {
|
|||||||
|
|
||||||
static std::deque<std::shared_ptr<Item>> queues;
|
static std::deque<std::shared_ptr<Item>> queues;
|
||||||
|
|
||||||
|
std::deque<std::shared_ptr<Item>> &GetActionQueues()
|
||||||
|
{
|
||||||
|
return queues;
|
||||||
|
}
|
||||||
|
|
||||||
void SetupActionQueues()
|
void SetupActionQueues()
|
||||||
{
|
{
|
||||||
static bool done = false;
|
static bool done = false;
|
||||||
@@ -51,9 +56,13 @@ void ActionQueue::Load(obs_data_t *obj)
|
|||||||
|
|
||||||
void ActionQueue::Start()
|
void ActionQueue::Start()
|
||||||
{
|
{
|
||||||
if (_thread.joinable()) {
|
if (!_stop) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_thread.joinable()) {
|
||||||
|
_thread.join();
|
||||||
|
}
|
||||||
_stop = false;
|
_stop = false;
|
||||||
_thread = std::thread(&ActionQueue::RunActions, this);
|
_thread = std::thread(&ActionQueue::RunActions, this);
|
||||||
}
|
}
|
||||||
@@ -62,6 +71,10 @@ void ActionQueue::Stop()
|
|||||||
{
|
{
|
||||||
_stop = true;
|
_stop = true;
|
||||||
_cv.notify_all();
|
_cv.notify_all();
|
||||||
|
if (std::this_thread::get_id() == _thread.get_id()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_thread.joinable()) {
|
if (_thread.joinable()) {
|
||||||
_thread.join();
|
_thread.join();
|
||||||
}
|
}
|
||||||
@@ -69,7 +82,7 @@ void ActionQueue::Stop()
|
|||||||
|
|
||||||
bool ActionQueue::IsRunning() const
|
bool ActionQueue::IsRunning() const
|
||||||
{
|
{
|
||||||
return _thread.joinable();
|
return !_stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ActionQueue::RunsOnStartup() const
|
bool ActionQueue::RunsOnStartup() const
|
||||||
@@ -358,6 +371,27 @@ void LoadActionQueues(obs_data_t *obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool queueWithNameExists(const std::string &name)
|
||||||
|
{
|
||||||
|
return !GetWeakActionQueueByName(name).expired();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportQueues(obs_data_t *data)
|
||||||
|
{
|
||||||
|
OBSDataArrayAutoRelease array =
|
||||||
|
obs_data_get_array(data, "actionQueues");
|
||||||
|
size_t count = obs_data_array_count(array);
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
OBSDataAutoRelease arrayElement = obs_data_array_item(array, i);
|
||||||
|
auto queue = ActionQueue::Create();
|
||||||
|
queue->Load(arrayElement);
|
||||||
|
if (queueWithNameExists(queue->Name())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
queues.emplace_back(queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::weak_ptr<ActionQueue> GetWeakActionQueueByName(const std::string &name)
|
std::weak_ptr<ActionQueue> GetWeakActionQueueByName(const std::string &name)
|
||||||
{
|
{
|
||||||
for (const auto &queue : queues) {
|
for (const auto &queue : queues) {
|
||||||
@@ -39,7 +39,7 @@ private:
|
|||||||
|
|
||||||
bool _runOnStartup = true;
|
bool _runOnStartup = true;
|
||||||
bool _resolveVariablesOnAdd = true;
|
bool _resolveVariablesOnAdd = true;
|
||||||
std::atomic_bool _stop = {false};
|
std::atomic_bool _stop = {true};
|
||||||
std::mutex _mutex;
|
std::mutex _mutex;
|
||||||
std::condition_variable _cv;
|
std::condition_variable _cv;
|
||||||
std::thread _thread;
|
std::thread _thread;
|
||||||
@@ -95,9 +95,11 @@ signals:
|
|||||||
void Remove(const QString &);
|
void Remove(const QString &);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::deque<std::shared_ptr<Item>> &GetActionQueues();
|
||||||
void SetupActionQueues();
|
void SetupActionQueues();
|
||||||
void SaveActionQueues(obs_data_t *);
|
void SaveActionQueues(obs_data_t *);
|
||||||
void LoadActionQueues(obs_data_t *);
|
void LoadActionQueues(obs_data_t *);
|
||||||
|
void ImportQueues(obs_data_t *);
|
||||||
std::weak_ptr<ActionQueue> GetWeakActionQueueByName(const std::string &name);
|
std::weak_ptr<ActionQueue> GetWeakActionQueueByName(const std::string &name);
|
||||||
std::weak_ptr<ActionQueue> GetWeakActionQueueByQString(const QString &name);
|
std::weak_ptr<ActionQueue> GetWeakActionQueueByQString(const QString &name);
|
||||||
std::string GetActionQueueName(const std::weak_ptr<ActionQueue> &);
|
std::string GetActionQueueName(const std::weak_ptr<ActionQueue> &);
|
||||||
@@ -187,24 +187,6 @@ void SwitcherData::RunPostLoadSteps()
|
|||||||
postLoadSteps.clear();
|
postLoadSteps.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::AddPluginInitStep(std::function<void()> function)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
pluginInitSteps.emplace_back(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitcherData::AddPluginPostLoadStep(std::function<void()> function)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
pluginPostLoadSteps.emplace_back(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitcherData::AddPluginCleanupStep(std::function<void()> function)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
pluginCleanupSteps.emplace_back(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SwitcherData::AddSaveStep(std::function<void(obs_data_t *)> function)
|
void SwitcherData::AddSaveStep(std::function<void(obs_data_t *)> function)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
|||||||
@@ -65,9 +65,6 @@ public:
|
|||||||
void AddPostLoadStep(std::function<void()>);
|
void AddPostLoadStep(std::function<void()>);
|
||||||
void AddIntervalResetStep(std::function<void()>, bool lock = true);
|
void AddIntervalResetStep(std::function<void()>, bool lock = true);
|
||||||
void RunPostLoadSteps();
|
void RunPostLoadSteps();
|
||||||
void AddPluginInitStep(std::function<void()>);
|
|
||||||
void AddPluginPostLoadStep(std::function<void()>);
|
|
||||||
void AddPluginCleanupStep(std::function<void()>);
|
|
||||||
bool CheckForMatch(OBSWeakSource &scene, OBSWeakSource &transition,
|
bool CheckForMatch(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||||
int &linger, bool &setPreviousSceneAsMatch,
|
int &linger, bool &setPreviousSceneAsMatch,
|
||||||
bool ¯oMatch);
|
bool ¯oMatch);
|
||||||
@@ -106,9 +103,6 @@ public:
|
|||||||
std::vector<std::function<void(obs_data_t *)>> loadSteps;
|
std::vector<std::function<void(obs_data_t *)>> loadSteps;
|
||||||
std::vector<std::function<void()>> postLoadSteps;
|
std::vector<std::function<void()>> postLoadSteps;
|
||||||
std::vector<std::function<void()>> resetIntervalSteps;
|
std::vector<std::function<void()>> resetIntervalSteps;
|
||||||
std::vector<std::function<void()>> pluginInitSteps;
|
|
||||||
std::vector<std::function<void()>> pluginPostLoadSteps;
|
|
||||||
std::vector<std::function<void()>> pluginCleanupSteps;
|
|
||||||
|
|
||||||
bool firstBoot = true;
|
bool firstBoot = true;
|
||||||
bool transitionActive = false;
|
bool transitionActive = false;
|
||||||
@@ -171,7 +165,6 @@ public:
|
|||||||
/* --- Start of UI section --- */
|
/* --- Start of UI section --- */
|
||||||
|
|
||||||
bool settingsWindowOpened = false;
|
bool settingsWindowOpened = false;
|
||||||
int lastOpenedTab = -1;
|
|
||||||
std::string lastImportPath;
|
std::string lastImportPath;
|
||||||
QStringList loadFailureLibs;
|
QStringList loadFailureLibs;
|
||||||
bool warnPluginLoadFailure = true;
|
bool warnPluginLoadFailure = true;
|
||||||
|
|||||||
63
lib/utils/double-slider.cpp
Normal file
63
lib/utils/double-slider.cpp
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#include "double-slider.hpp"
|
||||||
|
#include <QWheelEvent>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
SliderIgnoreScroll::SliderIgnoreScroll(QWidget *parent) : QSlider(parent)
|
||||||
|
{
|
||||||
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
|
}
|
||||||
|
|
||||||
|
SliderIgnoreScroll::SliderIgnoreScroll(Qt::Orientation orientation,
|
||||||
|
QWidget *parent)
|
||||||
|
: QSlider(parent)
|
||||||
|
{
|
||||||
|
setFocusPolicy(Qt::StrongFocus);
|
||||||
|
setOrientation(orientation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SliderIgnoreScroll::wheelEvent(QWheelEvent *event)
|
||||||
|
{
|
||||||
|
if (!hasFocus()) {
|
||||||
|
event->ignore();
|
||||||
|
} else {
|
||||||
|
QSlider::wheelEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleSlider::DoubleSlider(QWidget *parent) : SliderIgnoreScroll(parent)
|
||||||
|
{
|
||||||
|
connect(this, &DoubleSlider::valueChanged, [this](int val) {
|
||||||
|
emit DoubleValChanged((minVal / minStep + val) * minStep);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoubleSlider::SetDoubleConstraints(double newMin, double newMax,
|
||||||
|
double newStep, double val)
|
||||||
|
{
|
||||||
|
minVal = newMin;
|
||||||
|
maxVal = newMax;
|
||||||
|
minStep = newStep;
|
||||||
|
|
||||||
|
double total = maxVal - minVal;
|
||||||
|
int intMax = int(total / minStep);
|
||||||
|
|
||||||
|
setMinimum(0);
|
||||||
|
setMaximum(intMax);
|
||||||
|
setSingleStep(1);
|
||||||
|
SetDoubleVal(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
double DoubleSlider::DoubleValue()
|
||||||
|
{
|
||||||
|
return (minVal / minStep + value()) * minStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoubleSlider::SetDoubleVal(double val)
|
||||||
|
{
|
||||||
|
setValue(lround((val - minVal) / minStep));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
40
lib/utils/double-slider.hpp
Normal file
40
lib/utils/double-slider.hpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// Based on OBS DoubleSlider and SliderIgnoreScroll implementation
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "export-symbol-helper.hpp"
|
||||||
|
|
||||||
|
#include <QSlider>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
class SliderIgnoreScroll : public QSlider {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SliderIgnoreScroll(QWidget *parent = nullptr);
|
||||||
|
SliderIgnoreScroll(Qt::Orientation orientation,
|
||||||
|
QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void wheelEvent(QWheelEvent *event) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ADVSS_EXPORT DoubleSlider : public SliderIgnoreScroll {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
double minVal = 0, maxVal = 100, minStep = 1;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DoubleSlider(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
void SetDoubleConstraints(double newMin, double newMax, double newStep,
|
||||||
|
double val);
|
||||||
|
double DoubleValue();
|
||||||
|
signals:
|
||||||
|
void DoubleValChanged(double val);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void SetDoubleVal(double val);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -177,7 +177,7 @@ void ItemSelection::RenameItem()
|
|||||||
Item *item = variant.value<Item *>();
|
Item *item = variant.value<Item *>();
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
bool accepted = AdvSSNameDialog::AskForName(
|
bool accepted = NameDialog::AskForName(
|
||||||
this, obs_module_text("AdvSceneSwitcher.windowTitle"),
|
this, obs_module_text("AdvSceneSwitcher.windowTitle"),
|
||||||
obs_module_text("AdvSceneSwitcher.item.newName"), name,
|
obs_module_text("AdvSceneSwitcher.item.newName"), name,
|
||||||
QString::fromStdString(item->Name()));
|
QString::fromStdString(item->Name()));
|
||||||
@@ -347,4 +347,18 @@ void Item::Save(obs_data_t *obj) const
|
|||||||
obs_data_set_string(obj, "name", _name.c_str());
|
obs_data_set_string(obj, "name", _name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RemoveItemsByName(std::deque<std::shared_ptr<Item>> &items,
|
||||||
|
const QStringList &names)
|
||||||
|
{
|
||||||
|
for (const auto &name : names) {
|
||||||
|
items.erase(std::remove_if(
|
||||||
|
items.begin(), items.end(),
|
||||||
|
[name](const std::shared_ptr<Item> &item) {
|
||||||
|
return item->Name() ==
|
||||||
|
name.toStdString();
|
||||||
|
}),
|
||||||
|
items.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ protected:
|
|||||||
friend ItemSettingsDialog;
|
friend ItemSettingsDialog;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void EXPORT RemoveItemsByName(std::deque<std::shared_ptr<Item>> &items,
|
||||||
|
const QStringList &names);
|
||||||
|
|
||||||
class ItemSettingsDialog : public QDialog {
|
class ItemSettingsDialog : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
|||||||
@@ -5,22 +5,22 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
AdvSSNameDialog::AdvSSNameDialog(QWidget *parent) : QDialog(parent)
|
NameDialog::NameDialog(QWidget *parent)
|
||||||
|
: QDialog(parent),
|
||||||
|
_label(new QLabel(this)),
|
||||||
|
_userText(new QLineEdit(this))
|
||||||
|
|
||||||
{
|
{
|
||||||
setModal(true);
|
setModal(true);
|
||||||
setWindowModality(Qt::WindowModality::WindowModal);
|
setWindowModality(Qt::WindowModality::WindowModal);
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
setFixedWidth(555);
|
setFixedWidth(555);
|
||||||
setMinimumHeight(100);
|
setMinimumHeight(100);
|
||||||
QVBoxLayout *layout = new QVBoxLayout;
|
auto layout = new QVBoxLayout;
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
label = new QLabel(this);
|
layout->addWidget(_label);
|
||||||
layout->addWidget(label);
|
layout->addWidget(_userText);
|
||||||
label->setText("Set Text");
|
|
||||||
|
|
||||||
userText = new QLineEdit(this);
|
|
||||||
layout->addWidget(userText);
|
|
||||||
|
|
||||||
QDialogButtonBox *buttonbox = new QDialogButtonBox(
|
QDialogButtonBox *buttonbox = new QDialogButtonBox(
|
||||||
QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
@@ -30,43 +30,44 @@ AdvSSNameDialog::AdvSSNameDialog(QWidget *parent) : QDialog(parent)
|
|||||||
connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsWhitespace(char ch)
|
static bool isWhitespace(char ch)
|
||||||
{
|
{
|
||||||
return ch == ' ' || ch == '\t';
|
return ch == ' ' || ch == '\t';
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CleanWhitespace(std::string &str)
|
static void cleanWhitespace(std::string &str)
|
||||||
{
|
{
|
||||||
while (str.size() && IsWhitespace(str.back()))
|
while (str.size() && isWhitespace(str.back())) {
|
||||||
str.erase(str.end() - 1);
|
str.erase(str.end() - 1);
|
||||||
while (str.size() && IsWhitespace(str.front()))
|
}
|
||||||
|
while (str.size() && isWhitespace(str.front())) {
|
||||||
str.erase(str.begin());
|
str.erase(str.begin());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AdvSSNameDialog::AskForName(QWidget *parent, const QString &title,
|
bool NameDialog::AskForName(QWidget *parent, const QString &title,
|
||||||
const QString &text,
|
const QString &prompt, std::string &userTextInput,
|
||||||
std::string &userTextInput,
|
const QString &placeHolder, int maxSize, bool clean)
|
||||||
const QString &placeHolder, int maxSize,
|
|
||||||
bool clean)
|
|
||||||
{
|
{
|
||||||
if (maxSize <= 0 || maxSize > 32767) {
|
if (maxSize <= 0 || maxSize > 32767) {
|
||||||
maxSize = 170;
|
maxSize = 170;
|
||||||
}
|
}
|
||||||
|
|
||||||
AdvSSNameDialog dialog(parent);
|
NameDialog dialog(parent);
|
||||||
dialog.setWindowTitle(title);
|
dialog.setWindowTitle(title);
|
||||||
|
|
||||||
dialog.label->setText(text);
|
dialog._label->setVisible(!prompt.isEmpty());
|
||||||
dialog.userText->setMaxLength(maxSize);
|
dialog._label->setText(prompt);
|
||||||
dialog.userText->setText(placeHolder);
|
dialog._userText->setMaxLength(maxSize);
|
||||||
dialog.userText->selectAll();
|
dialog._userText->setText(placeHolder);
|
||||||
|
dialog._userText->selectAll();
|
||||||
|
|
||||||
if (dialog.exec() != DialogCode::Accepted) {
|
if (dialog.exec() != DialogCode::Accepted) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
userTextInput = dialog.userText->text().toUtf8().constData();
|
userTextInput = dialog._userText->text().toUtf8().constData();
|
||||||
if (clean) {
|
if (clean) {
|
||||||
CleanWhitespace(userTextInput);
|
cleanWhitespace(userTextInput);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,23 +8,23 @@
|
|||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
// Based on OBS's NameDialog
|
// Based on OBS's NameDialog
|
||||||
class AdvSSNameDialog : public QDialog {
|
class NameDialog : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AdvSSNameDialog(QWidget *parent);
|
NameDialog(QWidget *parent);
|
||||||
|
|
||||||
// Returns true if user clicks OK, false otherwise
|
// Returns true if user clicks OK, false otherwise
|
||||||
// userTextInput returns string that user typed into dialog
|
// userTextInput returns string that user typed into dialog
|
||||||
EXPORT static bool AskForName(QWidget *parent, const QString &title,
|
EXPORT static bool AskForName(QWidget *parent, const QString &title,
|
||||||
const QString &text,
|
const QString &prompt,
|
||||||
std::string &userTextInput,
|
std::string &userTextInput,
|
||||||
const QString &placeHolder = QString(""),
|
const QString &placeHolder = QString(""),
|
||||||
int maxSize = 170, bool clean = true);
|
int maxSize = 170, bool clean = true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel *label;
|
QLabel *_label;
|
||||||
QLineEdit *userText;
|
QLineEdit *_userText;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ namespace advss {
|
|||||||
const char *obs_module_text(const char *text)
|
const char *obs_module_text(const char *text)
|
||||||
{
|
{
|
||||||
if (!advss::switcher) {
|
if (!advss::switcher) {
|
||||||
return "";
|
assert(false);
|
||||||
|
return "obs_module_text called too early";
|
||||||
}
|
}
|
||||||
return advss::switcher->Translate(text);
|
return advss::switcher->Translate(text);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,26 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
|
static std::vector<std::function<void()>> &getPluginInitSteps()
|
||||||
|
{
|
||||||
|
static std::vector<std::function<void()>> steps;
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::function<void()>> &getPluginPostLoadSteps()
|
||||||
|
{
|
||||||
|
static std::vector<std::function<void()>> steps;
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::function<void()>> &getPluginCleanupSteps()
|
||||||
|
{
|
||||||
|
static std::vector<std::function<void()>> steps;
|
||||||
|
return steps;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::mutex mutex;
|
||||||
|
|
||||||
void SavePluginSettings(obs_data_t *obj)
|
void SavePluginSettings(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
GetSwitcher()->SaveSettings(obj);
|
GetSwitcher()->SaveSettings(obj);
|
||||||
@@ -40,17 +60,44 @@ void RunPostLoadSteps()
|
|||||||
|
|
||||||
void AddPluginInitStep(std::function<void()> step)
|
void AddPluginInitStep(std::function<void()> step)
|
||||||
{
|
{
|
||||||
GetSwitcher()->AddPluginInitStep(step);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
getPluginInitSteps().emplace_back(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddPluginPostLoadStep(std::function<void()> step)
|
void AddPluginPostLoadStep(std::function<void()> step)
|
||||||
{
|
{
|
||||||
GetSwitcher()->AddPluginPostLoadStep(step);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
getPluginPostLoadSteps().emplace_back(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddPluginCleanupStep(std::function<void()> step)
|
void AddPluginCleanupStep(std::function<void()> step)
|
||||||
{
|
{
|
||||||
GetSwitcher()->AddPluginCleanupStep(step);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
getPluginCleanupSteps().emplace_back(step);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunPluginInitSteps()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
for (const auto &step : getPluginInitSteps()) {
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunPluginPostLoadSteps()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
for (const auto &step : getPluginPostLoadSteps()) {
|
||||||
|
step();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunPluginCleanupSteps()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
|
for (const auto &step : getPluginCleanupSteps()) {
|
||||||
|
step();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StopPlugin()
|
void StopPlugin()
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ EXPORT void RunPostLoadSteps();
|
|||||||
EXPORT void AddPluginInitStep(std::function<void()>);
|
EXPORT void AddPluginInitStep(std::function<void()>);
|
||||||
EXPORT void AddPluginPostLoadStep(std::function<void()>);
|
EXPORT void AddPluginPostLoadStep(std::function<void()>);
|
||||||
EXPORT void AddPluginCleanupStep(std::function<void()>);
|
EXPORT void AddPluginCleanupStep(std::function<void()>);
|
||||||
|
void RunPluginInitSteps();
|
||||||
|
extern "C" EXPORT void RunPluginPostLoadSteps();
|
||||||
|
void RunPluginCleanupSteps();
|
||||||
|
|
||||||
EXPORT void StopPlugin();
|
EXPORT void StopPlugin();
|
||||||
EXPORT void StartPlugin();
|
EXPORT void StartPlugin();
|
||||||
|
|||||||
70
lib/utils/resource-table-hotkey-handler.cpp
Normal file
70
lib/utils/resource-table-hotkey-handler.cpp
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
#include "resource-table-hotkey-handler.hpp"
|
||||||
|
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
void RegisterHotkeyFunction(QWidget *widget, Qt::Key key,
|
||||||
|
std::function<void()> func)
|
||||||
|
{
|
||||||
|
ResourceTabHotkeyHandler::Instance()->RegisterHandler(widget, key,
|
||||||
|
func);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeregisterHotkeyFunctions(QWidget *widget)
|
||||||
|
{
|
||||||
|
ResourceTabHotkeyHandler::Instance()->Deregister(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceTabHotkeyHandler *ResourceTabHotkeyHandler::Instance()
|
||||||
|
{
|
||||||
|
static ResourceTabHotkeyHandler handler;
|
||||||
|
return &handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceTabHotkeyHandler::RegisterHandler(QWidget *widget, Qt::Key key,
|
||||||
|
std::function<void()> func)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
_callbacks.emplace(widget, CallbackData{key, func});
|
||||||
|
widget->installEventFilter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceTabHotkeyHandler::Deregister(QWidget *widget)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
_callbacks.erase(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ResourceTabHotkeyHandler::eventFilter(QObject *obj, QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() != QEvent::KeyPress) {
|
||||||
|
return QObject::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||||
|
auto pressedKey = keyEvent->key();
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(_mutex);
|
||||||
|
auto it = _callbacks.find(obj);
|
||||||
|
if (it == _callbacks.end()) {
|
||||||
|
return QObject::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto current = it;
|
||||||
|
while (current != _callbacks.end() && current->first == it->first) {
|
||||||
|
auto &[_, cbData] = *current;
|
||||||
|
if (pressedKey != cbData.key) {
|
||||||
|
++current;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
cbData.func();
|
||||||
|
++current;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QObject::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
37
lib/utils/resource-table-hotkey-handler.hpp
Normal file
37
lib/utils/resource-table-hotkey-handler.hpp
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "export-symbol-helper.hpp"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <mutex>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
EXPORT void RegisterHotkeyFunction(QWidget *, Qt::Key,
|
||||||
|
std::function<void()> func);
|
||||||
|
EXPORT void DeregisterHotkeyFunctions(QWidget *);
|
||||||
|
|
||||||
|
class ResourceTabHotkeyHandler : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
static ResourceTabHotkeyHandler *Instance();
|
||||||
|
void RegisterHandler(QWidget *, Qt::Key, std::function<void()> func);
|
||||||
|
void Deregister(QWidget *);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct CallbackData {
|
||||||
|
Qt::Key key;
|
||||||
|
std::function<void()> func;
|
||||||
|
};
|
||||||
|
|
||||||
|
ResourceTabHotkeyHandler() : QObject(){};
|
||||||
|
|
||||||
|
std::multimap<QObject *, CallbackData> _callbacks;
|
||||||
|
std::mutex _mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
157
lib/utils/resource-table.cpp
Normal file
157
lib/utils/resource-table.cpp
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
#include "resource-table.hpp"
|
||||||
|
#include "plugin-state-helpers.hpp"
|
||||||
|
#include "resource-table-hotkey-handler.hpp"
|
||||||
|
#include "ui-helpers.hpp"
|
||||||
|
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QHeaderView>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
ResourceTable::ResourceTable(QTabWidget *parent, const QString &help,
|
||||||
|
const QString &addToolTip,
|
||||||
|
const QString &removeToolTip,
|
||||||
|
const QStringList &headers,
|
||||||
|
const std::function<void()> &openSettings)
|
||||||
|
: QWidget(parent),
|
||||||
|
_table(new QTableWidget()),
|
||||||
|
_add(new QPushButton()),
|
||||||
|
_remove(new QPushButton()),
|
||||||
|
_help(new QLabel(help))
|
||||||
|
{
|
||||||
|
_add->setMaximumWidth(22);
|
||||||
|
_add->setProperty("themeID",
|
||||||
|
QVariant(QString::fromUtf8("addIconSmall")));
|
||||||
|
_add->setFlat(true);
|
||||||
|
_add->setToolTip(addToolTip);
|
||||||
|
|
||||||
|
_remove->setMaximumWidth(22);
|
||||||
|
_remove->setProperty("themeID",
|
||||||
|
QVariant(QString::fromUtf8("removeIconSmall")));
|
||||||
|
_remove->setFlat(true);
|
||||||
|
_remove->setToolTip(removeToolTip);
|
||||||
|
|
||||||
|
_help->setWordWrap(true);
|
||||||
|
_help->setAlignment(Qt::AlignCenter);
|
||||||
|
|
||||||
|
_table->setColumnCount(headers.size());
|
||||||
|
_table->horizontalHeader()->setSectionResizeMode(
|
||||||
|
QHeaderView::ResizeMode::Interactive);
|
||||||
|
_table->setHorizontalHeaderLabels(headers);
|
||||||
|
_table->verticalHeader()->hide();
|
||||||
|
_table->setCornerButtonEnabled(false);
|
||||||
|
_table->setShowGrid(false);
|
||||||
|
_table->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
|
_table->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
|
||||||
|
auto helpAndTableLayout = new QGridLayout();
|
||||||
|
helpAndTableLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
helpAndTableLayout->addWidget(_table, 0, 0);
|
||||||
|
helpAndTableLayout->addWidget(_help, 0, 0, Qt::AlignCenter);
|
||||||
|
|
||||||
|
auto controlLayout = new QHBoxLayout;
|
||||||
|
controlLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
controlLayout->addWidget(_add);
|
||||||
|
controlLayout->addWidget(_remove);
|
||||||
|
controlLayout->addStretch();
|
||||||
|
|
||||||
|
auto layout = new QVBoxLayout();
|
||||||
|
layout->addLayout(helpAndTableLayout);
|
||||||
|
layout->addLayout(controlLayout);
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
QWidget::connect(_add, SIGNAL(clicked()), this, SLOT(Add()));
|
||||||
|
QWidget::connect(_remove, SIGNAL(clicked()), this, SLOT(Remove()));
|
||||||
|
QWidget::connect(_table, &QTableWidget::cellDoubleClicked,
|
||||||
|
[openSettings]() { openSettings(); });
|
||||||
|
|
||||||
|
RegisterHotkeyFunction(this, Qt::Key_F2, openSettings);
|
||||||
|
RegisterHotkeyFunction(this, Qt::Key_Delete, [this]() { Remove(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceTable::~ResourceTable()
|
||||||
|
{
|
||||||
|
DeregisterHotkeyFunctions(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceTable::SetHelpVisible(bool visible) const
|
||||||
|
{
|
||||||
|
_help->setVisible(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceTable::HighlightAddButton(bool enable)
|
||||||
|
{
|
||||||
|
_add->disconnect(_highlightConnection);
|
||||||
|
if (enable && HighlightUIElementsEnabled()) {
|
||||||
|
_highlightConnection = PulseWidget(_add, QColor(Qt::green));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourceTable::resizeEvent(QResizeEvent *)
|
||||||
|
{
|
||||||
|
const auto columnCount = _table->columnCount();
|
||||||
|
const auto columnSize = (_table->width() - 1) / columnCount;
|
||||||
|
for (int i = 0; i < columnCount; ++i) {
|
||||||
|
_table->horizontalHeader()->resizeSection(i, columnSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddItemTableRow(QTableWidget *table, const QStringList &cellLabels)
|
||||||
|
{
|
||||||
|
int row = table->rowCount();
|
||||||
|
table->setRowCount(row + 1);
|
||||||
|
|
||||||
|
int col = 0;
|
||||||
|
for (const auto &cellLabel : cellLabels) {
|
||||||
|
auto *item = new QTableWidgetItem(cellLabel);
|
||||||
|
item->setToolTip(cellLabel);
|
||||||
|
table->setItem(row, col, item);
|
||||||
|
col++;
|
||||||
|
}
|
||||||
|
|
||||||
|
table->sortByColumn(0, Qt::AscendingOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateItemTableRow(QTableWidget *table, int row,
|
||||||
|
const QStringList &cellLabels)
|
||||||
|
{
|
||||||
|
int col = 1; // Skip the name cell
|
||||||
|
for (const auto &cellLabel : cellLabels) {
|
||||||
|
auto item = table->item(row, col);
|
||||||
|
item->setText(cellLabel);
|
||||||
|
item->setToolTip(cellLabel);
|
||||||
|
col++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenameItemTableRow(QTableWidget *table, const QString &oldName,
|
||||||
|
const QString &newName)
|
||||||
|
{
|
||||||
|
for (int row = 0; row < table->rowCount(); row++) {
|
||||||
|
auto item = table->item(row, 0);
|
||||||
|
if (!item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item->text() == oldName) {
|
||||||
|
item->setText(newName);
|
||||||
|
table->sortByColumn(0, Qt::AscendingOrder);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveItemTableRow(QTableWidget *table, const QString &name)
|
||||||
|
{
|
||||||
|
for (int row = 0; row < table->rowCount(); ++row) {
|
||||||
|
auto item = table->item(row, 0);
|
||||||
|
if (item && item->text() == name) {
|
||||||
|
table->removeRow(row);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table->sortByColumn(0, Qt::AscendingOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
50
lib/utils/resource-table.hpp
Normal file
50
lib/utils/resource-table.hpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "export-symbol-helper.hpp"
|
||||||
|
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QString>
|
||||||
|
#include <QTableWidget>
|
||||||
|
|
||||||
|
class QResizeEvent;
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
class ADVSS_EXPORT ResourceTable : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ResourceTable(QTabWidget *parent, const QString &help,
|
||||||
|
const QString &addToolTip, const QString &removeToolTip,
|
||||||
|
const QStringList &headers,
|
||||||
|
const std::function<void()> &openSettings);
|
||||||
|
virtual ~ResourceTable();
|
||||||
|
|
||||||
|
QTableWidget *Table() const { return _table; }
|
||||||
|
void SetHelpVisible(bool) const;
|
||||||
|
void HighlightAddButton(bool);
|
||||||
|
|
||||||
|
protected slots:
|
||||||
|
virtual void Add() {}
|
||||||
|
virtual void Remove() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTableWidget *_table;
|
||||||
|
QPushButton *_add;
|
||||||
|
QPushButton *_remove;
|
||||||
|
QLabel *_help;
|
||||||
|
|
||||||
|
QMetaObject::Connection _highlightConnection;
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPORT void AddItemTableRow(QTableWidget *table, const QStringList &cells);
|
||||||
|
EXPORT void UpdateItemTableRow(QTableWidget *table, int row,
|
||||||
|
const QStringList &cells);
|
||||||
|
EXPORT void RenameItemTableRow(QTableWidget *table, const QString &oldName,
|
||||||
|
const QString &newName);
|
||||||
|
EXPORT void RemoveItemTableRow(QTableWidget *table, const QString &name);
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
Section::Section(const int animationDuration, QWidget *parent)
|
Section::Section(const int animationDuration, QWidget *parent)
|
||||||
: QWidget(parent), _animationDuration(animationDuration)
|
: QWidget(parent),
|
||||||
|
_animationDuration(animationDuration)
|
||||||
{
|
{
|
||||||
_toggleButton = new QToolButton(this);
|
_toggleButton = new QToolButton(this);
|
||||||
_headerLine = new QFrame(this);
|
_headerLine = new QFrame(this);
|
||||||
|
|||||||
22
lib/utils/single-char-selection.cpp
Normal file
22
lib/utils/single-char-selection.cpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#include "single-char-selection.hpp"
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
SingleCharSelection::SingleCharSelection(QWidget *parent) : QLineEdit(parent)
|
||||||
|
{
|
||||||
|
setMaxLength(1);
|
||||||
|
setMaximumWidth(50);
|
||||||
|
connect(this, &QLineEdit::textChanged, this,
|
||||||
|
&SingleCharSelection::CharChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SingleCharSelection::HandleTextChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (text.length() == 1) {
|
||||||
|
emit CharChanged(text);
|
||||||
|
} else if (text.length() > 1) {
|
||||||
|
setText(text.left(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
18
lib/utils/single-char-selection.hpp
Normal file
18
lib/utils/single-char-selection.hpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <QLineEdit>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
class SingleCharSelection : public QLineEdit {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SingleCharSelection(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void CharChanged(const QString &character);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void HandleTextChanged(const QString &text);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
182
lib/utils/tab-helpers.cpp
Normal file
182
lib/utils/tab-helpers.cpp
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
#include "tab-helpers.hpp"
|
||||||
|
#include "log-helper.hpp"
|
||||||
|
#include "obs-module-helper.hpp"
|
||||||
|
|
||||||
|
#include <obs.hpp>
|
||||||
|
#include <QTabBar>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
static std::vector<std::string> tabNames = {
|
||||||
|
"generalTab", "macroTab", "windowTitleTab",
|
||||||
|
"executableTab", "screenRegionTab", "mediaTab",
|
||||||
|
"fileTab", "randomTab", "timeTab",
|
||||||
|
"idleTab", "sceneSequenceTab", "audioTab",
|
||||||
|
"videoTab", "networkTab", "sceneGroupTab",
|
||||||
|
"transitionsTab", "pauseTab", "sceneTriggerTab"};
|
||||||
|
|
||||||
|
static std::vector<int> tabOrder = std::vector<int>(tabNames.size());
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct TabCallbacks {
|
||||||
|
std::function<QWidget *()> createWidget;
|
||||||
|
std::function<void(QTabWidget *)> setupTab;
|
||||||
|
};
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
static std::unordered_map<const char *, TabCallbacks> createTabCallbacks;
|
||||||
|
|
||||||
|
static int lastOpenedTab = -1;
|
||||||
|
|
||||||
|
void SetTabVisibleByName(QTabWidget *tabWidget, bool visible,
|
||||||
|
const QString &name)
|
||||||
|
{
|
||||||
|
for (int idx = 0; idx < tabWidget->count(); idx++) {
|
||||||
|
if (tabWidget->tabText(idx) != name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
tabWidget->setTabVisible(idx, visible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddSetupTabCallback(const char *tabName,
|
||||||
|
std::function<QWidget *()> createWidget,
|
||||||
|
std::function<void(QTabWidget *)> setupTab)
|
||||||
|
{
|
||||||
|
if (std::find(tabNames.begin(), tabNames.end(), tabName) !=
|
||||||
|
tabNames.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tabNames.emplace_back(tabName);
|
||||||
|
TabCallbacks callbacks = {createWidget, setupTab};
|
||||||
|
createTabCallbacks.emplace(tabName, callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveLastOpenedTab(QTabWidget *tabWidget)
|
||||||
|
{
|
||||||
|
lastOpenedTab = tabWidget->currentIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetLastOpenedTab()
|
||||||
|
{
|
||||||
|
lastOpenedTab = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveTabOrder(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
OBSDataArrayAutoRelease tabWidgetOrder = obs_data_array_create();
|
||||||
|
for (size_t i = 0; i < tabNames.size(); i++) {
|
||||||
|
OBSDataAutoRelease entry = obs_data_create();
|
||||||
|
obs_data_set_int(entry, tabNames[i].c_str(), tabOrder[i]);
|
||||||
|
obs_data_array_push_back(tabWidgetOrder, entry);
|
||||||
|
}
|
||||||
|
obs_data_set_array(obj, "tabWidgetOrder", tabWidgetOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool tabWidgetOrderValid()
|
||||||
|
{
|
||||||
|
auto tmp = std::vector<int>(tabNames.size());
|
||||||
|
std::iota(tmp.begin(), tmp.end(), 0);
|
||||||
|
|
||||||
|
for (auto &p : tmp) {
|
||||||
|
auto it = std::find(tabOrder.begin(), tabOrder.end(), p);
|
||||||
|
if (it == tabOrder.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resetTabWidgetOrder()
|
||||||
|
{
|
||||||
|
tabOrder = std::vector<int>(tabNames.size());
|
||||||
|
std::iota(tabOrder.begin(), tabOrder.end(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadTabOrder(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
OBSDataArrayAutoRelease defaultTabWidgetOrder = obs_data_array_create();
|
||||||
|
for (size_t i = 0; i < tabNames.size(); i++) {
|
||||||
|
OBSDataAutoRelease entry = obs_data_create();
|
||||||
|
obs_data_set_default_int(entry, tabNames[i].c_str(), i);
|
||||||
|
obs_data_array_push_back(defaultTabWidgetOrder, entry);
|
||||||
|
}
|
||||||
|
obs_data_set_default_array(obj, "tabWidgetOrder",
|
||||||
|
defaultTabWidgetOrder);
|
||||||
|
|
||||||
|
tabOrder.clear();
|
||||||
|
OBSDataArrayAutoRelease tabWidgetOrder =
|
||||||
|
obs_data_get_array(obj, "tabWidgetOrder");
|
||||||
|
for (size_t i = 0; i < tabNames.size(); i++) {
|
||||||
|
OBSDataAutoRelease entry =
|
||||||
|
obs_data_array_item(tabWidgetOrder, i);
|
||||||
|
tabOrder.emplace_back(
|
||||||
|
(int)(obs_data_get_int(entry, tabNames[i].c_str())));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tabWidgetOrderValid()) {
|
||||||
|
resetTabWidgetOrder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int findTabIndex(QTabWidget *tabWidget, int pos)
|
||||||
|
{
|
||||||
|
int at = -1;
|
||||||
|
QString tabName = QString::fromStdString(tabNames.at(pos));
|
||||||
|
QWidget *page = tabWidget->findChild<QWidget *>(tabName);
|
||||||
|
if (page) {
|
||||||
|
at = tabWidget->indexOf(page);
|
||||||
|
}
|
||||||
|
if (at == -1) {
|
||||||
|
blog(LOG_INFO, "failed to find tab %s",
|
||||||
|
tabName.toUtf8().constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
return at;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTabOrder(QTabWidget *tabWidget)
|
||||||
|
{
|
||||||
|
if (!tabWidgetOrderValid()) {
|
||||||
|
resetTabWidgetOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto bar = tabWidget->tabBar();
|
||||||
|
for (int i = 0; i < bar->count(); ++i) {
|
||||||
|
int curPos = findTabIndex(tabWidget, tabOrder[i]);
|
||||||
|
|
||||||
|
if (i != curPos && curPos != -1) {
|
||||||
|
bar->moveTab(curPos, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::connect(bar, &QTabBar::tabMoved, [](int from, int to) {
|
||||||
|
std::swap(tabOrder[from], tabOrder[to]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetCurrentTab(QTabWidget *tabWidget)
|
||||||
|
{
|
||||||
|
if (lastOpenedTab >= 0) {
|
||||||
|
tabWidget->setCurrentIndex(lastOpenedTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupOtherTabs(QTabWidget *tabWidget)
|
||||||
|
{
|
||||||
|
for (const auto &[name, callbacks] : createTabCallbacks) {
|
||||||
|
auto widget = callbacks.createWidget();
|
||||||
|
widget->setObjectName(name);
|
||||||
|
auto tabText = obs_module_text(
|
||||||
|
(std::string("AdvSceneSwitcher.") + name + ".title")
|
||||||
|
.c_str());
|
||||||
|
tabWidget->insertTab(0, widget, tabText);
|
||||||
|
callbacks.setupTab(tabWidget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
22
lib/utils/tab-helpers.hpp
Normal file
22
lib/utils/tab-helpers.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "export-symbol-helper.hpp"
|
||||||
|
|
||||||
|
#include <obs-data.h>
|
||||||
|
#include <QTabWidget>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
EXPORT void AddSetupTabCallback(const char *tabName,
|
||||||
|
std::function<QWidget *()> createWidget,
|
||||||
|
std::function<void(QTabWidget *)> setupTab);
|
||||||
|
EXPORT void SetTabVisibleByName(QTabWidget *tabWidget, bool visible,
|
||||||
|
const QString &name);
|
||||||
|
void SaveLastOpenedTab(QTabWidget *tabWidget);
|
||||||
|
void ResetLastOpenedTab();
|
||||||
|
void SetTabOrder(QTabWidget *tabWidget);
|
||||||
|
void SetCurrentTab(QTabWidget *tabWidget);
|
||||||
|
void SetupOtherTabs(QTabWidget *tabWidget);
|
||||||
|
void SaveTabOrder(obs_data_t *obj);
|
||||||
|
void LoadTabOrder(obs_data_t *obj);
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -17,7 +17,10 @@ namespace advss {
|
|||||||
TempVariable::TempVariable(const std::string &id, const std::string &name,
|
TempVariable::TempVariable(const std::string &id, const std::string &name,
|
||||||
const std::string &description,
|
const std::string &description,
|
||||||
const std::shared_ptr<MacroSegment> &segment)
|
const std::shared_ptr<MacroSegment> &segment)
|
||||||
: _id(id), _name(name), _description(description), _segment(segment)
|
: _id(id),
|
||||||
|
_name(name),
|
||||||
|
_description(description),
|
||||||
|
_segment(segment)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,6 +250,8 @@ TempVariableSelection::TempVariableSelection(QWidget *parent)
|
|||||||
_info->setPixmap(pixmap);
|
_info->setPixmap(pixmap);
|
||||||
_info->hide();
|
_info->hide();
|
||||||
|
|
||||||
|
_selection->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||||
|
_selection->setMaximumWidth(350);
|
||||||
_selection->setDuplicatesEnabled(true);
|
_selection->setDuplicatesEnabled(true);
|
||||||
PopulateSelection();
|
PopulateSelection();
|
||||||
|
|
||||||
@@ -439,7 +444,9 @@ void NotifyUIAboutTempVarChange()
|
|||||||
|
|
||||||
AutoUpdateTooltipLabel::AutoUpdateTooltipLabel(
|
AutoUpdateTooltipLabel::AutoUpdateTooltipLabel(
|
||||||
QWidget *parent, std::function<QString()> updateFunc)
|
QWidget *parent, std::function<QString()> updateFunc)
|
||||||
: QLabel(parent), _updateFunc(updateFunc), _timer(new QTimer(this))
|
: QLabel(parent),
|
||||||
|
_updateFunc(updateFunc),
|
||||||
|
_timer(new QTimer(this))
|
||||||
{
|
{
|
||||||
connect(_timer, &QTimer::timeout, this,
|
connect(_timer, &QTimer::timeout, this,
|
||||||
&AutoUpdateTooltipLabel::UpdateTooltip);
|
&AutoUpdateTooltipLabel::UpdateTooltip);
|
||||||
|
|||||||
@@ -90,15 +90,17 @@ void VolControl::setPeakMeterType(enum obs_peak_meter_type peakMeterType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
VolumeSlider::VolumeSlider(obs_fader_t *fader, QWidget *parent)
|
VolumeSlider::VolumeSlider(obs_fader_t *fader, QWidget *parent)
|
||||||
: QSlider(parent)
|
: DoubleSlider(parent)
|
||||||
{
|
{
|
||||||
fad = fader;
|
fad = fader;
|
||||||
}
|
}
|
||||||
|
|
||||||
VolumeSlider::VolumeSlider(obs_fader_t *fader, Qt::Orientation orientation,
|
VolumeSlider::VolumeSlider(obs_fader_t *fader, Qt::Orientation orientation,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QSlider(orientation, parent)
|
: DoubleSlider(parent)
|
||||||
{
|
{
|
||||||
|
SetDoubleConstraints(0, 100, 0.01, 0);
|
||||||
|
setOrientation(orientation);
|
||||||
fad = fader;
|
fad = fader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +221,6 @@ VolControl::VolControl(OBSSource source_, bool showConfig, bool vertical)
|
|||||||
nameLabel->setText(sourceName);
|
nameLabel->setText(sourceName);
|
||||||
|
|
||||||
slider->setMinimum(0);
|
slider->setMinimum(0);
|
||||||
slider->setMaximum(int(FADER_PRECISION));
|
|
||||||
|
|
||||||
obs_fader_add_callback(obs_fader, OBSVolumeChanged, this);
|
obs_fader_add_callback(obs_fader, OBSVolumeChanged, this);
|
||||||
obs_volmeter_add_callback(obs_volmeter, OBSVolumeLevel, this);
|
obs_volmeter_add_callback(obs_volmeter, OBSVolumeLevel, this);
|
||||||
@@ -592,7 +593,9 @@ void VolumeMeter::mousePressEvent(QMouseEvent *event)
|
|||||||
|
|
||||||
VolumeMeter::VolumeMeter(QWidget *parent, obs_volmeter_t *obs_volmeter,
|
VolumeMeter::VolumeMeter(QWidget *parent, obs_volmeter_t *obs_volmeter,
|
||||||
bool vertical)
|
bool vertical)
|
||||||
: QWidget(parent), obs_volmeter(obs_volmeter), vertical(vertical)
|
: QWidget(parent),
|
||||||
|
obs_volmeter(obs_volmeter),
|
||||||
|
vertical(vertical)
|
||||||
{
|
{
|
||||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "double-slider.hpp"
|
||||||
|
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
@@ -284,7 +285,7 @@ private:
|
|||||||
QLabel *nameLabel;
|
QLabel *nameLabel;
|
||||||
QLabel *volLabel;
|
QLabel *volLabel;
|
||||||
VolumeMeter *volMeter;
|
VolumeMeter *volMeter;
|
||||||
QSlider *slider;
|
DoubleSlider *slider;
|
||||||
QPushButton *config = nullptr;
|
QPushButton *config = nullptr;
|
||||||
float levelTotal;
|
float levelTotal;
|
||||||
float levelCount;
|
float levelCount;
|
||||||
@@ -327,10 +328,10 @@ public:
|
|||||||
inline void SetContextMenu(QMenu *cm) { contextMenu = cm; }
|
inline void SetContextMenu(QMenu *cm) { contextMenu = cm; }
|
||||||
|
|
||||||
void refreshColors();
|
void refreshColors();
|
||||||
QSlider *GetSlider() const { return slider; }
|
DoubleSlider *GetSlider() const { return slider; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class VolumeSlider : public QSlider {
|
class VolumeSlider : public DoubleSlider {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1,31 +1,67 @@
|
|||||||
#include "advanced-scene-switcher.hpp"
|
#include "variable-tab.hpp"
|
||||||
|
#include "log-helper.hpp"
|
||||||
|
#include "obs-module-helper.hpp"
|
||||||
|
#include "plugin-state-helpers.hpp"
|
||||||
|
#include "sync-helpers.hpp"
|
||||||
|
#include "tab-helpers.hpp"
|
||||||
|
#include "ui-helpers.hpp"
|
||||||
#include "variable.hpp"
|
#include "variable.hpp"
|
||||||
|
|
||||||
#include <QTableWidgetItem>
|
#include <QTimer>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
static void setVariableTabVisible(QTabWidget *tabWidget, bool visible)
|
static bool registerTab();
|
||||||
|
static void setupTab(QTabWidget *);
|
||||||
|
static bool registerTabDone = registerTab();
|
||||||
|
|
||||||
|
static VariableTable *tabWidget = nullptr;
|
||||||
|
|
||||||
|
static bool registerTab()
|
||||||
{
|
{
|
||||||
for (int idx = 0; idx < tabWidget->count(); idx++) {
|
AddPluginInitStep([]() {
|
||||||
if (tabWidget->tabText(idx) !=
|
AddSetupTabCallback("variableTab", VariableTable::Create,
|
||||||
obs_module_text("AdvSceneSwitcher.variableTab.title")) {
|
setupTab);
|
||||||
continue;
|
});
|
||||||
}
|
return true;
|
||||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
|
||||||
// TODO: Switch to setTabVisible() once QT 5.15 is more wide spread
|
|
||||||
tabWidget->setTabEnabled(idx, visible);
|
|
||||||
tabWidget->setStyleSheet(
|
|
||||||
"QTabBar::tab::disabled {width: 0; height: 0; margin: 0; padding: 0; border: none;} ");
|
|
||||||
#else
|
|
||||||
tabWidget->setTabVisible(idx, visible);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString getSaveActionString(Variable *variable)
|
static void setTabVisible(QTabWidget *tabWidget, bool visible)
|
||||||
|
{
|
||||||
|
SetTabVisibleByName(
|
||||||
|
tabWidget, visible,
|
||||||
|
obs_module_text("AdvSceneSwitcher.variableTab.title"));
|
||||||
|
}
|
||||||
|
|
||||||
|
VariableTable *VariableTable::Create()
|
||||||
|
{
|
||||||
|
tabWidget = new VariableTable();
|
||||||
|
return tabWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VariableTable::Add()
|
||||||
|
{
|
||||||
|
auto newVariable = std::make_shared<Variable>();
|
||||||
|
auto accepted =
|
||||||
|
VariableSettingsDialog::AskForSettings(this, *newVariable);
|
||||||
|
if (!accepted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto lock = LockContext();
|
||||||
|
auto &variables = GetVariables();
|
||||||
|
variables.emplace_back(newVariable);
|
||||||
|
}
|
||||||
|
|
||||||
|
VariableSignalManager::Instance()->Add(
|
||||||
|
QString::fromStdString(newVariable->Name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static QString formatSaveActionText(Variable *variable)
|
||||||
{
|
{
|
||||||
QString saveAction;
|
QString saveAction;
|
||||||
|
|
||||||
switch (variable->GetSaveAction()) {
|
switch (variable->GetSaveAction()) {
|
||||||
case Variable::SaveAction::DONT_SAVE:
|
case Variable::SaveAction::DONT_SAVE:
|
||||||
saveAction = obs_module_text(
|
saveAction = obs_module_text(
|
||||||
@@ -38,123 +74,111 @@ static QString getSaveActionString(Variable *variable)
|
|||||||
case Variable::SaveAction::SET_DEFAULT:
|
case Variable::SaveAction::SET_DEFAULT:
|
||||||
saveAction =
|
saveAction =
|
||||||
QString(obs_module_text(
|
QString(obs_module_text(
|
||||||
"AdvSceneSwitcher.variable.save.default")) +
|
"AdvSceneSwitcher.variableTab.saveLoadBehavior.text.default"))
|
||||||
" \"" +
|
.arg(QString::fromStdString(
|
||||||
QString::fromStdString(variable->GetDefaultValue()) +
|
variable->GetDefaultValue()));
|
||||||
"\"";
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return saveAction;
|
return saveAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
static QString getLastUsedString(Variable *variable)
|
static QString formatLastUsedText(Variable *variable)
|
||||||
{
|
{
|
||||||
auto lastUsed = variable->SecondsSinceLastUse();
|
auto lastUsed = variable->GetSecondsSinceLastUse();
|
||||||
if (!lastUsed) {
|
if (!lastUsed) {
|
||||||
return obs_module_text(
|
return obs_module_text(
|
||||||
"AdvSceneSwitcher.variableTab.neverNused");
|
"AdvSceneSwitcher.variableTab.lastUsed.text.never");
|
||||||
}
|
}
|
||||||
QString fmt = obs_module_text("AdvSceneSwitcher.variableTab.lastUsed");
|
|
||||||
return fmt.arg(QString::number(*lastUsed));
|
QString text =
|
||||||
|
obs_module_text("AdvSceneSwitcher.variableTab.lastUsed.text");
|
||||||
|
return text.arg(QString::number(*lastUsed));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addVariableRow(QTableWidget *table, Variable *variable)
|
static QString formatLastChangedText(Variable *variable)
|
||||||
{
|
{
|
||||||
if (!variable) {
|
auto lastChanged = variable->GetSecondsSinceLastChange();
|
||||||
blog(LOG_INFO, "%s called with nullptr", __func__);
|
if (!lastChanged) {
|
||||||
assert(false);
|
return obs_module_text(
|
||||||
return;
|
"AdvSceneSwitcher.variableTab.lastChanged.text.none");
|
||||||
}
|
}
|
||||||
|
|
||||||
int row = table->rowCount();
|
QString text = obs_module_text(
|
||||||
table->setRowCount(row + 1);
|
"AdvSceneSwitcher.variableTab.lastChanged.text");
|
||||||
|
return text.arg(QString::number(*lastChanged));
|
||||||
int col = 0;
|
|
||||||
auto *item =
|
|
||||||
new QTableWidgetItem(QString::fromStdString(variable->Name()));
|
|
||||||
table->setItem(row, col, item);
|
|
||||||
col++;
|
|
||||||
item = new QTableWidgetItem(
|
|
||||||
QString::fromStdString(variable->Value(false)));
|
|
||||||
table->setItem(row, col, item);
|
|
||||||
col++;
|
|
||||||
item = new QTableWidgetItem(getSaveActionString(variable));
|
|
||||||
table->setItem(row, col, item);
|
|
||||||
col++;
|
|
||||||
item = new QTableWidgetItem(getLastUsedString(variable));
|
|
||||||
table->setItem(row, col, item);
|
|
||||||
table->sortByColumn(0, Qt::AscendingOrder);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void removeVariableRow(QTableWidget *table, const QString &name)
|
static QString formatLastChangedTooltip(Variable *variable)
|
||||||
{
|
{
|
||||||
for (int row = 0; row < table->rowCount(); ++row) {
|
auto lastChanged = variable->GetSecondsSinceLastChange();
|
||||||
auto item = table->item(row, 0);
|
if (!lastChanged) {
|
||||||
if (item && item->text() == name) {
|
return QString();
|
||||||
table->removeRow(row);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
table->sortByColumn(0, Qt::AscendingOrder);
|
|
||||||
|
QString tooltip = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.variableTab.lastChanged.tooltip");
|
||||||
|
return tooltip.arg(QString::number(variable->GetValueChangeCount()))
|
||||||
|
.arg(QString::fromStdString(variable->GetPreviousValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void updateVaribleStatus(QTableWidget *table)
|
static QStringList getCellLabels(Variable *variable, bool addName = true)
|
||||||
|
{
|
||||||
|
assert(variable);
|
||||||
|
|
||||||
|
auto result = QStringList();
|
||||||
|
if (addName) {
|
||||||
|
result << QString::fromStdString(variable->Name());
|
||||||
|
}
|
||||||
|
result << QString::fromStdString(variable->Value(false))
|
||||||
|
<< formatSaveActionText(variable) << formatLastUsedText(variable)
|
||||||
|
<< formatLastChangedText(variable);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateVariableStatus(QTableWidget *table)
|
||||||
{
|
{
|
||||||
for (int row = 0; row < table->rowCount(); row++) {
|
for (int row = 0; row < table->rowCount(); row++) {
|
||||||
auto item = table->item(row, 0);
|
auto item = table->item(row, 0);
|
||||||
if (!item) {
|
if (!item) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto weakVariable = GetWeakVariableByQString(item->text());
|
auto weakVariable = GetWeakVariableByQString(item->text());
|
||||||
auto variable = weakVariable.lock();
|
auto variable = weakVariable.lock();
|
||||||
if (!variable) {
|
if (!variable) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
item = table->item(row, 1);
|
|
||||||
item->setText(QString::fromStdString(variable->Value(false)));
|
UpdateItemTableRow(table, row,
|
||||||
item = table->item(row, 2);
|
getCellLabels(variable.get(), false));
|
||||||
item->setText(getSaveActionString(variable.get()));
|
|
||||||
item = table->item(row, 3);
|
|
||||||
item->setText(getLastUsedString(variable.get()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void renameVariable(QTableWidget *table, const QString &oldName,
|
static void openSettingsDialog()
|
||||||
const QString &newName)
|
|
||||||
{
|
{
|
||||||
for (int row = 0; row < table->rowCount(); row++) {
|
auto selectedRows =
|
||||||
auto item = table->item(row, 0);
|
tabWidget->Table()->selectionModel()->selectedRows();
|
||||||
if (!item) {
|
if (selectedRows.empty()) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (item->text() == oldName) {
|
|
||||||
item->setText(newName);
|
|
||||||
table->sortByColumn(0, Qt::AscendingOrder);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
blog(LOG_INFO, "%s called but entry \"%s\" not found", __func__,
|
|
||||||
oldName.toStdString().c_str());
|
|
||||||
assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void openSettingsDialogAtRow(QTableWidget *table, int row)
|
|
||||||
{
|
|
||||||
auto item = table->item(row, 0);
|
|
||||||
if (!item) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto weakVariable = GetWeakVariableByQString(item->text());
|
|
||||||
|
auto cell = tabWidget->Table()->item(selectedRows.last().row(), 0);
|
||||||
|
if (!cell) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto weakVariable = GetWeakVariableByQString(cell->text());
|
||||||
auto variable = weakVariable.lock();
|
auto variable = weakVariable.lock();
|
||||||
if (!variable) {
|
if (!variable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto oldName = variable->Name();
|
|
||||||
|
|
||||||
bool accepted =
|
auto oldName = variable->Name();
|
||||||
VariableSettingsDialog::AskForSettings(table, *variable.get());
|
bool accepted = VariableSettingsDialog::AskForSettings(
|
||||||
|
tabWidget->Table(), *variable.get());
|
||||||
if (accepted && oldName != variable->Name()) {
|
if (accepted && oldName != variable->Name()) {
|
||||||
VariableSignalManager::Instance()->Rename(
|
VariableSignalManager::Instance()->Rename(
|
||||||
QString::fromStdString(oldName),
|
QString::fromStdString(oldName),
|
||||||
@@ -162,134 +186,114 @@ static void openSettingsDialogAtRow(QTableWidget *table, int row)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::SetupVariableTab()
|
void VariableTable::Remove()
|
||||||
{
|
{
|
||||||
if (GetVariables().empty()) {
|
auto selectedRows =
|
||||||
setVariableTabVisible(ui->tabWidget, false);
|
tabWidget->Table()->selectionModel()->selectedRows();
|
||||||
} else {
|
|
||||||
ui->variablesHelp->hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const QStringList horizontalHeaders =
|
|
||||||
QStringList()
|
|
||||||
<< obs_module_text("AdvSceneSwitcher.variableTab.header.name")
|
|
||||||
<< obs_module_text("AdvSceneSwitcher.variableTab.header.value")
|
|
||||||
<< obs_module_text(
|
|
||||||
"AdvSceneSwitcher.variableTab.header.saveLoadBehavior")
|
|
||||||
<< obs_module_text(
|
|
||||||
"AdvSceneSwitcher.variableTab.header.lastUse");
|
|
||||||
|
|
||||||
auto &variables = GetVariables();
|
|
||||||
|
|
||||||
ui->variables->setColumnCount(horizontalHeaders.size());
|
|
||||||
ui->variables->horizontalHeader()->setSectionResizeMode(
|
|
||||||
QHeaderView::ResizeMode::Stretch);
|
|
||||||
ui->variables->setHorizontalHeaderLabels(horizontalHeaders);
|
|
||||||
|
|
||||||
for (const auto &var : variables) {
|
|
||||||
auto variable = std::static_pointer_cast<Variable>(var);
|
|
||||||
addVariableRow(ui->variables, variable.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
ui->variables->resizeColumnsToContents();
|
|
||||||
ui->variables->resizeRowsToContents();
|
|
||||||
|
|
||||||
QWidget::connect(
|
|
||||||
VariableSignalManager::Instance(),
|
|
||||||
&VariableSignalManager::Rename,
|
|
||||||
[this](const QString &oldName, const QString &newName) {
|
|
||||||
renameVariable(ui->variables, oldName, newName);
|
|
||||||
});
|
|
||||||
QWidget::connect(VariableSignalManager::Instance(),
|
|
||||||
&VariableSignalManager::Add, this,
|
|
||||||
[this](const QString &name) {
|
|
||||||
addVariableRow(ui->variables,
|
|
||||||
GetVariableByQString(name));
|
|
||||||
ui->variablesHelp->hide();
|
|
||||||
setVariableTabVisible(ui->tabWidget, true);
|
|
||||||
});
|
|
||||||
QWidget::connect(VariableSignalManager::Instance(),
|
|
||||||
&VariableSignalManager::Remove, this,
|
|
||||||
[this](const QString &name) {
|
|
||||||
removeVariableRow(ui->variables, name);
|
|
||||||
if (ui->variables->rowCount() == 0) {
|
|
||||||
ui->variablesHelp->show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
QWidget::connect(ui->variables, &QTableWidget::cellDoubleClicked,
|
|
||||||
[this](int row, int _) {
|
|
||||||
openSettingsDialogAtRow(ui->variables, row);
|
|
||||||
});
|
|
||||||
|
|
||||||
auto timer = new QTimer(this);
|
|
||||||
timer->setInterval(1000);
|
|
||||||
QWidget::connect(timer, &QTimer::timeout,
|
|
||||||
[this]() { updateVaribleStatus(ui->variables); });
|
|
||||||
timer->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_variableAdd_clicked()
|
|
||||||
{
|
|
||||||
auto newVariable = std::make_shared<Variable>();
|
|
||||||
auto accepted =
|
|
||||||
VariableSettingsDialog::AskForSettings(this, *newVariable);
|
|
||||||
if (!accepted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
auto lock = LockContext();
|
|
||||||
auto &variables = GetVariables();
|
|
||||||
variables.emplace_back(newVariable);
|
|
||||||
}
|
|
||||||
|
|
||||||
VariableSignalManager::Instance()->Add(
|
|
||||||
QString::fromStdString(newVariable->Name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_variableRemove_clicked()
|
|
||||||
{
|
|
||||||
auto selectedItems = ui->variables->selectedItems();
|
|
||||||
QList<int> selectedRows;
|
|
||||||
for (auto item : selectedItems) {
|
|
||||||
int row = item->row();
|
|
||||||
if (!selectedRows.contains(row)) {
|
|
||||||
selectedRows.append(row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedRows.empty()) {
|
if (selectedRows.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList names;
|
QStringList varNames;
|
||||||
for (int row : selectedRows) {
|
for (const auto &row : selectedRows) {
|
||||||
auto item = ui->variables->item(row, 0);
|
auto cell = tabWidget->Table()->item(row.row(), 0);
|
||||||
if (!item) {
|
if (!cell) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
names << item->text();
|
|
||||||
|
varNames << cell->text();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &name : names) {
|
int varNameCount = varNames.size();
|
||||||
|
if (varNameCount == 1) {
|
||||||
|
QString deleteWarning = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.variableTab.removeSingleVariablePopup.text");
|
||||||
|
if (!DisplayMessage(deleteWarning.arg(varNames.at(0)), true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QString deleteWarning = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.variableTab.removeMultipleVariablesPopup.text");
|
||||||
|
if (!DisplayMessage(deleteWarning.arg(varNameCount), true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto lock = LockContext();
|
||||||
|
RemoveItemsByName(GetVariables(), varNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &name : varNames) {
|
||||||
VariableSignalManager::Instance()->Remove(name);
|
VariableSignalManager::Instance()->Remove(name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
auto lock = LockContext();
|
|
||||||
for (const auto &name : names) {
|
VariableTable::VariableTable(QTabWidget *parent)
|
||||||
auto variable = GetVariableByQString(name);
|
: ResourceTable(
|
||||||
if (!variable) {
|
parent, obs_module_text("AdvSceneSwitcher.variableTab.help"),
|
||||||
continue;
|
obs_module_text(
|
||||||
}
|
"AdvSceneSwitcher.variableTab.variableAddButton.tooltip"),
|
||||||
|
obs_module_text(
|
||||||
auto &variables = GetVariables();
|
"AdvSceneSwitcher.variableTab.variableRemoveButton.tooltip"),
|
||||||
variables.erase(
|
QStringList()
|
||||||
std::remove_if(
|
<< obs_module_text(
|
||||||
variables.begin(), variables.end(),
|
"AdvSceneSwitcher.variableTab.name.header")
|
||||||
[variable](const std::shared_ptr<Item> &item) {
|
<< obs_module_text(
|
||||||
return item.get() == variable;
|
"AdvSceneSwitcher.variableTab.value.header")
|
||||||
}),
|
<< obs_module_text(
|
||||||
variables.end());
|
"AdvSceneSwitcher.variableTab.saveLoadBehavior.header")
|
||||||
}
|
<< obs_module_text(
|
||||||
|
"AdvSceneSwitcher.variableTab.lastUsed.header")
|
||||||
|
<< obs_module_text(
|
||||||
|
"AdvSceneSwitcher.variableTab.lastChanged.header"),
|
||||||
|
openSettingsDialog)
|
||||||
|
{
|
||||||
|
for (const auto &variable : GetVariables()) {
|
||||||
|
auto v = std::static_pointer_cast<Variable>(variable);
|
||||||
|
AddItemTableRow(Table(), getCellLabels(v.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
SetHelpVisible(GetVariables().empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setupTab(QTabWidget *tab)
|
||||||
|
{
|
||||||
|
if (GetVariables().empty()) {
|
||||||
|
setTabVisible(tab, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::connect(VariableSignalManager::Instance(),
|
||||||
|
&VariableSignalManager::Rename,
|
||||||
|
[](const QString &oldName, const QString &newName) {
|
||||||
|
RenameItemTableRow(tabWidget->Table(), oldName,
|
||||||
|
newName);
|
||||||
|
});
|
||||||
|
QWidget::connect(
|
||||||
|
VariableSignalManager::Instance(), &VariableSignalManager::Add,
|
||||||
|
[tab](const QString &name) {
|
||||||
|
AddItemTableRow(
|
||||||
|
tabWidget->Table(),
|
||||||
|
getCellLabels(GetVariableByQString(name)));
|
||||||
|
tabWidget->SetHelpVisible(false);
|
||||||
|
tabWidget->HighlightAddButton(false);
|
||||||
|
setTabVisible(tab, true);
|
||||||
|
});
|
||||||
|
QWidget::connect(VariableSignalManager::Instance(),
|
||||||
|
&VariableSignalManager::Remove,
|
||||||
|
[](const QString &name) {
|
||||||
|
RemoveItemTableRow(tabWidget->Table(), name);
|
||||||
|
if (tabWidget->Table()->rowCount() == 0) {
|
||||||
|
tabWidget->SetHelpVisible(true);
|
||||||
|
tabWidget->HighlightAddButton(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
auto timer = new QTimer(tabWidget);
|
||||||
|
timer->setInterval(1000);
|
||||||
|
QWidget::connect(timer, &QTimer::timeout,
|
||||||
|
[]() { updateVariableStatus(tabWidget->Table()); });
|
||||||
|
timer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
20
lib/variables/variable-tab.hpp
Normal file
20
lib/variables/variable-tab.hpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "resource-table.hpp"
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
class VariableTable final : public ResourceTable {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static VariableTable *Create();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void Add();
|
||||||
|
void Remove();
|
||||||
|
|
||||||
|
private:
|
||||||
|
VariableTable(QTabWidget *parent = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -13,11 +13,6 @@ static std::deque<std::shared_ptr<Item>> variables;
|
|||||||
// when resolving strings containing variables, etc.
|
// when resolving strings containing variables, etc.
|
||||||
static std::chrono::high_resolution_clock::time_point lastVariableChange{};
|
static std::chrono::high_resolution_clock::time_point lastVariableChange{};
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point GetLastVariableChangeTime()
|
|
||||||
{
|
|
||||||
return lastVariableChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
Variable::Variable() : Item()
|
Variable::Variable() : Item()
|
||||||
{
|
{
|
||||||
lastVariableChange = std::chrono::high_resolution_clock::now();
|
lastVariableChange = std::chrono::high_resolution_clock::now();
|
||||||
@@ -34,11 +29,13 @@ void Variable::Load(obs_data_t *obj)
|
|||||||
_saveAction =
|
_saveAction =
|
||||||
static_cast<SaveAction>(obs_data_get_int(obj, "saveAction"));
|
static_cast<SaveAction>(obs_data_get_int(obj, "saveAction"));
|
||||||
_defaultValue = obs_data_get_string(obj, "defaultValue");
|
_defaultValue = obs_data_get_string(obj, "defaultValue");
|
||||||
|
|
||||||
if (_saveAction == SaveAction::SAVE) {
|
if (_saveAction == SaveAction::SAVE) {
|
||||||
_value = obs_data_get_string(obj, "value");
|
SetValue(obs_data_get_string(obj, "value"));
|
||||||
} else if (_saveAction == SaveAction::SET_DEFAULT) {
|
} else if (_saveAction == SaveAction::SET_DEFAULT) {
|
||||||
_value = _defaultValue;
|
SetValue(_defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
lastVariableChange = std::chrono::high_resolution_clock::now();
|
lastVariableChange = std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,9 +43,11 @@ void Variable::Save(obs_data_t *obj) const
|
|||||||
{
|
{
|
||||||
Item::Save(obj);
|
Item::Save(obj);
|
||||||
obs_data_set_int(obj, "saveAction", static_cast<int>(_saveAction));
|
obs_data_set_int(obj, "saveAction", static_cast<int>(_saveAction));
|
||||||
|
|
||||||
if (_saveAction == SaveAction::SAVE) {
|
if (_saveAction == SaveAction::SAVE) {
|
||||||
obs_data_set_string(obj, "value", _value.c_str());
|
obs_data_set_string(obj, "value", _value.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_data_set_string(obj, "defaultValue", _defaultValue.c_str());
|
obs_data_set_string(obj, "defaultValue", _defaultValue.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,6 +56,7 @@ std::string Variable::Value(bool updateLastUsed) const
|
|||||||
if (updateLastUsed) {
|
if (updateLastUsed) {
|
||||||
UpdateLastUsed();
|
UpdateLastUsed();
|
||||||
}
|
}
|
||||||
|
|
||||||
return _value;
|
return _value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,128 +72,61 @@ std::optional<int> Variable::IntValue() const
|
|||||||
|
|
||||||
void Variable::SetValue(const std::string &value)
|
void Variable::SetValue(const std::string &value)
|
||||||
{
|
{
|
||||||
|
_previousValue = _value;
|
||||||
_value = value;
|
_value = value;
|
||||||
|
|
||||||
UpdateLastUsed();
|
UpdateLastUsed();
|
||||||
|
UpdateLastChanged();
|
||||||
lastVariableChange = std::chrono::high_resolution_clock::now();
|
lastVariableChange = std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Variable::SetValue(double value)
|
void Variable::SetValue(double value)
|
||||||
{
|
{
|
||||||
_value = ToString(value);
|
SetValue(ToString(value));
|
||||||
|
|
||||||
UpdateLastUsed();
|
|
||||||
lastVariableChange = std::chrono::high_resolution_clock::now();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<uint64_t> Variable::SecondsSinceLastUse() const
|
std::optional<uint64_t> Variable::GetSecondsSinceLastUse() const
|
||||||
{
|
{
|
||||||
if (_lastUsed.time_since_epoch().count() == 0) {
|
if (_lastUsed.time_since_epoch().count() == 0) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto now = std::chrono::high_resolution_clock::now();
|
const auto now = std::chrono::high_resolution_clock::now();
|
||||||
return std::chrono::duration_cast<std::chrono::seconds>(now - _lastUsed)
|
return std::chrono::duration_cast<std::chrono::seconds>(now - _lastUsed)
|
||||||
.count();
|
.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<uint64_t> Variable::GetSecondsSinceLastChange() const
|
||||||
|
{
|
||||||
|
if (_lastChanged.time_since_epoch().count() == 0) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto now = std::chrono::high_resolution_clock::now();
|
||||||
|
return std::chrono::duration_cast<std::chrono::seconds>(now -
|
||||||
|
_lastChanged)
|
||||||
|
.count();
|
||||||
|
}
|
||||||
|
|
||||||
void Variable::UpdateLastUsed() const
|
void Variable::UpdateLastUsed() const
|
||||||
{
|
{
|
||||||
_lastUsed = std::chrono::high_resolution_clock::now();
|
_lastUsed = std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::deque<std::shared_ptr<Item>> &GetVariables()
|
void Variable::UpdateLastChanged()
|
||||||
{
|
{
|
||||||
return variables;
|
if (_previousValue != _value) {
|
||||||
}
|
_lastChanged = std::chrono::high_resolution_clock::now();
|
||||||
|
++_valueChangeCount;
|
||||||
Variable *GetVariableByName(const std::string &name)
|
|
||||||
{
|
|
||||||
for (const auto &v : variables) {
|
|
||||||
if (v->Name() == name) {
|
|
||||||
return dynamic_cast<Variable *>(v.get());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Variable *GetVariableByQString(const QString &name)
|
|
||||||
{
|
|
||||||
return GetVariableByName(name.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::weak_ptr<Variable> GetWeakVariableByName(const std::string &name)
|
|
||||||
{
|
|
||||||
for (const auto &v : variables) {
|
|
||||||
if (v->Name() == name) {
|
|
||||||
std::weak_ptr<Variable> wp =
|
|
||||||
std::dynamic_pointer_cast<Variable>(v);
|
|
||||||
return wp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return std::weak_ptr<Variable>();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::weak_ptr<Variable> GetWeakVariableByQString(const QString &name)
|
|
||||||
{
|
|
||||||
return GetWeakVariableByName(name.toStdString());
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList GetVariablesNameList()
|
|
||||||
{
|
|
||||||
QStringList list;
|
|
||||||
for (const auto &var : variables) {
|
|
||||||
list << QString::fromStdString(var->Name());
|
|
||||||
}
|
|
||||||
list.sort();
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string GetWeakVariableName(std::weak_ptr<Variable> var_)
|
|
||||||
{
|
|
||||||
auto var = var_.lock();
|
|
||||||
if (!var) {
|
|
||||||
return obs_module_text("AdvSceneSwitcher.variable.invalid");
|
|
||||||
}
|
|
||||||
return var->Name();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveVariables(obs_data_t *obj)
|
|
||||||
{
|
|
||||||
obs_data_array_t *variablesArray = obs_data_array_create();
|
|
||||||
for (const auto &v : variables) {
|
|
||||||
obs_data_t *array_obj = obs_data_create();
|
|
||||||
v->Save(array_obj);
|
|
||||||
obs_data_array_push_back(variablesArray, array_obj);
|
|
||||||
obs_data_release(array_obj);
|
|
||||||
}
|
|
||||||
obs_data_set_array(obj, "variables", variablesArray);
|
|
||||||
obs_data_array_release(variablesArray);
|
|
||||||
}
|
|
||||||
|
|
||||||
void LoadVariables(obs_data_t *obj)
|
|
||||||
{
|
|
||||||
variables.clear();
|
|
||||||
|
|
||||||
obs_data_array_t *variablesArray = obs_data_get_array(obj, "variables");
|
|
||||||
size_t count = obs_data_array_count(variablesArray);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
|
||||||
obs_data_t *array_obj = obs_data_array_item(variablesArray, i);
|
|
||||||
auto var = Variable::Create();
|
|
||||||
variables.emplace_back(var);
|
|
||||||
variables.back()->Load(array_obj);
|
|
||||||
obs_data_release(array_obj);
|
|
||||||
}
|
|
||||||
obs_data_array_release(variablesArray);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void populateSaveActionSelection(QComboBox *list)
|
static void populateSaveActionSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
list->addItem(
|
list->addItems(
|
||||||
obs_module_text("AdvSceneSwitcher.variable.save.dontSave"));
|
{obs_module_text("AdvSceneSwitcher.variable.save.dontSave"),
|
||||||
list->addItem(obs_module_text("AdvSceneSwitcher.variable.save.save"));
|
obs_module_text("AdvSceneSwitcher.variable.save.save"),
|
||||||
list->addItem(
|
obs_module_text("AdvSceneSwitcher.variable.save.default")});
|
||||||
obs_module_text("AdvSceneSwitcher.variable.save.default"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VariableSettingsDialog::VariableSettingsDialog(QWidget *parent,
|
VariableSettingsDialog::VariableSettingsDialog(QWidget *parent,
|
||||||
@@ -220,6 +153,7 @@ VariableSettingsDialog::VariableSettingsDialog(QWidget *parent,
|
|||||||
layout->addWidget(
|
layout->addWidget(
|
||||||
new QLabel(obs_module_text("AdvSceneSwitcher.variable.name")),
|
new QLabel(obs_module_text("AdvSceneSwitcher.variable.name")),
|
||||||
row, 0);
|
row, 0);
|
||||||
|
|
||||||
QHBoxLayout *nameLayout = new QHBoxLayout;
|
QHBoxLayout *nameLayout = new QHBoxLayout;
|
||||||
nameLayout->addWidget(_name);
|
nameLayout->addWidget(_name);
|
||||||
nameLayout->addWidget(_nameHint);
|
nameLayout->addWidget(_nameHint);
|
||||||
@@ -233,13 +167,14 @@ VariableSettingsDialog::VariableSettingsDialog(QWidget *parent,
|
|||||||
layout->addWidget(
|
layout->addWidget(
|
||||||
new QLabel(obs_module_text("AdvSceneSwitcher.variable.save")),
|
new QLabel(obs_module_text("AdvSceneSwitcher.variable.save")),
|
||||||
row, 0);
|
row, 0);
|
||||||
|
|
||||||
auto saveLayout = new QVBoxLayout;
|
auto saveLayout = new QVBoxLayout;
|
||||||
saveLayout->addWidget(_save);
|
saveLayout->addWidget(_save);
|
||||||
saveLayout->addWidget(_defaultValue);
|
saveLayout->addWidget(_defaultValue);
|
||||||
saveLayout->addStretch();
|
saveLayout->addStretch();
|
||||||
|
|
||||||
layout->addLayout(saveLayout, row, 1);
|
layout->addLayout(saveLayout, row, 1);
|
||||||
++row;
|
layout->addWidget(_buttonbox, ++row, 0, 1, -1);
|
||||||
layout->addWidget(_buttonbox, row, 0, 1, -1);
|
|
||||||
layout->setSizeConstraint(QLayout::SetFixedSize);
|
layout->setSizeConstraint(QLayout::SetFixedSize);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
}
|
}
|
||||||
@@ -262,12 +197,13 @@ bool VariableSettingsDialog::AskForSettings(QWidget *parent, Variable &settings)
|
|||||||
}
|
}
|
||||||
|
|
||||||
settings._name = dialog._name->text().toStdString();
|
settings._name = dialog._name->text().toStdString();
|
||||||
settings._value = dialog._value->toPlainText().toStdString();
|
settings.SetValue(dialog._value->toPlainText().toStdString());
|
||||||
settings._defaultValue =
|
settings._defaultValue =
|
||||||
dialog._defaultValue->toPlainText().toStdString();
|
dialog._defaultValue->toPlainText().toStdString();
|
||||||
settings._saveAction =
|
settings._saveAction =
|
||||||
static_cast<Variable::SaveAction>(dialog._save->currentIndex());
|
static_cast<Variable::SaveAction>(dialog._save->currentIndex());
|
||||||
lastVariableChange = std::chrono::high_resolution_clock::now();
|
lastVariableChange = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,6 +213,7 @@ static bool AskForSettingsWrapper(QWidget *parent, Item &settings)
|
|||||||
if (VariableSettingsDialog::AskForSettings(parent, VariableSettings)) {
|
if (VariableSettingsDialog::AskForSettings(parent, VariableSettings)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,4 +277,128 @@ VariableSignalManager *VariableSignalManager::Instance()
|
|||||||
return &manager;
|
return &manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::deque<std::shared_ptr<Item>> &GetVariables()
|
||||||
|
{
|
||||||
|
return variables;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable *GetVariableByName(const std::string &name)
|
||||||
|
{
|
||||||
|
for (const auto &v : variables) {
|
||||||
|
if (v->Name() == name) {
|
||||||
|
return dynamic_cast<Variable *>(v.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variable *GetVariableByQString(const QString &name)
|
||||||
|
{
|
||||||
|
return GetVariableByName(name.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Variable> GetWeakVariableByName(const std::string &name)
|
||||||
|
{
|
||||||
|
for (const auto &v : variables) {
|
||||||
|
if (v->Name() == name) {
|
||||||
|
std::weak_ptr<Variable> wp =
|
||||||
|
std::dynamic_pointer_cast<Variable>(v);
|
||||||
|
return wp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::weak_ptr<Variable>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Variable> GetWeakVariableByQString(const QString &name)
|
||||||
|
{
|
||||||
|
return GetWeakVariableByName(name.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList GetVariablesNameList()
|
||||||
|
{
|
||||||
|
QStringList list;
|
||||||
|
|
||||||
|
for (const auto &var : variables) {
|
||||||
|
list << QString::fromStdString(var->Name());
|
||||||
|
}
|
||||||
|
|
||||||
|
list.sort();
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetWeakVariableName(std::weak_ptr<Variable> var_)
|
||||||
|
{
|
||||||
|
auto var = var_.lock();
|
||||||
|
if (!var) {
|
||||||
|
return obs_module_text("AdvSceneSwitcher.variable.invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
return var->Name();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool variableWithNameExists(const std::string &name)
|
||||||
|
{
|
||||||
|
return !!GetVariableByName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveVariables(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
obs_data_array_t *variablesArray = obs_data_array_create();
|
||||||
|
for (const auto &v : variables) {
|
||||||
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
v->Save(array_obj);
|
||||||
|
obs_data_array_push_back(variablesArray, array_obj);
|
||||||
|
obs_data_release(array_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_set_array(obj, "variables", variablesArray);
|
||||||
|
obs_data_array_release(variablesArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadVariables(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
variables.clear();
|
||||||
|
|
||||||
|
obs_data_array_t *variablesArray = obs_data_get_array(obj, "variables");
|
||||||
|
size_t count = obs_data_array_count(variablesArray);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
obs_data_t *array_obj = obs_data_array_item(variablesArray, i);
|
||||||
|
auto var = Variable::Create();
|
||||||
|
variables.emplace_back(var);
|
||||||
|
variables.back()->Load(array_obj);
|
||||||
|
obs_data_release(array_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_array_release(variablesArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImportVariables(obs_data_t *data)
|
||||||
|
{
|
||||||
|
obs_data_array_t *array = obs_data_get_array(data, "variables");
|
||||||
|
size_t count = obs_data_array_count(array);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
obs_data_t *arrayElement = obs_data_array_item(array, i);
|
||||||
|
auto var = Variable::Create();
|
||||||
|
var->Load(arrayElement);
|
||||||
|
obs_data_release(arrayElement);
|
||||||
|
|
||||||
|
if (variableWithNameExists(var->Name())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetVariables().emplace_back(var);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_array_release(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::high_resolution_clock::time_point GetLastVariableChangeTime()
|
||||||
|
{
|
||||||
|
return lastVariableChange;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -17,14 +17,6 @@ class Variable : public Item {
|
|||||||
public:
|
public:
|
||||||
Variable();
|
Variable();
|
||||||
~Variable();
|
~Variable();
|
||||||
void Load(obs_data_t *obj);
|
|
||||||
void Save(obs_data_t *obj) const;
|
|
||||||
EXPORT std::string Value(bool updateLastUsed = true) const;
|
|
||||||
EXPORT std::optional<double> DoubleValue() const;
|
|
||||||
EXPORT std::optional<int> IntValue() const;
|
|
||||||
void SetValue(const std::string &value);
|
|
||||||
void SetValue(double value);
|
|
||||||
std::string GetDefaultValue() const { return _defaultValue; }
|
|
||||||
static std::shared_ptr<Item> Create()
|
static std::shared_ptr<Item> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<Variable>();
|
return std::make_shared<Variable>();
|
||||||
@@ -35,15 +27,31 @@ public:
|
|||||||
SAVE,
|
SAVE,
|
||||||
SET_DEFAULT,
|
SET_DEFAULT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void Load(obs_data_t *obj);
|
||||||
|
void Save(obs_data_t *obj) const;
|
||||||
|
EXPORT std::string Value(bool updateLastUsed = true) const;
|
||||||
|
EXPORT std::optional<double> DoubleValue() const;
|
||||||
|
EXPORT std::optional<int> IntValue() const;
|
||||||
|
std::string GetPreviousValue() const { return _previousValue; };
|
||||||
|
std::string GetDefaultValue() const { return _defaultValue; }
|
||||||
|
void SetValue(const std::string &value);
|
||||||
|
void SetValue(double value);
|
||||||
SaveAction GetSaveAction() const { return _saveAction; }
|
SaveAction GetSaveAction() const { return _saveAction; }
|
||||||
std::optional<uint64_t> SecondsSinceLastUse() const;
|
int GetValueChangeCount() const { return _valueChangeCount; }
|
||||||
|
std::optional<uint64_t> GetSecondsSinceLastUse() const;
|
||||||
|
std::optional<uint64_t> GetSecondsSinceLastChange() const;
|
||||||
void UpdateLastUsed() const;
|
void UpdateLastUsed() const;
|
||||||
|
void UpdateLastChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SaveAction _saveAction = SaveAction::DONT_SAVE;
|
SaveAction _saveAction = SaveAction::DONT_SAVE;
|
||||||
std::string _value = "";
|
std::string _value = "";
|
||||||
|
std::string _previousValue = "";
|
||||||
std::string _defaultValue = "";
|
std::string _defaultValue = "";
|
||||||
|
int _valueChangeCount = 0;
|
||||||
mutable std::chrono::high_resolution_clock::time_point _lastUsed;
|
mutable std::chrono::high_resolution_clock::time_point _lastUsed;
|
||||||
|
mutable std::chrono::high_resolution_clock::time_point _lastChanged;
|
||||||
|
|
||||||
friend VariableSelection;
|
friend VariableSelection;
|
||||||
friend VariableSettingsDialog;
|
friend VariableSettingsDialog;
|
||||||
@@ -86,11 +94,7 @@ signals:
|
|||||||
void Remove(const QString &);
|
void Remove(const QString &);
|
||||||
};
|
};
|
||||||
|
|
||||||
void SaveVariables(obs_data_t *obj);
|
|
||||||
void LoadVariables(obs_data_t *obj);
|
|
||||||
|
|
||||||
std::deque<std::shared_ptr<Item>> &GetVariables();
|
std::deque<std::shared_ptr<Item>> &GetVariables();
|
||||||
|
|
||||||
EXPORT Variable *GetVariableByName(const std::string &name);
|
EXPORT Variable *GetVariableByName(const std::string &name);
|
||||||
EXPORT Variable *GetVariableByQString(const QString &name);
|
EXPORT Variable *GetVariableByQString(const QString &name);
|
||||||
EXPORT std::weak_ptr<Variable> GetWeakVariableByName(const std::string &name);
|
EXPORT std::weak_ptr<Variable> GetWeakVariableByName(const std::string &name);
|
||||||
@@ -98,6 +102,10 @@ EXPORT std::weak_ptr<Variable> GetWeakVariableByQString(const QString &name);
|
|||||||
std::string GetWeakVariableName(std::weak_ptr<Variable>);
|
std::string GetWeakVariableName(std::weak_ptr<Variable>);
|
||||||
EXPORT QStringList GetVariablesNameList();
|
EXPORT QStringList GetVariablesNameList();
|
||||||
|
|
||||||
|
void SaveVariables(obs_data_t *obj);
|
||||||
|
void LoadVariables(obs_data_t *obj);
|
||||||
|
void ImportVariables(obs_data_t *obj);
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point GetLastVariableChangeTime();
|
std::chrono::high_resolution_clock::time_point GetLastVariableChangeTime();
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -75,6 +75,8 @@ target_sources(
|
|||||||
macro-action-window.hpp
|
macro-action-window.hpp
|
||||||
macro-condition-audio.cpp
|
macro-condition-audio.cpp
|
||||||
macro-condition-audio.hpp
|
macro-condition-audio.hpp
|
||||||
|
macro-condition-clipboard.cpp
|
||||||
|
macro-condition-clipboard.hpp
|
||||||
macro-condition-cursor.cpp
|
macro-condition-cursor.cpp
|
||||||
macro-condition-cursor.hpp
|
macro-condition-cursor.hpp
|
||||||
macro-condition-date.cpp
|
macro-condition-date.cpp
|
||||||
@@ -158,6 +160,8 @@ target_sources(
|
|||||||
utils/scene-item-selection.hpp
|
utils/scene-item-selection.hpp
|
||||||
utils/scene-item-transform-helpers.cpp
|
utils/scene-item-transform-helpers.cpp
|
||||||
utils/scene-item-transform-helpers.hpp
|
utils/scene-item-transform-helpers.hpp
|
||||||
|
utils/source-properties-button.cpp
|
||||||
|
utils/source-properties-button.hpp
|
||||||
utils/source-settings-helpers.cpp
|
utils/source-settings-helpers.cpp
|
||||||
utils/source-settings-helpers.hpp
|
utils/source-settings-helpers.hpp
|
||||||
utils/source-setting.cpp
|
utils/source-setting.cpp
|
||||||
@@ -171,7 +175,9 @@ target_sources(
|
|||||||
utils/transition-selection.cpp
|
utils/transition-selection.cpp
|
||||||
utils/transition-selection.hpp
|
utils/transition-selection.hpp
|
||||||
utils/websocket-helpers.cpp
|
utils/websocket-helpers.cpp
|
||||||
utils/websocket-helpers.hpp)
|
utils/websocket-helpers.hpp
|
||||||
|
utils/websocket-tab.cpp
|
||||||
|
utils/websocket-tab.hpp)
|
||||||
|
|
||||||
if(OS_WINDOWS)
|
if(OS_WINDOWS)
|
||||||
target_sources(${PROJECT_NAME} PRIVATE utils/windows/windows.cpp)
|
target_sources(${PROJECT_NAME} PRIVATE utils/windows/windows.cpp)
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ static const std::map<MacroActionAudio::Action, std::string> actionTypes = {
|
|||||||
"AdvSceneSwitcher.action.audio.type.monitor"},
|
"AdvSceneSwitcher.action.audio.type.monitor"},
|
||||||
{MacroActionAudio::Action::BALANCE,
|
{MacroActionAudio::Action::BALANCE,
|
||||||
"AdvSceneSwitcher.action.audio.type.balance"},
|
"AdvSceneSwitcher.action.audio.type.balance"},
|
||||||
|
{MacroActionAudio::Action::ENABLE_ON_TRACK,
|
||||||
|
"AdvSceneSwitcher.action.audio.type.enableOnTrack"},
|
||||||
|
{MacroActionAudio::Action::DISABLE_ON_TRACK,
|
||||||
|
"AdvSceneSwitcher.action.audio.type.disableOnTrack"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::map<MacroActionAudio::FadeType, std::string> fadeTypes = {
|
static const std::map<MacroActionAudio::FadeType, std::string> fadeTypes = {
|
||||||
@@ -205,6 +209,28 @@ void MacroActionAudio::StartFade() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setMixerEnable(obs_source_t *source, const int mixerIdx,
|
||||||
|
const bool enable)
|
||||||
|
{
|
||||||
|
if (mixerIdx < 0) {
|
||||||
|
blog(LOG_INFO, "refusing to %s mixer id %d for %s",
|
||||||
|
enable ? "enable" : "disable", mixerIdx,
|
||||||
|
obs_source_get_name(source));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t mixers = obs_source_get_audio_mixers(source);
|
||||||
|
uint32_t new_mixers = mixers;
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
new_mixers |= (1 << mixerIdx);
|
||||||
|
} else {
|
||||||
|
new_mixers &= ~(1 << mixerIdx);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_set_audio_mixers(source, new_mixers);
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroActionAudio::PerformAction()
|
bool MacroActionAudio::PerformAction()
|
||||||
{
|
{
|
||||||
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||||
@@ -232,6 +258,12 @@ bool MacroActionAudio::PerformAction()
|
|||||||
case Action::BALANCE:
|
case Action::BALANCE:
|
||||||
obs_source_set_balance_value(s, _balance);
|
obs_source_set_balance_value(s, _balance);
|
||||||
break;
|
break;
|
||||||
|
case Action::ENABLE_ON_TRACK:
|
||||||
|
setMixerEnable(s, _track - 1, true);
|
||||||
|
break;
|
||||||
|
case Action::DISABLE_ON_TRACK:
|
||||||
|
setMixerEnable(s, _track - 1, false);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -263,6 +295,7 @@ bool MacroActionAudio::Save(obs_data_t *obj) const
|
|||||||
obs_data_set_int(obj, "monitor", _monitorType);
|
obs_data_set_int(obj, "monitor", _monitorType);
|
||||||
_syncOffset.Save(obj, "syncOffset");
|
_syncOffset.Save(obj, "syncOffset");
|
||||||
_balance.Save(obj, "balance");
|
_balance.Save(obj, "balance");
|
||||||
|
_track.Save(obj, "track");
|
||||||
_volume.Save(obj, "volume");
|
_volume.Save(obj, "volume");
|
||||||
_rate.Save(obj, "rate");
|
_rate.Save(obj, "rate");
|
||||||
obs_data_set_bool(obj, "fade", _fade);
|
obs_data_set_bool(obj, "fade", _fade);
|
||||||
@@ -271,7 +304,7 @@ bool MacroActionAudio::Save(obs_data_t *obj) const
|
|||||||
obs_data_set_bool(obj, "abortActiveFade", _abortActiveFade);
|
obs_data_set_bool(obj, "abortActiveFade", _abortActiveFade);
|
||||||
obs_data_set_bool(obj, "useDb", _useDb);
|
obs_data_set_bool(obj, "useDb", _useDb);
|
||||||
_volumeDB.Save(obj, "volumeDB");
|
_volumeDB.Save(obj, "volumeDB");
|
||||||
obs_data_set_int(obj, "version", 2);
|
obs_data_set_int(obj, "version", 3);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,13 +345,18 @@ bool MacroActionAudio::Load(obs_data_t *obj)
|
|||||||
_abortActiveFade = false;
|
_abortActiveFade = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obs_data_get_int(obj, "version") != 2) {
|
if (obs_data_get_int(obj, "version") < 2) {
|
||||||
_useDb = false;
|
_useDb = false;
|
||||||
_volumeDB = 0.0;
|
_volumeDB = 0.0;
|
||||||
} else {
|
} else {
|
||||||
_useDb = obs_data_get_bool(obj, "useDb");
|
_useDb = obs_data_get_bool(obj, "useDb");
|
||||||
_volumeDB.Load(obj, "volumeDB");
|
_volumeDB.Load(obj, "volumeDB");
|
||||||
}
|
}
|
||||||
|
if (obs_data_get_int(obj, "version") < 3) {
|
||||||
|
_track = 1;
|
||||||
|
} else {
|
||||||
|
_track.Load(obj, "track");
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -381,6 +419,7 @@ MacroActionAudioEdit::MacroActionAudioEdit(
|
|||||||
0., 1., "",
|
0., 1., "",
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.action.audio.balance.description"))),
|
"AdvSceneSwitcher.action.audio.balance.description"))),
|
||||||
|
_track(new VariableSpinBox),
|
||||||
_volumePercent(new VariableSpinBox),
|
_volumePercent(new VariableSpinBox),
|
||||||
_volumeDB(new VariableDoubleSpinBox),
|
_volumeDB(new VariableDoubleSpinBox),
|
||||||
_percentDBToggle(new QPushButton),
|
_percentDBToggle(new QPushButton),
|
||||||
@@ -398,6 +437,9 @@ MacroActionAudioEdit::MacroActionAudioEdit(
|
|||||||
_syncOffset->setMaximum(20000);
|
_syncOffset->setMaximum(20000);
|
||||||
_syncOffset->setSuffix("ms");
|
_syncOffset->setSuffix("ms");
|
||||||
|
|
||||||
|
_track->setMinimum(1);
|
||||||
|
_track->setMaximum(32);
|
||||||
|
|
||||||
_volumePercent->setMinimum(0);
|
_volumePercent->setMinimum(0);
|
||||||
_volumePercent->setMaximum(2000);
|
_volumePercent->setMaximum(2000);
|
||||||
_volumePercent->setSuffix("%");
|
_volumePercent->setSuffix("%");
|
||||||
@@ -433,6 +475,10 @@ MacroActionAudioEdit::MacroActionAudioEdit(
|
|||||||
this, SLOT(BalanceChanged(const NumberVariable<double> &)));
|
this, SLOT(BalanceChanged(const NumberVariable<double> &)));
|
||||||
QWidget::connect(_monitorTypes, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_monitorTypes, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(MonitorTypeChanged(int)));
|
SLOT(MonitorTypeChanged(int)));
|
||||||
|
QWidget::connect(
|
||||||
|
_track,
|
||||||
|
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||||
|
this, SLOT(TrackChanged(const NumberVariable<int> &)));
|
||||||
QWidget::connect(
|
QWidget::connect(
|
||||||
_volumePercent,
|
_volumePercent,
|
||||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||||
@@ -464,6 +510,7 @@ MacroActionAudioEdit::MacroActionAudioEdit(
|
|||||||
{"{{syncOffset}}", _syncOffset},
|
{"{{syncOffset}}", _syncOffset},
|
||||||
{"{{monitorTypes}}", _monitorTypes},
|
{"{{monitorTypes}}", _monitorTypes},
|
||||||
{"{{balance}}", _balance},
|
{"{{balance}}", _balance},
|
||||||
|
{"{{track}}", _track},
|
||||||
{"{{volume}}", _volumePercent},
|
{"{{volume}}", _volumePercent},
|
||||||
{"{{volumeDB}}", _volumeDB},
|
{"{{volumeDB}}", _volumeDB},
|
||||||
{"{{percentDBToggle}}", _percentDBToggle},
|
{"{{percentDBToggle}}", _percentDBToggle},
|
||||||
@@ -519,6 +566,10 @@ void MacroActionAudioEdit::SetWidgetVisibility()
|
|||||||
MacroActionAudio::Action::MONITOR);
|
MacroActionAudio::Action::MONITOR);
|
||||||
_balance->setVisible(_entryData->_action ==
|
_balance->setVisible(_entryData->_action ==
|
||||||
MacroActionAudio::Action::BALANCE);
|
MacroActionAudio::Action::BALANCE);
|
||||||
|
_track->setVisible(_entryData->_action ==
|
||||||
|
MacroActionAudio::Action::ENABLE_ON_TRACK ||
|
||||||
|
_entryData->_action ==
|
||||||
|
MacroActionAudio::Action::DISABLE_ON_TRACK);
|
||||||
|
|
||||||
_fadeTypeLayout->removeWidget(_fade);
|
_fadeTypeLayout->removeWidget(_fade);
|
||||||
_fadeTypeLayout->removeWidget(_fadeTypes);
|
_fadeTypeLayout->removeWidget(_fadeTypes);
|
||||||
@@ -583,6 +634,7 @@ void MacroActionAudioEdit::UpdateEntryData()
|
|||||||
_syncOffset->SetValue(_entryData->_syncOffset);
|
_syncOffset->SetValue(_entryData->_syncOffset);
|
||||||
_monitorTypes->setCurrentIndex(_entryData->_monitorType);
|
_monitorTypes->setCurrentIndex(_entryData->_monitorType);
|
||||||
_balance->SetDoubleValue(_entryData->_balance);
|
_balance->SetDoubleValue(_entryData->_balance);
|
||||||
|
_track->SetValue(_entryData->_track);
|
||||||
_volumePercent->SetValue(_entryData->_volume);
|
_volumePercent->SetValue(_entryData->_volume);
|
||||||
_volumeDB->SetValue(_entryData->_volumeDB);
|
_volumeDB->SetValue(_entryData->_volumeDB);
|
||||||
_fade->setChecked(_entryData->_fade);
|
_fade->setChecked(_entryData->_fade);
|
||||||
@@ -648,6 +700,16 @@ void MacroActionAudioEdit::BalanceChanged(const NumberVariable<double> &value)
|
|||||||
_entryData->_balance = value;
|
_entryData->_balance = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionAudioEdit::TrackChanged(const NumberVariable<int> &value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->_track = value;
|
||||||
|
}
|
||||||
|
|
||||||
void MacroActionAudioEdit::VolumeDBChanged(const NumberVariable<double> &value)
|
void MacroActionAudioEdit::VolumeDBChanged(const NumberVariable<double> &value)
|
||||||
{
|
{
|
||||||
if (_loading || !_entryData) {
|
if (_loading || !_entryData) {
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ public:
|
|||||||
SYNC_OFFSET,
|
SYNC_OFFSET,
|
||||||
MONITOR,
|
MONITOR,
|
||||||
BALANCE,
|
BALANCE,
|
||||||
|
ENABLE_ON_TRACK,
|
||||||
|
DISABLE_ON_TRACK,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class FadeType {
|
enum class FadeType {
|
||||||
@@ -46,6 +48,7 @@ public:
|
|||||||
IntVariable _syncOffset = 0;
|
IntVariable _syncOffset = 0;
|
||||||
obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE;
|
obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE;
|
||||||
DoubleVariable _balance = 0.5;
|
DoubleVariable _balance = 0.5;
|
||||||
|
IntVariable _track = 1;
|
||||||
bool _useDb = false;
|
bool _useDb = false;
|
||||||
IntVariable _volume = 0;
|
IntVariable _volume = 0;
|
||||||
DoubleVariable _volumeDB = 0.0;
|
DoubleVariable _volumeDB = 0.0;
|
||||||
@@ -91,6 +94,7 @@ private slots:
|
|||||||
void SyncOffsetChanged(const NumberVariable<int> &value);
|
void SyncOffsetChanged(const NumberVariable<int> &value);
|
||||||
void MonitorTypeChanged(int value);
|
void MonitorTypeChanged(int value);
|
||||||
void BalanceChanged(const NumberVariable<double> &value);
|
void BalanceChanged(const NumberVariable<double> &value);
|
||||||
|
void TrackChanged(const NumberVariable<int> &value);
|
||||||
void VolumeChanged(const NumberVariable<int> &value);
|
void VolumeChanged(const NumberVariable<int> &value);
|
||||||
void VolumeDBChanged(const NumberVariable<double> &value);
|
void VolumeDBChanged(const NumberVariable<double> &value);
|
||||||
void PercentDBClicked();
|
void PercentDBClicked();
|
||||||
@@ -110,6 +114,7 @@ protected:
|
|||||||
VariableSpinBox *_syncOffset;
|
VariableSpinBox *_syncOffset;
|
||||||
QComboBox *_monitorTypes;
|
QComboBox *_monitorTypes;
|
||||||
SliderSpinBox *_balance;
|
SliderSpinBox *_balance;
|
||||||
|
VariableSpinBox *_track;
|
||||||
VariableSpinBox *_volumePercent;
|
VariableSpinBox *_volumePercent;
|
||||||
VariableDoubleSpinBox *_volumeDB;
|
VariableDoubleSpinBox *_volumeDB;
|
||||||
QPushButton *_percentDBToggle;
|
QPushButton *_percentDBToggle;
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ const static std::map<MacroActionFilter::Action, std::string> actionTypes = {
|
|||||||
"AdvSceneSwitcher.action.filter.type.toggle"},
|
"AdvSceneSwitcher.action.filter.type.toggle"},
|
||||||
{MacroActionFilter::Action::SETTINGS,
|
{MacroActionFilter::Action::SETTINGS,
|
||||||
"AdvSceneSwitcher.action.filter.type.settings"},
|
"AdvSceneSwitcher.action.filter.type.settings"},
|
||||||
|
{MacroActionFilter::Action::SETTINGS_BUTTON,
|
||||||
|
"AdvSceneSwitcher.action.filter.type.pressSettingsButton"},
|
||||||
};
|
};
|
||||||
|
|
||||||
const static std::map<MacroActionFilter::SettingsInputMethod, std::string>
|
const static std::map<MacroActionFilter::SettingsInputMethod, std::string>
|
||||||
@@ -39,7 +41,7 @@ static void performActionHelper(
|
|||||||
MacroActionFilter::SettingsInputMethod settingsInputMethod,
|
MacroActionFilter::SettingsInputMethod settingsInputMethod,
|
||||||
const SourceSetting &setting, const std::string &manualSettingValue,
|
const SourceSetting &setting, const std::string &manualSettingValue,
|
||||||
const TempVariableRef &tempVar, Macro *macro,
|
const TempVariableRef &tempVar, Macro *macro,
|
||||||
const StringVariable &settingsString)
|
const StringVariable &settingsString, const SourceSettingButton &button)
|
||||||
{
|
{
|
||||||
OBSSourceAutoRelease source = obs_weak_source_get_source(filter);
|
OBSSourceAutoRelease source = obs_weak_source_get_source(filter);
|
||||||
switch (action) {
|
switch (action) {
|
||||||
@@ -74,6 +76,9 @@ static void performActionHelper(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case MacroActionFilter::Action::SETTINGS_BUTTON:
|
||||||
|
PressSourceButton(button, source);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -85,7 +90,7 @@ bool MacroActionFilter::PerformAction()
|
|||||||
for (const auto &filter : filters) {
|
for (const auto &filter : filters) {
|
||||||
performActionHelper(_action, filter, _settingsInputMethod,
|
performActionHelper(_action, filter, _settingsInputMethod,
|
||||||
_setting, _manualSettingValue, _tempVar,
|
_setting, _manualSettingValue, _tempVar,
|
||||||
GetMacro(), _settingsString);
|
GetMacro(), _settingsString, _button);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -116,6 +121,7 @@ bool MacroActionFilter::Save(obs_data_t *obj) const
|
|||||||
_manualSettingValue.Save(obj, "manualSettingValue");
|
_manualSettingValue.Save(obj, "manualSettingValue");
|
||||||
_tempVar.Save(obj);
|
_tempVar.Save(obj);
|
||||||
_settingsString.Save(obj, "settings");
|
_settingsString.Save(obj, "settings");
|
||||||
|
_button.Save(obj);
|
||||||
obs_data_set_int(obj, "version", 1);
|
obs_data_set_int(obj, "version", 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -147,6 +153,7 @@ bool MacroActionFilter::Load(obs_data_t *obj)
|
|||||||
_settingsString.Load(obj, "settings");
|
_settingsString.Load(obj, "settings");
|
||||||
_manualSettingValue.Load(obj, "manualSettingValue");
|
_manualSettingValue.Load(obj, "manualSettingValue");
|
||||||
_tempVar.Load(obj, GetMacro());
|
_tempVar.Load(obj, GetMacro());
|
||||||
|
_button.Load(obj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +214,8 @@ MacroActionFilterEdit::MacroActionFilterEdit(
|
|||||||
_filterSettings(new SourceSettingSelection(this)),
|
_filterSettings(new SourceSettingSelection(this)),
|
||||||
_settingsString(new VariableTextEdit(this)),
|
_settingsString(new VariableTextEdit(this)),
|
||||||
_refreshSettingSelection(new QPushButton(
|
_refreshSettingSelection(new QPushButton(
|
||||||
obs_module_text("AdvSceneSwitcher.action.filter.refresh")))
|
obs_module_text("AdvSceneSwitcher.action.filter.refresh"))),
|
||||||
|
_settingsButtons(new QComboBox())
|
||||||
{
|
{
|
||||||
_filters->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
_filters->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||||
|
|
||||||
@@ -245,10 +253,10 @@ MacroActionFilterEdit::MacroActionFilterEdit(
|
|||||||
SLOT(SelectionChanged(const SourceSetting &)));
|
SLOT(SelectionChanged(const SourceSetting &)));
|
||||||
QWidget::connect(_refreshSettingSelection, SIGNAL(clicked()), this,
|
QWidget::connect(_refreshSettingSelection, SIGNAL(clicked()), this,
|
||||||
SLOT(RefreshVariableSourceSelectionValue()));
|
SLOT(RefreshVariableSourceSelectionValue()));
|
||||||
|
QWidget::connect(_settingsButtons, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(ButtonChanged(int)));
|
||||||
|
|
||||||
auto entrylayout = new QHBoxLayout;
|
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
|
||||||
{"{{sources}}", _sources},
|
{"{{sources}}", _sources},
|
||||||
{"{{filters}}", _filters},
|
{"{{filters}}", _filters},
|
||||||
{"{{actions}}", _actions},
|
{"{{actions}}", _actions},
|
||||||
@@ -256,8 +264,10 @@ MacroActionFilterEdit::MacroActionFilterEdit(
|
|||||||
{"{{settingsInputMethod}}", _settingsInputMethods},
|
{"{{settingsInputMethod}}", _settingsInputMethods},
|
||||||
{"{{settingValue}}", _manualSettingValue},
|
{"{{settingValue}}", _manualSettingValue},
|
||||||
{"{{tempVar}}", _tempVars},
|
{"{{tempVar}}", _tempVars},
|
||||||
{"{{refresh}}", _refreshSettingSelection}};
|
{"{{refresh}}", _refreshSettingSelection},
|
||||||
|
{"{{settingsButtons}}", _settingsButtons}};
|
||||||
|
|
||||||
|
auto entrylayout = new QHBoxLayout;
|
||||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.filter.entry"),
|
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.filter.entry"),
|
||||||
entrylayout, widgetPlaceholders);
|
entrylayout, widgetPlaceholders);
|
||||||
_settingsLayout->setContentsMargins(0, 0, 0, 0);
|
_settingsLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
@@ -294,12 +304,16 @@ void MacroActionFilterEdit::UpdateEntryData()
|
|||||||
_settingsString->setPlainText(_entryData->_settingsString);
|
_settingsString->setPlainText(_entryData->_settingsString);
|
||||||
const auto filters =
|
const auto filters =
|
||||||
_entryData->_filter.GetFilters(_entryData->_source);
|
_entryData->_filter.GetFilters(_entryData->_source);
|
||||||
_filterSettings->SetSource(filters.empty() ? nullptr : filters.at(0));
|
OBSWeakSource firstFilter = filters.empty() ? nullptr : filters.at(0);
|
||||||
|
_filterSettings->SetSource(firstFilter);
|
||||||
_filterSettings->SetSetting(_entryData->_setting);
|
_filterSettings->SetSetting(_entryData->_setting);
|
||||||
_settingsInputMethods->setCurrentIndex(_settingsInputMethods->findData(
|
_settingsInputMethods->setCurrentIndex(_settingsInputMethods->findData(
|
||||||
static_cast<int>(_entryData->_settingsInputMethod)));
|
static_cast<int>(_entryData->_settingsInputMethod)));
|
||||||
_tempVars->SetVariable(_entryData->_tempVar);
|
_tempVars->SetVariable(_entryData->_tempVar);
|
||||||
_manualSettingValue->setPlainText(_entryData->_manualSettingValue);
|
_manualSettingValue->setPlainText(_entryData->_manualSettingValue);
|
||||||
|
PopulateSourceButtonSelection(_settingsButtons, firstFilter);
|
||||||
|
_settingsButtons->setCurrentText(
|
||||||
|
QString::fromStdString(_entryData->_button.ToString()));
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,7 +339,9 @@ void MacroActionFilterEdit::FilterChanged(const FilterSelection &filter)
|
|||||||
}
|
}
|
||||||
const auto filters =
|
const auto filters =
|
||||||
_entryData->_filter.GetFilters(_entryData->_source);
|
_entryData->_filter.GetFilters(_entryData->_source);
|
||||||
_filterSettings->SetSource(filters.empty() ? nullptr : filters.at(0));
|
OBSWeakSource firstFilter = filters.empty() ? nullptr : filters.at(0);
|
||||||
|
_filterSettings->SetSource(firstFilter);
|
||||||
|
PopulateSourceButtonSelection(_settingsButtons, firstFilter);
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
emit HeaderInfoChanged(
|
emit HeaderInfoChanged(
|
||||||
QString::fromStdString(_entryData->GetShortDesc()));
|
QString::fromStdString(_entryData->GetShortDesc()));
|
||||||
@@ -441,6 +457,17 @@ void MacroActionFilterEdit::RefreshVariableSourceSelectionValue()
|
|||||||
_filterSettings->SetSource(filters.empty() ? nullptr : filters.at(0));
|
_filterSettings->SetSource(filters.empty() ? nullptr : filters.at(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionFilterEdit::ButtonChanged(int idx)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->_button = qvariant_cast<SourceSettingButton>(
|
||||||
|
_settingsButtons->itemData(idx));
|
||||||
|
}
|
||||||
|
|
||||||
void MacroActionFilterEdit::SetWidgetVisibility()
|
void MacroActionFilterEdit::SetWidgetVisibility()
|
||||||
{
|
{
|
||||||
SetLayoutVisible(_settingsLayout,
|
SetLayoutVisible(_settingsLayout,
|
||||||
@@ -479,6 +506,9 @@ void MacroActionFilterEdit::SetWidgetVisibility()
|
|||||||
SourceSelection::Type::VARIABLE ||
|
SourceSelection::Type::VARIABLE ||
|
||||||
_entryData->_filter.GetType() ==
|
_entryData->_filter.GetType() ==
|
||||||
FilterSelection::Type::VARIABLE));
|
FilterSelection::Type::VARIABLE));
|
||||||
|
_settingsButtons->setVisible(
|
||||||
|
_entryData->_action ==
|
||||||
|
MacroActionFilter::Action::SETTINGS_BUTTON);
|
||||||
|
|
||||||
adjustSize();
|
adjustSize();
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "variable-text-edit.hpp"
|
#include "variable-text-edit.hpp"
|
||||||
#include "source-selection.hpp"
|
#include "source-selection.hpp"
|
||||||
#include "filter-selection.hpp"
|
#include "filter-selection.hpp"
|
||||||
|
#include "source-properties-button.hpp"
|
||||||
#include "source-setting.hpp"
|
#include "source-setting.hpp"
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
@@ -29,6 +30,7 @@ public:
|
|||||||
DISABLE,
|
DISABLE,
|
||||||
TOGGLE,
|
TOGGLE,
|
||||||
SETTINGS,
|
SETTINGS,
|
||||||
|
SETTINGS_BUTTON,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class SettingsInputMethod {
|
enum class SettingsInputMethod {
|
||||||
@@ -46,6 +48,7 @@ public:
|
|||||||
TempVariableRef _tempVar;
|
TempVariableRef _tempVar;
|
||||||
StringVariable _manualSettingValue = "";
|
StringVariable _manualSettingValue = "";
|
||||||
SourceSetting _setting;
|
SourceSetting _setting;
|
||||||
|
SourceSettingButton _button;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
@@ -79,10 +82,14 @@ private slots:
|
|||||||
void SelectionChanged(const SourceSetting &);
|
void SelectionChanged(const SourceSetting &);
|
||||||
void ManualSettingsValueChanged();
|
void ManualSettingsValueChanged();
|
||||||
void RefreshVariableSourceSelectionValue();
|
void RefreshVariableSourceSelectionValue();
|
||||||
|
void ButtonChanged(int idx);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
|
void SetWidgetVisibility();
|
||||||
|
|
||||||
SourceSelectionWidget *_sources;
|
SourceSelectionWidget *_sources;
|
||||||
FilterSelectionWidget *_filters;
|
FilterSelectionWidget *_filters;
|
||||||
QComboBox *_actions;
|
QComboBox *_actions;
|
||||||
@@ -94,11 +101,9 @@ protected:
|
|||||||
SourceSettingSelection *_filterSettings;
|
SourceSettingSelection *_filterSettings;
|
||||||
VariableTextEdit *_settingsString;
|
VariableTextEdit *_settingsString;
|
||||||
QPushButton *_refreshSettingSelection;
|
QPushButton *_refreshSettingSelection;
|
||||||
|
QComboBox *_settingsButtons;
|
||||||
|
|
||||||
std::shared_ptr<MacroActionFilter> _entryData;
|
std::shared_ptr<MacroActionFilter> _entryData;
|
||||||
|
|
||||||
private:
|
|
||||||
void SetWidgetVisibility();
|
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "macro-action-run.hpp"
|
#include "macro-action-run.hpp"
|
||||||
#include "layout-helpers.hpp"
|
#include "layout-helpers.hpp"
|
||||||
|
#include "ui-helpers.hpp"
|
||||||
|
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
@@ -16,6 +17,8 @@ bool MacroActionRun::PerformAction()
|
|||||||
{
|
{
|
||||||
if (_wait) {
|
if (_wait) {
|
||||||
_procConfig.StartProcessAndWait(_timeout.Milliseconds());
|
_procConfig.StartProcessAndWait(_timeout.Milliseconds());
|
||||||
|
SetTempVarValues();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,6 +31,7 @@ bool MacroActionRun::PerformAction()
|
|||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
||||||
QString::fromStdString(_procConfig.Path())));
|
QString::fromStdString(_procConfig.Path())));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,6 +40,45 @@ void MacroActionRun::LogAction() const
|
|||||||
ablog(LOG_INFO, "run \"%s\"", _procConfig.UnresolvedPath().c_str());
|
ablog(LOG_INFO, "run \"%s\"", _procConfig.UnresolvedPath().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionRun::SetupTempVars()
|
||||||
|
{
|
||||||
|
MacroAction::SetupTempVars();
|
||||||
|
|
||||||
|
AddTempvar(
|
||||||
|
"process.id",
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.run.process.id"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.run.process.id.description"));
|
||||||
|
AddTempvar(
|
||||||
|
"process.exitCode",
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.run.process.exitCode"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.run.process.exitCode.description"));
|
||||||
|
AddTempvar(
|
||||||
|
"process.stream.output",
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.run.process.stream.output"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.run.process.stream.output.description"));
|
||||||
|
AddTempvar(
|
||||||
|
"process.stream.error",
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.run.process.stream.error"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.run.process.stream.error.description"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionRun::SetTempVarValues()
|
||||||
|
{
|
||||||
|
SetTempVarValue("process.id", _procConfig.GetProcessId());
|
||||||
|
SetTempVarValue("process.exitCode", _procConfig.GetProcessExitCode());
|
||||||
|
SetTempVarValue("process.stream.output",
|
||||||
|
_procConfig.GetProcessOutputStream());
|
||||||
|
SetTempVarValue("process.stream.error",
|
||||||
|
_procConfig.GetProcessErrorStream());
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroActionRun::Save(obs_data_t *obj) const
|
bool MacroActionRun::Save(obs_data_t *obj) const
|
||||||
{
|
{
|
||||||
MacroAction::Save(obj);
|
MacroAction::Save(obj);
|
||||||
@@ -86,8 +129,18 @@ MacroActionRunEdit::MacroActionRunEdit(
|
|||||||
_procConfig(new ProcessConfigEdit(this)),
|
_procConfig(new ProcessConfigEdit(this)),
|
||||||
_waitLayout(new QHBoxLayout()),
|
_waitLayout(new QHBoxLayout()),
|
||||||
_wait(new QCheckBox()),
|
_wait(new QCheckBox()),
|
||||||
_timeout(new DurationSelection(this, true, 0.1))
|
_timeout(new DurationSelection(this, true, 0.1)),
|
||||||
|
_waitHelp(new QLabel())
|
||||||
{
|
{
|
||||||
|
QString helpIconPath = GetThemeTypeName() == "Light"
|
||||||
|
? ":/res/images/help.svg"
|
||||||
|
: ":/res/images/help_light.svg";
|
||||||
|
QIcon helpIcon(helpIconPath);
|
||||||
|
_waitHelp->setPixmap(helpIcon.pixmap(QSize(16, 16)));
|
||||||
|
_waitHelp->hide();
|
||||||
|
_waitHelp->setToolTip(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.run.wait.help.tooltip"));
|
||||||
|
|
||||||
QWidget::connect(_procConfig,
|
QWidget::connect(_procConfig,
|
||||||
SIGNAL(ConfigChanged(const ProcessConfig &)), this,
|
SIGNAL(ConfigChanged(const ProcessConfig &)), this,
|
||||||
SLOT(ProcessConfigChanged(const ProcessConfig &)));
|
SLOT(ProcessConfigChanged(const ProcessConfig &)));
|
||||||
@@ -98,9 +151,11 @@ MacroActionRunEdit::MacroActionRunEdit(
|
|||||||
QWidget::connect(_timeout, SIGNAL(DurationChanged(const Duration &)),
|
QWidget::connect(_timeout, SIGNAL(DurationChanged(const Duration &)),
|
||||||
this, SLOT(TimeoutChanged(const Duration &)));
|
this, SLOT(TimeoutChanged(const Duration &)));
|
||||||
|
|
||||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.run.entry.wait"),
|
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.run.wait.entry"),
|
||||||
_waitLayout,
|
_waitLayout,
|
||||||
{{"{{wait}}", _wait}, {"{{timeout}}", _timeout}});
|
{{"{{wait}}", _wait},
|
||||||
|
{"{{timeout}}", _timeout},
|
||||||
|
{"{{waitHelp}}", _waitHelp}});
|
||||||
SetLayoutVisible(_waitLayout, false);
|
SetLayoutVisible(_waitLayout, false);
|
||||||
|
|
||||||
auto layout = new QVBoxLayout;
|
auto layout = new QVBoxLayout;
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ public:
|
|||||||
Duration _timeout = 1;
|
Duration _timeout = 1;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void SetupTempVars();
|
||||||
|
void SetTempVarValues();
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const std::string id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
@@ -57,6 +60,7 @@ private:
|
|||||||
QHBoxLayout *_waitLayout;
|
QHBoxLayout *_waitLayout;
|
||||||
QCheckBox *_wait;
|
QCheckBox *_wait;
|
||||||
DurationSelection *_timeout;
|
DurationSelection *_timeout;
|
||||||
|
QLabel *_waitHelp;
|
||||||
|
|
||||||
std::shared_ptr<MacroActionRun> _entryData;
|
std::shared_ptr<MacroActionRun> _entryData;
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public:
|
|||||||
void LogAction() const;
|
void LogAction() const;
|
||||||
bool Save(obs_data_t *obj) const;
|
bool Save(obs_data_t *obj) const;
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
bool PostLoad() override;
|
bool PostLoad();
|
||||||
std::string GetId() const { return id; };
|
std::string GetId() const { return id; };
|
||||||
MacroRef GetNextMacro(bool advance = true);
|
MacroRef GetNextMacro(bool advance = true);
|
||||||
static std::shared_ptr<MacroAction> Create(Macro *m);
|
static std::shared_ptr<MacroAction> Create(Macro *m);
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
|
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(advss::SourceSettingButton);
|
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
const std::string MacroActionSource::id = "source";
|
const std::string MacroActionSource::id = "source";
|
||||||
@@ -79,38 +77,6 @@ const static std::map<MacroActionSource::SettingsInputMethod, std::string>
|
|||||||
"AdvSceneSwitcher.action.source.inputMethod.json"},
|
"AdvSceneSwitcher.action.source.inputMethod.json"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<SourceSettingButton> getSourceButtons(OBSWeakSource source)
|
|
||||||
{
|
|
||||||
auto s = obs_weak_source_get_source(source);
|
|
||||||
std::vector<SourceSettingButton> buttons;
|
|
||||||
obs_properties_t *sourceProperties = obs_source_properties(s);
|
|
||||||
auto it = obs_properties_first(sourceProperties);
|
|
||||||
do {
|
|
||||||
if (!it || obs_property_get_type(it) != OBS_PROPERTY_BUTTON) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
SourceSettingButton button = {obs_property_name(it),
|
|
||||||
obs_property_description(it)};
|
|
||||||
buttons.emplace_back(button);
|
|
||||||
} while (obs_property_next(&it));
|
|
||||||
obs_source_release(s);
|
|
||||||
obs_properties_destroy(sourceProperties);
|
|
||||||
return buttons;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void pressSourceButton(const SourceSettingButton &button,
|
|
||||||
obs_source_t *source)
|
|
||||||
{
|
|
||||||
obs_properties_t *sourceProperties = obs_source_properties(source);
|
|
||||||
obs_property_t *property =
|
|
||||||
obs_properties_get(sourceProperties, button.id.c_str());
|
|
||||||
if (!obs_property_button_clicked(property, source)) {
|
|
||||||
blog(LOG_WARNING, "Failed to press settings button '%s' for %s",
|
|
||||||
button.id.c_str(), obs_source_get_name(source));
|
|
||||||
}
|
|
||||||
obs_properties_destroy(sourceProperties);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void refreshSourceSettings(obs_source_t *s)
|
static void refreshSourceSettings(obs_source_t *s)
|
||||||
{
|
{
|
||||||
if (!s) {
|
if (!s) {
|
||||||
@@ -174,7 +140,7 @@ bool MacroActionSource::PerformAction()
|
|||||||
refreshSourceSettings(s);
|
refreshSourceSettings(s);
|
||||||
break;
|
break;
|
||||||
case Action::SETTINGS_BUTTON:
|
case Action::SETTINGS_BUTTON:
|
||||||
pressSourceButton(_button, s);
|
PressSourceButton(_button, s);
|
||||||
break;
|
break;
|
||||||
case Action::DEINTERLACE_MODE:
|
case Action::DEINTERLACE_MODE:
|
||||||
obs_source_set_deinterlace_mode(s, _deinterlaceMode);
|
obs_source_set_deinterlace_mode(s, _deinterlaceMode);
|
||||||
@@ -297,23 +263,6 @@ static inline void populateActionSelection(QComboBox *list)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void populateSourceButtonSelection(QComboBox *list,
|
|
||||||
OBSWeakSource source)
|
|
||||||
{
|
|
||||||
list->clear();
|
|
||||||
auto buttons = getSourceButtons(source);
|
|
||||||
if (buttons.empty()) {
|
|
||||||
list->addItem(obs_module_text(
|
|
||||||
"AdvSceneSwitcher.action.source.noSettingsButtons"));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &button : buttons) {
|
|
||||||
QVariant value;
|
|
||||||
value.setValue(button);
|
|
||||||
list->addItem(QString::fromStdString(button.ToString()), value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void populateDeinterlaceModeSelection(QComboBox *list)
|
static inline void populateDeinterlaceModeSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
list->clear();
|
list->clear();
|
||||||
@@ -445,7 +394,7 @@ void MacroActionSourceEdit::UpdateEntryData()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
populateSourceButtonSelection(_settingsButtons,
|
PopulateSourceButtonSelection(_settingsButtons,
|
||||||
_entryData->_source.GetSource());
|
_entryData->_source.GetSource());
|
||||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||||
_sources->SetSource(_entryData->_source);
|
_sources->SetSource(_entryData->_source);
|
||||||
@@ -476,7 +425,7 @@ void MacroActionSourceEdit::SourceChanged(const SourceSelection &source)
|
|||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->_source = source;
|
_entryData->_source = source;
|
||||||
}
|
}
|
||||||
populateSourceButtonSelection(_settingsButtons,
|
PopulateSourceButtonSelection(_settingsButtons,
|
||||||
_entryData->_source.GetSource());
|
_entryData->_source.GetSource());
|
||||||
_sourceSettings->SetSource(_entryData->_source.GetSource());
|
_sourceSettings->SetSource(_entryData->_source.GetSource());
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
@@ -672,31 +621,4 @@ void MacroActionSourceEdit::SetWidgetVisibility()
|
|||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SourceSettingButton::Save(obs_data_t *obj) const
|
|
||||||
{
|
|
||||||
auto data = obs_data_create();
|
|
||||||
obs_data_set_string(data, "id", id.c_str());
|
|
||||||
obs_data_set_string(data, "description", description.c_str());
|
|
||||||
obs_data_set_obj(obj, "sourceSettingButton", data);
|
|
||||||
obs_data_release(data);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SourceSettingButton::Load(obs_data_t *obj)
|
|
||||||
{
|
|
||||||
auto data = obs_data_get_obj(obj, "sourceSettingButton");
|
|
||||||
id = obs_data_get_string(data, "id");
|
|
||||||
description = obs_data_get_string(data, "description");
|
|
||||||
obs_data_release(data);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string SourceSettingButton::ToString() const
|
|
||||||
{
|
|
||||||
if (id.empty()) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return "[" + id + "] " + description;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "macro-action-edit.hpp"
|
#include "macro-action-edit.hpp"
|
||||||
#include "variable-text-edit.hpp"
|
#include "variable-text-edit.hpp"
|
||||||
|
#include "source-properties-button.hpp"
|
||||||
#include "source-selection.hpp"
|
#include "source-selection.hpp"
|
||||||
#include "source-setting.hpp"
|
#include "source-setting.hpp"
|
||||||
|
|
||||||
@@ -11,15 +12,6 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
struct SourceSettingButton {
|
|
||||||
bool Save(obs_data_t *obj) const;
|
|
||||||
bool Load(obs_data_t *obj);
|
|
||||||
std::string ToString() const;
|
|
||||||
|
|
||||||
std::string id = "";
|
|
||||||
std::string description = "";
|
|
||||||
};
|
|
||||||
|
|
||||||
class MacroActionSource : public MacroAction {
|
class MacroActionSource : public MacroAction {
|
||||||
public:
|
public:
|
||||||
MacroActionSource(Macro *m) : MacroAction(m) {}
|
MacroActionSource(Macro *m) : MacroAction(m) {}
|
||||||
@@ -103,7 +95,9 @@ private slots:
|
|||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
|
void SetWidgetVisibility();
|
||||||
|
|
||||||
SourceSelectionWidget *_sources;
|
SourceSelectionWidget *_sources;
|
||||||
QComboBox *_actions;
|
QComboBox *_actions;
|
||||||
QComboBox *_settingsButtons;
|
QComboBox *_settingsButtons;
|
||||||
@@ -120,9 +114,6 @@ protected:
|
|||||||
QPushButton *_refreshSettingSelection;
|
QPushButton *_refreshSettingSelection;
|
||||||
|
|
||||||
std::shared_ptr<MacroActionSource> _entryData;
|
std::shared_ptr<MacroActionSource> _entryData;
|
||||||
|
|
||||||
private:
|
|
||||||
void SetWidgetVisibility();
|
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
#include "layout-helpers.hpp"
|
#include "layout-helpers.hpp"
|
||||||
#include "ui-helpers.hpp"
|
#include "ui-helpers.hpp"
|
||||||
|
|
||||||
|
#include <obs-frontend-api.h>
|
||||||
|
#include <util/config-file.h>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
const std::string MacroActionSystray::id = "systray_notification";
|
const std::string MacroActionSystray::id = "systray_notification";
|
||||||
@@ -72,7 +75,9 @@ MacroActionSystrayEdit::MacroActionSystrayEdit(
|
|||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
_message(new VariableLineEdit(this)),
|
_message(new VariableLineEdit(this)),
|
||||||
_title(new VariableLineEdit(this)),
|
_title(new VariableLineEdit(this)),
|
||||||
_iconPath(new FileSelection())
|
_iconPath(new FileSelection()),
|
||||||
|
_trayDisableWarning(
|
||||||
|
new QLabel("AdvSceneSwitcher.action.systray.disabled"))
|
||||||
{
|
{
|
||||||
_iconPath->setToolTip(
|
_iconPath->setToolTip(
|
||||||
obs_module_text("AdvSceneSwitcher.action.systray.iconHint"));
|
obs_module_text("AdvSceneSwitcher.action.systray.iconHint"));
|
||||||
@@ -85,25 +90,35 @@ MacroActionSystrayEdit::MacroActionSystrayEdit(
|
|||||||
SLOT(IconPathChanged(const QString &)));
|
SLOT(IconPathChanged(const QString &)));
|
||||||
|
|
||||||
auto layout = new QGridLayout();
|
auto layout = new QGridLayout();
|
||||||
|
int row = 0;
|
||||||
layout->addWidget(new QLabel(obs_module_text(
|
layout->addWidget(new QLabel(obs_module_text(
|
||||||
"AdvSceneSwitcher.action.systray.title")),
|
"AdvSceneSwitcher.action.systray.title")),
|
||||||
0, 0);
|
row, 0);
|
||||||
layout->addWidget(_title, 0, 1);
|
layout->addWidget(_title, row++, 1);
|
||||||
layout->addWidget(new QLabel(obs_module_text(
|
layout->addWidget(new QLabel(obs_module_text(
|
||||||
"AdvSceneSwitcher.action.systray.message")),
|
"AdvSceneSwitcher.action.systray.message")),
|
||||||
1, 0);
|
row, 0);
|
||||||
layout->addWidget(_message, 1, 1);
|
layout->addWidget(_message, row++, 1);
|
||||||
layout->addWidget(new QLabel(obs_module_text(
|
layout->addWidget(new QLabel(obs_module_text(
|
||||||
"AdvSceneSwitcher.action.systray.icon")),
|
"AdvSceneSwitcher.action.systray.icon")),
|
||||||
2, 0);
|
row, 0);
|
||||||
layout->addWidget(_iconPath, 2, 1);
|
layout->addWidget(_iconPath, row++, 1);
|
||||||
setLayout(layout);
|
|
||||||
|
auto mainlayout = new QVBoxLayout();
|
||||||
|
mainlayout->addLayout(layout);
|
||||||
|
mainlayout->addWidget(_trayDisableWarning);
|
||||||
|
setLayout(mainlayout);
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
_message->setText(_entryData->_message);
|
_message->setText(_entryData->_message);
|
||||||
_title->setText(_entryData->_title);
|
_title->setText(_entryData->_title);
|
||||||
_iconPath->SetPath(_entryData->_iconPath);
|
_iconPath->SetPath(_entryData->_iconPath);
|
||||||
_loading = false;
|
_loading = false;
|
||||||
|
|
||||||
|
CheckIfTrayIsDisabled();
|
||||||
|
QWidget::connect(&_checkTrayDisableTimer, SIGNAL(timeout()), this,
|
||||||
|
SLOT(CheckIfTrayIsDisabled()));
|
||||||
|
_checkTrayDisableTimer.start(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionSystrayEdit::TitleChanged()
|
void MacroActionSystrayEdit::TitleChanged()
|
||||||
@@ -126,6 +141,19 @@ void MacroActionSystrayEdit::IconPathChanged(const QString &text)
|
|||||||
_entryData->_iconPath = text.toStdString();
|
_entryData->_iconPath = text.toStdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionSystrayEdit::CheckIfTrayIsDisabled()
|
||||||
|
{
|
||||||
|
auto config = obs_frontend_get_global_config();
|
||||||
|
if (!config) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_trayDisableWarning->setVisible(
|
||||||
|
!config_get_bool(config, "BasicWindow", "SysTrayEnabled"));
|
||||||
|
adjustSize();
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
void MacroActionSystrayEdit::MessageChanged()
|
void MacroActionSystrayEdit::MessageChanged()
|
||||||
{
|
{
|
||||||
if (_loading || !_entryData) {
|
if (_loading || !_entryData) {
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ private slots:
|
|||||||
void MessageChanged();
|
void MessageChanged();
|
||||||
void TitleChanged();
|
void TitleChanged();
|
||||||
void IconPathChanged(const QString &text);
|
void IconPathChanged(const QString &text);
|
||||||
|
void CheckIfTrayIsDisabled();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<MacroActionSystray> _entryData;
|
std::shared_ptr<MacroActionSystray> _entryData;
|
||||||
@@ -58,6 +59,9 @@ private:
|
|||||||
VariableLineEdit *_message;
|
VariableLineEdit *_message;
|
||||||
VariableLineEdit *_title;
|
VariableLineEdit *_title;
|
||||||
FileSelection *_iconPath;
|
FileSelection *_iconPath;
|
||||||
|
QLabel *_trayDisableWarning;
|
||||||
|
|
||||||
|
QTimer _checkTrayDisableTimer;
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ MacroActionWebsocketEdit::MacroActionWebsocketEdit(
|
|||||||
_apiType(new QComboBox(this)),
|
_apiType(new QComboBox(this)),
|
||||||
_messageType(new QComboBox(this)),
|
_messageType(new QComboBox(this)),
|
||||||
_message(new VariableTextEdit(this)),
|
_message(new VariableTextEdit(this)),
|
||||||
_connection(new ConnectionSelection(this)),
|
_connection(new WSConnectionSelection(this)),
|
||||||
_editLayout(new QHBoxLayout()),
|
_editLayout(new QHBoxLayout()),
|
||||||
_settingsConflict(new QLabel())
|
_settingsConflict(new QLabel())
|
||||||
{
|
{
|
||||||
@@ -307,9 +307,32 @@ void MacroActionWebsocketEdit::APITypeChanged(int index)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
{
|
||||||
_entryData->_api = static_cast<MacroActionWebsocket::API>(index);
|
auto lock = LockContext();
|
||||||
|
_entryData->_api =
|
||||||
|
static_cast<MacroActionWebsocket::API>(index);
|
||||||
|
}
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
|
|
||||||
|
// Set example OBS websocket message if the default message or an empty
|
||||||
|
// message was entered as neither of those are valid OBS websocket
|
||||||
|
// messages
|
||||||
|
if ((std::string(_entryData->_message).empty() ||
|
||||||
|
std::string(_entryData->_message) ==
|
||||||
|
obs_module_text("AdvSceneSwitcher.enterText")) &&
|
||||||
|
_entryData->_api == MacroActionWebsocket::API::OBS_WEBSOCKET) {
|
||||||
|
static constexpr std::string_view example =
|
||||||
|
"{\n"
|
||||||
|
" \"d\": {\n"
|
||||||
|
" \"requestData\" : {},\n"
|
||||||
|
" \"requestId\": \"someUniqueIdHere\",\n"
|
||||||
|
" \"requestType\" : \"StartRecord\"\n"
|
||||||
|
" },\n"
|
||||||
|
" \"op\": 6\n"
|
||||||
|
"}";
|
||||||
|
_message->setPlainText(QString(example.data()));
|
||||||
|
}
|
||||||
|
|
||||||
emit HeaderInfoChanged(
|
emit HeaderInfoChanged(
|
||||||
QString::fromStdString(_entryData->GetShortDesc()));
|
QString::fromStdString(_entryData->GetShortDesc()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public:
|
|||||||
API _api = API::SCENE_SWITCHER;
|
API _api = API::SCENE_SWITCHER;
|
||||||
MessageType _type = MessageType::REQUEST;
|
MessageType _type = MessageType::REQUEST;
|
||||||
StringVariable _message = obs_module_text("AdvSceneSwitcher.enterText");
|
StringVariable _message = obs_module_text("AdvSceneSwitcher.enterText");
|
||||||
std::weak_ptr<Connection> _connection;
|
std::weak_ptr<WSConnection> _connection;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SendRequest(const std::string &msg);
|
void SendRequest(const std::string &msg);
|
||||||
@@ -84,7 +84,7 @@ private:
|
|||||||
QComboBox *_apiType;
|
QComboBox *_apiType;
|
||||||
QComboBox *_messageType;
|
QComboBox *_messageType;
|
||||||
VariableTextEdit *_message;
|
VariableTextEdit *_message;
|
||||||
ConnectionSelection *_connection;
|
WSConnectionSelection *_connection;
|
||||||
QHBoxLayout *_editLayout;
|
QHBoxLayout *_editLayout;
|
||||||
QLabel *_settingsConflict;
|
QLabel *_settingsConflict;
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,21 @@ bool MacroConditionAudio::CheckOutputCondition()
|
|||||||
OBSSourceAutoRelease source =
|
OBSSourceAutoRelease source =
|
||||||
obs_weak_source_get_source(_audioSource.GetSource());
|
obs_weak_source_get_source(_audioSource.GetSource());
|
||||||
|
|
||||||
double curVolume = _useDb ? _peak : DecibelToPercent(_peak) * 100;
|
// OBS might very rarely not update _peak quickly enough when very low
|
||||||
|
// intervals are configured on the General tab.
|
||||||
|
// In that case _peak might be set to negative infinity still, which
|
||||||
|
// will result in unexpected behavior, so we use the previously valid
|
||||||
|
// peak value instead.
|
||||||
|
float peak;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_peakMutex);
|
||||||
|
peak = _peakUpdated ? _peak : _previousPeak;
|
||||||
|
_previousPeak = peak;
|
||||||
|
_peak = -std::numeric_limits<float>::infinity();
|
||||||
|
_peakUpdated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double curVolume = _useDb ? peak : DecibelToPercent(peak) * 100;
|
||||||
|
|
||||||
switch (_outputCondition) {
|
switch (_outputCondition) {
|
||||||
case OutputCondition::ABOVE:
|
case OutputCondition::ABOVE:
|
||||||
@@ -92,7 +106,6 @@ bool MacroConditionAudio::CheckOutputCondition()
|
|||||||
SetTempVarValue("output_volume", std::to_string(curVolume));
|
SetTempVarValue("output_volume", std::to_string(curVolume));
|
||||||
|
|
||||||
// Reset for next check
|
// Reset for next check
|
||||||
_peak = -std::numeric_limits<float>::infinity();
|
|
||||||
if (_audioSource.GetType() == SourceSelection::Type::VARIABLE) {
|
if (_audioSource.GetType() == SourceSelection::Type::VARIABLE) {
|
||||||
ResetVolmeter();
|
ResetVolmeter();
|
||||||
}
|
}
|
||||||
@@ -253,7 +266,7 @@ bool MacroConditionAudio::Save(obs_data_t *obj) const
|
|||||||
static_cast<int>(_volumeCondition));
|
static_cast<int>(_volumeCondition));
|
||||||
obs_data_set_bool(obj, "useDb", _useDb);
|
obs_data_set_bool(obj, "useDb", _useDb);
|
||||||
_volumeDB.Save(obj, "volumeDB");
|
_volumeDB.Save(obj, "volumeDB");
|
||||||
obs_data_set_int(obj, "version", 2);
|
obs_data_set_int(obj, "version", 3);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,9 +307,19 @@ bool MacroConditionAudio::Load(obs_data_t *obj)
|
|||||||
_volumeCondition = static_cast<VolumeCondition>(
|
_volumeCondition = static_cast<VolumeCondition>(
|
||||||
obs_data_get_int(obj, "volumeCondition"));
|
obs_data_get_int(obj, "volumeCondition"));
|
||||||
_volmeter = AddVolmeterToSource(this, _audioSource.GetSource());
|
_volmeter = AddVolmeterToSource(this, _audioSource.GetSource());
|
||||||
if (obs_data_get_int(obj, "version") != 2) {
|
|
||||||
|
if (obs_data_get_int(obj, "version") < 2) {
|
||||||
|
// Set default values for dB handling
|
||||||
_useDb = false;
|
_useDb = false;
|
||||||
_volumeDB = 0.0;
|
_volumeDB = 0.0;
|
||||||
|
|
||||||
|
// In previous versions the scaling happened in CheckCondition()
|
||||||
|
// so these values must now be converted to enable compatibility
|
||||||
|
// with the decibel value based checks.
|
||||||
|
OBSDataAutoRelease data = obs_data_get_obj(obj, "volume");
|
||||||
|
auto oldFixedValue = obs_data_get_int(data, "value");
|
||||||
|
_volumeDB = ((double)oldFixedValue / 1.7) - 60;
|
||||||
|
_volumePercent = DecibelToPercent(_volumeDB) * 100;
|
||||||
} else {
|
} else {
|
||||||
_useDb = obs_data_get_bool(obj, "useDb");
|
_useDb = obs_data_get_bool(obj, "useDb");
|
||||||
_volumeDB.Load(obj, "volumeDB");
|
_volumeDB.Load(obj, "volumeDB");
|
||||||
@@ -319,11 +342,13 @@ void MacroConditionAudio::SetVolumeLevel(void *data, const float *,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(c->_peakMutex);
|
||||||
for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) {
|
for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) {
|
||||||
if (peak[i] > c->_peak) {
|
if (peak[i] > c->_peak) {
|
||||||
c->_peak = peak[i];
|
c->_peak = peak[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
c->_peakUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionAudio::ResetVolmeter()
|
void MacroConditionAudio::ResetVolmeter()
|
||||||
@@ -416,7 +441,7 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
|||||||
_checkTypes(new QComboBox()),
|
_checkTypes(new QComboBox()),
|
||||||
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
||||||
_condition(new QComboBox()),
|
_condition(new QComboBox()),
|
||||||
_volumePercent(new VariableSpinBox()),
|
_volumePercent(new VariableDoubleSpinBox()),
|
||||||
_volumeDB(new VariableDoubleSpinBox),
|
_volumeDB(new VariableDoubleSpinBox),
|
||||||
_percentDBToggle(new QPushButton),
|
_percentDBToggle(new QPushButton),
|
||||||
_syncOffset(new VariableSpinBox()),
|
_syncOffset(new VariableSpinBox()),
|
||||||
@@ -444,8 +469,9 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
|||||||
SLOT(CheckTypeChanged(int)));
|
SLOT(CheckTypeChanged(int)));
|
||||||
QWidget::connect(
|
QWidget::connect(
|
||||||
_volumePercent,
|
_volumePercent,
|
||||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
SIGNAL(NumberVariableChanged(const NumberVariable<double> &)),
|
||||||
this, SLOT(VolumePercentChanged(const NumberVariable<int> &)));
|
this,
|
||||||
|
SLOT(VolumePercentChanged(const NumberVariable<double> &)));
|
||||||
QWidget::connect(
|
QWidget::connect(
|
||||||
_syncOffset,
|
_syncOffset,
|
||||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||||
@@ -506,11 +532,12 @@ void MacroConditionAudioEdit::UpdateVolmeterSource()
|
|||||||
auto layout = this->layout();
|
auto layout = this->layout();
|
||||||
layout->addWidget(_volMeter);
|
layout->addWidget(_volMeter);
|
||||||
|
|
||||||
QWidget::connect(_volMeter->GetSlider(), &QSlider::valueChanged,
|
QWidget::connect(_volMeter->GetSlider(),
|
||||||
[=](int) { SyncSliderAndValueSelection(true); });
|
&DoubleSlider::DoubleValChanged,
|
||||||
|
[=](double) { SyncSliderAndValueSelection(true); });
|
||||||
|
|
||||||
// Slider will default to 0 so set it manually once
|
// Slider will default to 0 so set it manually once
|
||||||
_volMeter->GetSlider()->setValue(_entryData->_volumePercent);
|
SyncSliderAndValueSelection(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionAudioEdit::SourceChanged(const SourceSelection &source)
|
void MacroConditionAudioEdit::SourceChanged(const SourceSelection &source)
|
||||||
@@ -531,7 +558,7 @@ void MacroConditionAudioEdit::SourceChanged(const SourceSelection &source)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionAudioEdit::VolumePercentChanged(
|
void MacroConditionAudioEdit::VolumePercentChanged(
|
||||||
const NumberVariable<int> &vol)
|
const NumberVariable<double> &vol)
|
||||||
{
|
{
|
||||||
if (_loading || !_entryData) {
|
if (_loading || !_entryData) {
|
||||||
return;
|
return;
|
||||||
@@ -600,35 +627,35 @@ void MacroConditionAudioEdit::PercentDBClicked()
|
|||||||
|
|
||||||
void MacroConditionAudioEdit::SyncSliderAndValueSelection(bool sliderMoved)
|
void MacroConditionAudioEdit::SyncSliderAndValueSelection(bool sliderMoved)
|
||||||
{
|
{
|
||||||
if (_loading || !_entryData) {
|
if (!_entryData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sliderMoved) {
|
if (sliderMoved) {
|
||||||
|
auto sliderPosition = _volMeter->GetSlider()->DoubleValue();
|
||||||
|
// Adjust to the dB scale on the volume meter widget
|
||||||
|
auto dBScaleValue = ((sliderPosition * 3.0) / 5.0) - 60.0;
|
||||||
|
|
||||||
if (_entryData->_useDb) {
|
if (_entryData->_useDb) {
|
||||||
_volumeDB->SetFixedValue(PercentToDecibel(
|
_volumeDB->SetFixedValue(dBScaleValue);
|
||||||
(float)_volMeter->GetSlider()->value() /
|
|
||||||
100.0));
|
|
||||||
const QSignalBlocker blocker(this);
|
const QSignalBlocker blocker(this);
|
||||||
_volumePercent->SetFixedValue(
|
_volumePercent->SetFixedValue(
|
||||||
_volMeter->GetSlider()->value());
|
DecibelToPercent(dBScaleValue) * 100);
|
||||||
} else {
|
} else {
|
||||||
_volumePercent->SetFixedValue(
|
_volumePercent->SetFixedValue(
|
||||||
_volMeter->GetSlider()->value());
|
DecibelToPercent(dBScaleValue) * 100);
|
||||||
const QSignalBlocker blocker(this);
|
const QSignalBlocker blocker(this);
|
||||||
_volumeDB->SetFixedValue(PercentToDecibel(
|
_volumeDB->SetFixedValue(dBScaleValue);
|
||||||
(float)_volMeter->GetSlider()->value() /
|
|
||||||
100.0));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const QSignalBlocker blocker(this);
|
const QSignalBlocker blocker(this);
|
||||||
if (_entryData->_useDb) {
|
double dBValue =
|
||||||
_volMeter->GetSlider()->setValue(
|
_entryData->_useDb
|
||||||
DecibelToPercent(_entryData->_volumeDB) * 100);
|
? _entryData->_volumeDB.GetFixedValue()
|
||||||
} else {
|
: PercentToDecibel(_entryData->_volumePercent /
|
||||||
_volMeter->GetSlider()->setValue(
|
100.0);
|
||||||
_entryData->_volumePercent);
|
auto sliderPosition = (dBValue + 60.0) * 5 / 3.0;
|
||||||
}
|
_volMeter->GetSlider()->SetDoubleVal(sliderPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,11 +55,11 @@ public:
|
|||||||
|
|
||||||
SourceSelection _audioSource;
|
SourceSelection _audioSource;
|
||||||
bool _useDb = false;
|
bool _useDb = false;
|
||||||
NumberVariable<int> _volumePercent = 0;
|
DoubleVariable _volumePercent = 0;
|
||||||
NumberVariable<double> _volumeDB = 0.0;
|
DoubleVariable _volumeDB = 0.0;
|
||||||
NumberVariable<int> _syncOffset = 0;
|
IntVariable _syncOffset = 0;
|
||||||
obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE;
|
obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE;
|
||||||
NumberVariable<double> _balance = 0.5;
|
DoubleVariable _balance = 0.5;
|
||||||
OutputCondition _outputCondition = OutputCondition::ABOVE;
|
OutputCondition _outputCondition = OutputCondition::ABOVE;
|
||||||
VolumeCondition _volumeCondition = VolumeCondition::ABOVE;
|
VolumeCondition _volumeCondition = VolumeCondition::ABOVE;
|
||||||
obs_volmeter_t *_volmeter = nullptr;
|
obs_volmeter_t *_volmeter = nullptr;
|
||||||
@@ -73,7 +73,10 @@ private:
|
|||||||
void SetupTempVars();
|
void SetupTempVars();
|
||||||
|
|
||||||
Type _checkType = Type::OUTPUT_VOLUME;
|
Type _checkType = Type::OUTPUT_VOLUME;
|
||||||
|
std::mutex _peakMutex;
|
||||||
float _peak = -std::numeric_limits<float>::infinity();
|
float _peak = -std::numeric_limits<float>::infinity();
|
||||||
|
float _previousPeak = -std::numeric_limits<float>::infinity();
|
||||||
|
bool _peakUpdated = false;
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const std::string id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
@@ -97,7 +100,7 @@ public:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void SourceChanged(const SourceSelection &);
|
void SourceChanged(const SourceSelection &);
|
||||||
void VolumePercentChanged(const NumberVariable<int> &vol);
|
void VolumePercentChanged(const NumberVariable<double> &vol);
|
||||||
void ConditionChanged(int cond);
|
void ConditionChanged(int cond);
|
||||||
void CheckTypeChanged(int cond);
|
void CheckTypeChanged(int cond);
|
||||||
void SyncOffsetChanged(const NumberVariable<int> &value);
|
void SyncOffsetChanged(const NumberVariable<int> &value);
|
||||||
@@ -117,7 +120,7 @@ private:
|
|||||||
QComboBox *_checkTypes;
|
QComboBox *_checkTypes;
|
||||||
SourceSelectionWidget *_sources;
|
SourceSelectionWidget *_sources;
|
||||||
QComboBox *_condition;
|
QComboBox *_condition;
|
||||||
VariableSpinBox *_volumePercent;
|
VariableDoubleSpinBox *_volumePercent;
|
||||||
VariableDoubleSpinBox *_volumeDB;
|
VariableDoubleSpinBox *_volumeDB;
|
||||||
QPushButton *_percentDBToggle;
|
QPushButton *_percentDBToggle;
|
||||||
VariableSpinBox *_syncOffset;
|
VariableSpinBox *_syncOffset;
|
||||||
|
|||||||
312
plugins/base/macro-condition-clipboard.cpp
Normal file
312
plugins/base/macro-condition-clipboard.cpp
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
#include "macro-condition-clipboard.hpp"
|
||||||
|
#include "layout-helpers.hpp"
|
||||||
|
#include "ui-helpers.hpp"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QMimeData>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
const std::string MacroConditionClipboard::id = "clipboard";
|
||||||
|
|
||||||
|
bool MacroConditionClipboard::_registered = MacroConditionFactory::Register(
|
||||||
|
MacroConditionClipboard::id,
|
||||||
|
{MacroConditionClipboard::Create, MacroConditionClipboardEdit::Create,
|
||||||
|
"AdvSceneSwitcher.condition.clipboard"});
|
||||||
|
|
||||||
|
const static std::map<MacroConditionClipboard::Condition, std::string>
|
||||||
|
conditionTypes = {
|
||||||
|
{MacroConditionClipboard::Condition::CHANGED,
|
||||||
|
"AdvSceneSwitcher.condition.clipboard.condition.changed"},
|
||||||
|
{MacroConditionClipboard::Condition::IS_TEXT,
|
||||||
|
"AdvSceneSwitcher.condition.clipboard.condition.isText"},
|
||||||
|
{MacroConditionClipboard::Condition::IS_IMAGE,
|
||||||
|
"AdvSceneSwitcher.condition.clipboard.condition.isImage"},
|
||||||
|
{MacroConditionClipboard::Condition::IS_URL,
|
||||||
|
"AdvSceneSwitcher.condition.clipboard.condition.isURL"},
|
||||||
|
{MacroConditionClipboard::Condition::MATCHES,
|
||||||
|
"AdvSceneSwitcher.condition.clipboard.condition.matches"},
|
||||||
|
};
|
||||||
|
|
||||||
|
ClipboardMessageBuffer ClipboardListener::RegisterForClipboardChanges()
|
||||||
|
{
|
||||||
|
return Instance()->_dispatcher.RegisterClient();
|
||||||
|
}
|
||||||
|
|
||||||
|
ClipboardListener *ClipboardListener::Instance()
|
||||||
|
{
|
||||||
|
static ClipboardListener instance;
|
||||||
|
return &instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClipboardListener::ClipboardListener() : QObject(nullptr)
|
||||||
|
{
|
||||||
|
if (!QApplication::clipboard()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QObject::connect(QApplication::clipboard(), &QClipboard::dataChanged,
|
||||||
|
this, &ClipboardListener::ClipboardDataChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClipboardListener::ClipboardDataChanged()
|
||||||
|
{
|
||||||
|
auto text = QApplication::clipboard()->text();
|
||||||
|
_dispatcher.DispatchMessage(text.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroConditionClipboard::MacroConditionClipboard(Macro *m) : MacroCondition(m)
|
||||||
|
{
|
||||||
|
_messageBuffer = ClipboardListener::RegisterForClipboardChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<MacroCondition> MacroConditionClipboard::Create(Macro *m)
|
||||||
|
{
|
||||||
|
return std::make_shared<MacroConditionClipboard>(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool clipboardContainsImage()
|
||||||
|
{
|
||||||
|
const QClipboard *clipboard = QApplication::clipboard();
|
||||||
|
const QMimeData *mimeData = clipboard->mimeData();
|
||||||
|
return mimeData->hasImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool clipboardContainsText()
|
||||||
|
{
|
||||||
|
const QClipboard *clipboard = QApplication::clipboard();
|
||||||
|
const QMimeData *mimeData = clipboard->mimeData();
|
||||||
|
return mimeData->hasText();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool clipboardContainsUrl()
|
||||||
|
{
|
||||||
|
const QClipboard *clipboard = QApplication::clipboard();
|
||||||
|
const QMimeData *mimeData = clipboard->mimeData();
|
||||||
|
return mimeData->hasUrls();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getCurrentClipboardText()
|
||||||
|
{
|
||||||
|
auto clipboard = QApplication::clipboard();
|
||||||
|
if (!clipboard) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return clipboard->text().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionClipboard::CheckCondition()
|
||||||
|
{
|
||||||
|
switch (_condition) {
|
||||||
|
case Condition::CHANGED:
|
||||||
|
while (!_messageBuffer->Empty()) {
|
||||||
|
auto message = _messageBuffer->ConsumeMessage();
|
||||||
|
if (!message) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SetTempVarValue("text", *message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Condition::IS_TEXT:
|
||||||
|
if (clipboardContainsText()) {
|
||||||
|
SetTempVarValue("text", getCurrentClipboardText());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Condition::IS_IMAGE:
|
||||||
|
return clipboardContainsImage();
|
||||||
|
case Condition::IS_URL:
|
||||||
|
if (clipboardContainsUrl()) {
|
||||||
|
SetTempVarValue("text", getCurrentClipboardText());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case Condition::MATCHES:
|
||||||
|
if (_regex.Enabled()) {
|
||||||
|
auto text = getCurrentClipboardText();
|
||||||
|
if (_regex.Matches(text, _text)) {
|
||||||
|
SetTempVarValue("text", text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto text = getCurrentClipboardText();
|
||||||
|
if (text == std::string(_text)) {
|
||||||
|
SetTempVarValue("text", text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionClipboard::SetCondition(Condition condition)
|
||||||
|
{
|
||||||
|
_condition = condition;
|
||||||
|
_messageBuffer.reset();
|
||||||
|
if (_condition == Condition::CHANGED) {
|
||||||
|
_messageBuffer =
|
||||||
|
ClipboardListener::RegisterForClipboardChanges();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionClipboard::SetupTempVars()
|
||||||
|
{
|
||||||
|
MacroCondition::SetupTempVars();
|
||||||
|
|
||||||
|
AddTempvar(
|
||||||
|
"text",
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.clipboard.text"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.clipboard.text.description"));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionClipboard::Save(obs_data_t *obj) const
|
||||||
|
{
|
||||||
|
MacroCondition::Save(obj);
|
||||||
|
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
||||||
|
_text.Save(obj, "text");
|
||||||
|
_regex.Save(obj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionClipboard::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroCondition::Load(obj);
|
||||||
|
_text.Load(obj, "text");
|
||||||
|
_regex.Load(obj);
|
||||||
|
SetCondition(
|
||||||
|
static_cast<Condition>(obs_data_get_int(obj, "condition")));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void populateCompareModeselection(QComboBox *list)
|
||||||
|
{
|
||||||
|
for (const auto &[_, name] : conditionTypes) {
|
||||||
|
list->addItem(obs_module_text(name.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroConditionClipboardEdit::MacroConditionClipboardEdit(
|
||||||
|
QWidget *parent, std::shared_ptr<MacroConditionClipboard> entryData)
|
||||||
|
: QWidget(parent),
|
||||||
|
_conditions(new QComboBox(this)),
|
||||||
|
_text(new VariableTextEdit(this)),
|
||||||
|
_regex(new RegexConfigWidget(parent)),
|
||||||
|
_urlInfo(new QLabel())
|
||||||
|
{
|
||||||
|
populateCompareModeselection(_conditions);
|
||||||
|
|
||||||
|
QString path = GetThemeTypeName() == "Light"
|
||||||
|
? ":/res/images/help.svg"
|
||||||
|
: ":/res/images/help_light.svg";
|
||||||
|
QIcon icon(path);
|
||||||
|
QPixmap pixmap = icon.pixmap(QSize(16, 16));
|
||||||
|
_urlInfo->setPixmap(pixmap);
|
||||||
|
_urlInfo->hide();
|
||||||
|
_urlInfo->setToolTip(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.clipboard.urlTooltip"));
|
||||||
|
|
||||||
|
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ConditionChanged(int)));
|
||||||
|
QWidget::connect(_text, SIGNAL(textChanged()), this,
|
||||||
|
SLOT(TextChanged()));
|
||||||
|
QWidget::connect(_regex,
|
||||||
|
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
|
||||||
|
SLOT(RegexChanged(const RegexConfig &)));
|
||||||
|
|
||||||
|
auto layout = new QHBoxLayout();
|
||||||
|
PlaceWidgets(
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.clipboard.condition.entry"),
|
||||||
|
layout,
|
||||||
|
{{"{{conditions}}", _conditions},
|
||||||
|
{"{{regex}}", _regex},
|
||||||
|
{"{{urlInfo}}", _urlInfo}});
|
||||||
|
|
||||||
|
auto mainLayout = new QVBoxLayout();
|
||||||
|
mainLayout->addLayout(layout);
|
||||||
|
mainLayout->addWidget(_text);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
_entryData = entryData;
|
||||||
|
UpdateEntryData();
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget *
|
||||||
|
MacroConditionClipboardEdit::Create(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroCondition> action)
|
||||||
|
{
|
||||||
|
return new MacroConditionClipboardEdit(
|
||||||
|
parent,
|
||||||
|
std::dynamic_pointer_cast<MacroConditionClipboard>(action));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionClipboardEdit::ConditionChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->SetCondition(
|
||||||
|
static_cast<MacroConditionClipboard::Condition>(value));
|
||||||
|
SetWidgetVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionClipboardEdit::TextChanged()
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->_text = _text->toPlainText().toStdString();
|
||||||
|
adjustSize();
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionClipboardEdit::RegexChanged(const RegexConfig &conf)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->_regex = conf;
|
||||||
|
adjustSize();
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionClipboardEdit::UpdateEntryData()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_conditions->setCurrentIndex(
|
||||||
|
static_cast<int>(_entryData->GetCondition()));
|
||||||
|
_text->setPlainText(_entryData->_text);
|
||||||
|
_regex->SetRegexConfig(_entryData->_regex);
|
||||||
|
SetWidgetVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionClipboardEdit::SetWidgetVisibility()
|
||||||
|
{
|
||||||
|
const bool requiresTextInput =
|
||||||
|
_entryData->GetCondition() ==
|
||||||
|
MacroConditionClipboard::Condition::MATCHES;
|
||||||
|
_regex->setVisible(requiresTextInput);
|
||||||
|
_text->setVisible(requiresTextInput);
|
||||||
|
_urlInfo->setVisible(_entryData->GetCondition() ==
|
||||||
|
MacroConditionClipboard::Condition::IS_URL);
|
||||||
|
adjustSize();
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
92
plugins/base/macro-condition-clipboard.hpp
Normal file
92
plugins/base/macro-condition-clipboard.hpp
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "macro-condition-edit.hpp"
|
||||||
|
#include "filter-combo-box.hpp"
|
||||||
|
#include "message-buffer.hpp"
|
||||||
|
#include "message-dispatcher.hpp"
|
||||||
|
#include "regex-config.hpp"
|
||||||
|
#include "variable-text-edit.hpp"
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
using ClipboardMessageBuffer = std::shared_ptr<MessageBuffer<std::string>>;
|
||||||
|
using ClipboardMessageDispatcher = MessageDispatcher<std::string>;
|
||||||
|
|
||||||
|
class ClipboardListener : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
[[nodiscard]] static ClipboardMessageBuffer
|
||||||
|
RegisterForClipboardChanges();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void ClipboardDataChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ClipboardListener();
|
||||||
|
static ClipboardListener *Instance();
|
||||||
|
|
||||||
|
ClipboardMessageDispatcher _dispatcher;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroConditionClipboard : public MacroCondition {
|
||||||
|
public:
|
||||||
|
MacroConditionClipboard(Macro *m);
|
||||||
|
static std::shared_ptr<MacroCondition> Create(Macro *m);
|
||||||
|
std::string GetId() const { return id; };
|
||||||
|
bool CheckCondition();
|
||||||
|
|
||||||
|
bool Save(obs_data_t *obj) const;
|
||||||
|
bool Load(obs_data_t *obj);
|
||||||
|
|
||||||
|
enum class Condition {
|
||||||
|
CHANGED,
|
||||||
|
IS_TEXT,
|
||||||
|
IS_IMAGE,
|
||||||
|
IS_URL,
|
||||||
|
MATCHES,
|
||||||
|
};
|
||||||
|
void SetCondition(Condition);
|
||||||
|
Condition GetCondition() const { return _condition; }
|
||||||
|
|
||||||
|
StringVariable _text = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.clipboard.placeholder");
|
||||||
|
RegexConfig _regex;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetupTempVars();
|
||||||
|
|
||||||
|
Condition _condition = Condition::CHANGED;
|
||||||
|
ClipboardMessageBuffer _messageBuffer;
|
||||||
|
|
||||||
|
static bool _registered;
|
||||||
|
static const std::string id;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroConditionClipboardEdit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroConditionClipboardEdit(
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<MacroConditionClipboard> entryData = nullptr);
|
||||||
|
static QWidget *Create(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroCondition> action);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void ConditionChanged(int);
|
||||||
|
void TextChanged();
|
||||||
|
void RegexChanged(const RegexConfig &conf);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void UpdateEntryData();
|
||||||
|
void SetWidgetVisibility();
|
||||||
|
|
||||||
|
QComboBox *_conditions;
|
||||||
|
VariableTextEdit *_text;
|
||||||
|
RegexConfigWidget *_regex;
|
||||||
|
QLabel *_urlInfo;
|
||||||
|
|
||||||
|
std::shared_ptr<MacroConditionClipboard> _entryData;
|
||||||
|
bool _loading = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -42,6 +42,12 @@ static std::string getRemoteData(std::string &url)
|
|||||||
return readBuffer;
|
return readBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroConditionFile::SetCondition(Condition condition)
|
||||||
|
{
|
||||||
|
_condition = condition;
|
||||||
|
SetupTempVars();
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroConditionFile::MatchFileContent(QString &filedata)
|
bool MacroConditionFile::MatchFileContent(QString &filedata)
|
||||||
{
|
{
|
||||||
if (_onlyMatchIfChanged) {
|
if (_onlyMatchIfChanged) {
|
||||||
@@ -65,6 +71,7 @@ bool MacroConditionFile::CheckRemoteFileContent()
|
|||||||
std::string path = _file;
|
std::string path = _file;
|
||||||
std::string data = getRemoteData(path);
|
std::string data = getRemoteData(path);
|
||||||
SetVariableValue(data);
|
SetVariableValue(data);
|
||||||
|
SetTempVarValue("content", data);
|
||||||
QString qdata = QString::fromStdString(data);
|
QString qdata = QString::fromStdString(data);
|
||||||
return MatchFileContent(qdata);
|
return MatchFileContent(qdata);
|
||||||
}
|
}
|
||||||
@@ -86,6 +93,7 @@ bool MacroConditionFile::CheckLocalFileContent()
|
|||||||
|
|
||||||
QString filedata = QTextStream(&file).readAll();
|
QString filedata = QTextStream(&file).readAll();
|
||||||
SetVariableValue(filedata.toStdString());
|
SetVariableValue(filedata.toStdString());
|
||||||
|
SetTempVarValue("content", filedata.toStdString());
|
||||||
bool match = MatchFileContent(filedata);
|
bool match = MatchFileContent(filedata);
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
@@ -114,6 +122,7 @@ bool MacroConditionFile::CheckChangeContent()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetTempVarValue("content", filedata.toStdString());
|
||||||
size_t newHash = strHash(filedata.toUtf8().constData());
|
size_t newHash = strHash(filedata.toUtf8().constData());
|
||||||
const bool contentChanged = newHash != _lastHash;
|
const bool contentChanged = newHash != _lastHash;
|
||||||
_lastHash = newHash;
|
_lastHash = newHash;
|
||||||
@@ -131,24 +140,39 @@ bool MacroConditionFile::CheckChangeDate()
|
|||||||
SetVariableValue(newLastMod.toString().toStdString());
|
SetVariableValue(newLastMod.toString().toStdString());
|
||||||
const bool dateChanged = _lastMod != newLastMod;
|
const bool dateChanged = _lastMod != newLastMod;
|
||||||
_lastMod = newLastMod;
|
_lastMod = newLastMod;
|
||||||
|
SetTempVarValue("date", newLastMod.toString(Qt::ISODate).toStdString());
|
||||||
return dateChanged;
|
return dateChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroConditionFile::SetupTempVars()
|
||||||
|
{
|
||||||
|
MacroCondition::SetupTempVars();
|
||||||
|
if (_condition == Condition::DATE_CHANGE) {
|
||||||
|
AddTempvar(
|
||||||
|
"date",
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.file.date"));
|
||||||
|
} else {
|
||||||
|
AddTempvar("content",
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.file.content"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroConditionFile::CheckCondition()
|
bool MacroConditionFile::CheckCondition()
|
||||||
{
|
{
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
switch (_condition) {
|
switch (_condition) {
|
||||||
case MacroConditionFile::ConditionType::MATCH:
|
case Condition::MATCH:
|
||||||
if (_fileType == FileType::REMOTE) {
|
if (_fileType == FileType::REMOTE) {
|
||||||
ret = CheckRemoteFileContent();
|
ret = CheckRemoteFileContent();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ret = CheckLocalFileContent();
|
ret = CheckLocalFileContent();
|
||||||
break;
|
break;
|
||||||
case MacroConditionFile::ConditionType::CONTENT_CHANGE:
|
case Condition::CONTENT_CHANGE:
|
||||||
ret = CheckChangeContent();
|
ret = CheckChangeContent();
|
||||||
break;
|
break;
|
||||||
case MacroConditionFile::ConditionType::DATE_CHANGE:
|
case Condition::DATE_CHANGE:
|
||||||
ret = CheckChangeDate();
|
ret = CheckChangeDate();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -158,7 +182,6 @@ bool MacroConditionFile::CheckCondition()
|
|||||||
if (GetVariableValue().empty()) {
|
if (GetVariableValue().empty()) {
|
||||||
SetVariableValue(ret ? "true" : "false");
|
SetVariableValue(ret ? "true" : "false");
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,8 +210,8 @@ bool MacroConditionFile::Load(obs_data_t *obj)
|
|||||||
_file.Load(obj, "file");
|
_file.Load(obj, "file");
|
||||||
_text.Load(obj, "text");
|
_text.Load(obj, "text");
|
||||||
_fileType = static_cast<FileType>(obs_data_get_int(obj, "fileType"));
|
_fileType = static_cast<FileType>(obs_data_get_int(obj, "fileType"));
|
||||||
_condition =
|
SetCondition(
|
||||||
static_cast<ConditionType>(obs_data_get_int(obj, "condition"));
|
static_cast<Condition>(obs_data_get_int(obj, "condition")));
|
||||||
_useTime = obs_data_get_bool(obj, "useTime");
|
_useTime = obs_data_get_bool(obj, "useTime");
|
||||||
_onlyMatchIfChanged = obs_data_get_bool(obj, "onlyMatchIfChanged");
|
_onlyMatchIfChanged = obs_data_get_bool(obj, "onlyMatchIfChanged");
|
||||||
return true;
|
return true;
|
||||||
@@ -292,7 +315,8 @@ void MacroConditionFileEdit::UpdateEntryData()
|
|||||||
}
|
}
|
||||||
|
|
||||||
_fileTypes->setCurrentIndex(static_cast<int>(_entryData->_fileType));
|
_fileTypes->setCurrentIndex(static_cast<int>(_entryData->_fileType));
|
||||||
_conditions->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
_conditions->setCurrentIndex(
|
||||||
|
static_cast<int>(_entryData->GetCondition()));
|
||||||
_filePath->SetPath(_entryData->_file);
|
_filePath->SetPath(_entryData->_file);
|
||||||
_matchText->setPlainText(_entryData->_text);
|
_matchText->setPlainText(_entryData->_text);
|
||||||
_regex->SetRegexConfig(_entryData->_regex);
|
_regex->SetRegexConfig(_entryData->_regex);
|
||||||
@@ -338,8 +362,8 @@ void MacroConditionFileEdit::ConditionChanged(int index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
_entryData->_condition =
|
_entryData->SetCondition(
|
||||||
static_cast<MacroConditionFile::ConditionType>(index);
|
static_cast<MacroConditionFile::Condition>(index));
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,18 +430,18 @@ void MacroConditionFileEdit::SetWidgetVisibility()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_matchText->setVisible(_entryData->_condition ==
|
_matchText->setVisible(_entryData->GetCondition() ==
|
||||||
MacroConditionFile::ConditionType::MATCH);
|
MacroConditionFile::Condition::MATCH);
|
||||||
_regex->setVisible(_entryData->_condition ==
|
_regex->setVisible(_entryData->GetCondition() ==
|
||||||
MacroConditionFile::ConditionType::MATCH);
|
MacroConditionFile::Condition::MATCH);
|
||||||
_checkModificationDate->setVisible(
|
_checkModificationDate->setVisible(
|
||||||
_entryData->_useTime &&
|
_entryData->_useTime &&
|
||||||
_entryData->_condition ==
|
_entryData->GetCondition() ==
|
||||||
MacroConditionFile::ConditionType::MATCH);
|
MacroConditionFile::Condition::MATCH);
|
||||||
_checkFileContent->setVisible(
|
_checkFileContent->setVisible(
|
||||||
_entryData->_onlyMatchIfChanged &&
|
_entryData->_onlyMatchIfChanged &&
|
||||||
_entryData->_condition ==
|
_entryData->GetCondition() ==
|
||||||
MacroConditionFile::ConditionType::MATCH);
|
MacroConditionFile::Condition::MATCH);
|
||||||
adjustSize();
|
adjustSize();
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,16 +31,17 @@ public:
|
|||||||
REMOTE,
|
REMOTE,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ConditionType {
|
enum class Condition {
|
||||||
MATCH,
|
MATCH,
|
||||||
CONTENT_CHANGE,
|
CONTENT_CHANGE,
|
||||||
DATE_CHANGE,
|
DATE_CHANGE,
|
||||||
};
|
};
|
||||||
|
void SetCondition(Condition condition);
|
||||||
|
Condition GetCondition() const { return _condition; }
|
||||||
|
|
||||||
StringVariable _file = obs_module_text("AdvSceneSwitcher.enterPath");
|
StringVariable _file = obs_module_text("AdvSceneSwitcher.enterPath");
|
||||||
StringVariable _text = obs_module_text("AdvSceneSwitcher.enterText");
|
StringVariable _text = obs_module_text("AdvSceneSwitcher.enterText");
|
||||||
FileType _fileType = FileType::LOCAL;
|
FileType _fileType = FileType::LOCAL;
|
||||||
ConditionType _condition = ConditionType::MATCH;
|
|
||||||
RegexConfig _regex;
|
RegexConfig _regex;
|
||||||
|
|
||||||
// TODO: Remove in future version
|
// TODO: Remove in future version
|
||||||
@@ -53,7 +54,9 @@ private:
|
|||||||
bool CheckLocalFileContent();
|
bool CheckLocalFileContent();
|
||||||
bool CheckChangeContent();
|
bool CheckChangeContent();
|
||||||
bool CheckChangeDate();
|
bool CheckChangeDate();
|
||||||
|
void SetupTempVars();
|
||||||
|
|
||||||
|
Condition _condition = Condition::MATCH;
|
||||||
QDateTime _lastMod;
|
QDateTime _lastMod;
|
||||||
size_t _lastHash = 0;
|
size_t _lastHash = 0;
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
|
|||||||
@@ -23,13 +23,17 @@ MacroConditionHotkey::MacroConditionHotkey(Macro *m) : MacroCondition(m)
|
|||||||
|
|
||||||
bool MacroConditionHotkey::CheckCondition()
|
bool MacroConditionHotkey::CheckCondition()
|
||||||
{
|
{
|
||||||
const bool hotkeyIsCurrentlyPressed = _hotkey->GetPressed();
|
const bool keyStateCurrentlyMatches =
|
||||||
const bool hotkeyWasPressedSinceLastCheck = _hotkey->GetLastPressed() >
|
_checkPressed ? _hotkey->GetPressed() : !_hotkey->GetPressed();
|
||||||
_lastCheck;
|
const auto lastKeyStateMatch = _checkPressed
|
||||||
|
? _hotkey->GetLastPressed()
|
||||||
|
: _hotkey->GetLastReleased();
|
||||||
|
const bool hotkeySateChangedSinceLastCheck = lastKeyStateMatch >
|
||||||
|
_lastCheck;
|
||||||
const bool macroWasPausedSinceLastCheck =
|
const bool macroWasPausedSinceLastCheck =
|
||||||
MacroWasPausedSince(GetMacro(), _lastCheck);
|
MacroWasPausedSince(GetMacro(), _lastCheck);
|
||||||
bool ret = hotkeyIsCurrentlyPressed ||
|
bool ret = keyStateCurrentlyMatches ||
|
||||||
(hotkeyWasPressedSinceLastCheck &&
|
(hotkeySateChangedSinceLastCheck &&
|
||||||
!macroWasPausedSinceLastCheck);
|
!macroWasPausedSinceLastCheck);
|
||||||
_lastCheck = std::chrono::high_resolution_clock::now();
|
_lastCheck = std::chrono::high_resolution_clock::now();
|
||||||
return ret;
|
return ret;
|
||||||
@@ -39,6 +43,7 @@ bool MacroConditionHotkey::Save(obs_data_t *obj) const
|
|||||||
{
|
{
|
||||||
MacroCondition::Save(obj);
|
MacroCondition::Save(obj);
|
||||||
_hotkey->Save(obj);
|
_hotkey->Save(obj);
|
||||||
|
obs_data_set_bool(obj, "checkPressed", _checkPressed);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,34 +57,47 @@ bool MacroConditionHotkey::Load(obs_data_t *obj)
|
|||||||
"hotkey name conflict for \"%s\" - using previous key bind",
|
"hotkey name conflict for \"%s\" - using previous key bind",
|
||||||
description);
|
description);
|
||||||
}
|
}
|
||||||
|
if (obs_data_has_user_value(obj, "checkPressed")) {
|
||||||
|
_checkPressed = obs_data_get_bool(obj, "checkPressed");
|
||||||
|
} else { // TODO: Remove fallback at some point in the future
|
||||||
|
_checkPressed = true;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroConditionHotkeyEdit::MacroConditionHotkeyEdit(
|
MacroConditionHotkeyEdit::MacroConditionHotkeyEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroConditionHotkey> entryData)
|
QWidget *parent, std::shared_ptr<MacroConditionHotkey> entryData)
|
||||||
: QWidget(parent)
|
: QWidget(parent),
|
||||||
|
_name(new QLineEdit()),
|
||||||
|
_keyState(new QComboBox())
|
||||||
{
|
{
|
||||||
_name = new QLineEdit();
|
_keyState->addItems(
|
||||||
QLabel *line1 = new QLabel(obs_module_text(
|
QStringList()
|
||||||
"AdvSceneSwitcher.condition.hotkey.entry.line1"));
|
<< obs_module_text("AdvSceneSwitcher.condition.hotkey.pressed")
|
||||||
QLabel *hint = new QLabel(
|
<< obs_module_text(
|
||||||
obs_module_text("AdvSceneSwitcher.condition.hotkey.tip"));
|
"AdvSceneSwitcher.condition.hotkey.released"));
|
||||||
|
|
||||||
QWidget::connect(_name, SIGNAL(editingFinished()), this,
|
QWidget::connect(_name, SIGNAL(editingFinished()), this,
|
||||||
SLOT(NameChanged()));
|
SLOT(NameChanged()));
|
||||||
|
QWidget::connect(_keyState, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(KeyStateChanged(int)));
|
||||||
|
|
||||||
QHBoxLayout *switchLayout = new QHBoxLayout;
|
auto keyStateLayout = new QHBoxLayout;
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
PlaceWidgets(
|
||||||
{"{{name}}", _name},
|
obs_module_text(
|
||||||
};
|
"AdvSceneSwitcher.condition.hotkey.entry.keyState"),
|
||||||
PlaceWidgets(obs_module_text(
|
keyStateLayout, {{"{{keyState}}", _keyState}});
|
||||||
"AdvSceneSwitcher.condition.hotkey.entry.line2"),
|
|
||||||
switchLayout, widgetPlaceholders);
|
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
auto nameLayout = new QHBoxLayout;
|
||||||
mainLayout->addWidget(line1);
|
PlaceWidgets(
|
||||||
mainLayout->addLayout(switchLayout);
|
obs_module_text("AdvSceneSwitcher.condition.hotkey.entry.name"),
|
||||||
mainLayout->addWidget(hint);
|
nameLayout, {{"{{name}}", _name}});
|
||||||
|
|
||||||
|
auto mainLayout = new QVBoxLayout;
|
||||||
|
mainLayout->addLayout(keyStateLayout);
|
||||||
|
mainLayout->addLayout(nameLayout);
|
||||||
|
mainLayout->addWidget(new QLabel(
|
||||||
|
obs_module_text("AdvSceneSwitcher.condition.hotkey.tip")));
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
@@ -116,6 +134,17 @@ void MacroConditionHotkeyEdit::UpdateEntryData()
|
|||||||
|
|
||||||
_name->setText(
|
_name->setText(
|
||||||
QString::fromStdString(_entryData->_hotkey->GetDescription()));
|
QString::fromStdString(_entryData->_hotkey->GetDescription()));
|
||||||
|
_keyState->setCurrentIndex(_entryData->_checkPressed ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionHotkeyEdit::KeyStateChanged(int index)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock = LockContext();
|
||||||
|
_entryData->_checkPressed = index == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user