mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-29 12:45:28 -05:00
Compare commits
129 Commits
1.24.0-bet
...
hotkey
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b25c1250e5 | ||
|
|
98f3f51ba9 | ||
|
|
f0df9ead3c | ||
|
|
7b1a57070d | ||
|
|
a412f2fd5e | ||
|
|
4f0c8c4ab5 | ||
|
|
946c90a749 | ||
|
|
7ba4eaab9c | ||
|
|
74553a82fc | ||
|
|
39fcb2d743 | ||
|
|
7041feaea3 | ||
|
|
9b1ffaeded | ||
|
|
07d397bdac | ||
|
|
a86ff4f1f0 | ||
|
|
953eca2732 | ||
|
|
d6c5fb149a | ||
|
|
12982708cf | ||
|
|
0cf9e1dd81 | ||
|
|
71e20c4983 | ||
|
|
2147f6d3bf | ||
|
|
23df42d2d3 | ||
|
|
bcf0a0b7fd | ||
|
|
dd78b03a28 | ||
|
|
84dd5e6930 | ||
|
|
dcee98fea7 | ||
|
|
9ffb982ae5 | ||
|
|
428850306f | ||
|
|
abfd6798e3 | ||
|
|
fffadd94de | ||
|
|
d0919776f3 | ||
|
|
267855fded | ||
|
|
4bdebb7feb | ||
|
|
ab5f69d2ef | ||
|
|
63ee36ddfe | ||
|
|
43967f5ded | ||
|
|
c043053b2b | ||
|
|
220f27bd0a | ||
|
|
83914d5378 | ||
|
|
57e4b1a3f1 | ||
|
|
c85e556924 | ||
|
|
8c0be8011d | ||
|
|
7914f75876 | ||
|
|
7d1253e14e | ||
|
|
d7c58b3eb3 | ||
|
|
fb664b6f08 | ||
|
|
258a6d076e | ||
|
|
32ab060153 | ||
|
|
91d3784f9b | ||
|
|
8a5aac3d31 | ||
|
|
06c6effb7d | ||
|
|
f3789c05bd | ||
|
|
c64e1f5e51 | ||
|
|
5d8e24c19a | ||
|
|
f756de05c3 | ||
|
|
574fdb496f | ||
|
|
5580da69eb | ||
|
|
35274863c9 | ||
|
|
1f31b81f0d | ||
|
|
cde111ddeb | ||
|
|
845c12c01c | ||
|
|
99a0118d31 | ||
|
|
bb7ee17362 | ||
|
|
70854ef012 | ||
|
|
053c14056d | ||
|
|
9397d50764 | ||
|
|
473e24cc42 | ||
|
|
d9394605f4 | ||
|
|
d2b9074852 | ||
|
|
b525eb7a0e | ||
|
|
3805aaeeec | ||
|
|
50dc404689 | ||
|
|
975eacbc7e | ||
|
|
7e56dc35b8 | ||
|
|
b3566d98bf | ||
|
|
15379a8e20 | ||
|
|
1e178f4223 | ||
|
|
c16a7b93ea | ||
|
|
f89bb1a750 | ||
|
|
79961aabe4 | ||
|
|
4686fc2b01 | ||
|
|
569b915c07 | ||
|
|
324d3fe7a5 | ||
|
|
ae8d0bf5cb | ||
|
|
17efa82057 | ||
|
|
c17523a476 | ||
|
|
33635d6991 | ||
|
|
d290dbe86b | ||
|
|
c1f5c49eda | ||
|
|
c3f4caa6f3 | ||
|
|
d4c7b0e455 | ||
|
|
b0cb52fe90 | ||
|
|
386f831cd4 | ||
|
|
449daa80cc | ||
|
|
3003547b83 | ||
|
|
1664eb672f | ||
|
|
0939dcacb6 | ||
|
|
54b81d1a42 | ||
|
|
626606100f | ||
|
|
53a0b76e8c | ||
|
|
e16ac9400a | ||
|
|
94060c236b | ||
|
|
890792c270 | ||
|
|
7bc1fc3d0d | ||
|
|
9ea90ed61b | ||
|
|
ce40b80d90 | ||
|
|
53fcd94c5a | ||
|
|
ecb6247959 | ||
|
|
3b4cb6934d | ||
|
|
babe93a6ce | ||
|
|
1e9173699c | ||
|
|
37ba7aa2ca | ||
|
|
a83d2d9910 | ||
|
|
0449064f5d | ||
|
|
6cf1073a3c | ||
|
|
9ac9171206 | ||
|
|
25ce8cd2e4 | ||
|
|
e50522ab89 | ||
|
|
4801502f32 | ||
|
|
e13e4b5ddd | ||
|
|
de8da553f1 | ||
|
|
6558792e73 | ||
|
|
ea5e92017e | ||
|
|
46199efb58 | ||
|
|
8a6eae6c97 | ||
|
|
67eef8a004 | ||
|
|
b5341e5cde | ||
|
|
ac6140b17a | ||
|
|
b1489d98f0 | ||
|
|
3b7119ec58 |
5
.github/scripts/.Aptfile
vendored
5
.github/scripts/.Aptfile
vendored
@@ -7,3 +7,8 @@ package 'ninja-build', bin: 'ninja'
|
||||
package 'pkg-config'
|
||||
package 'clang'
|
||||
package 'clang-format-13'
|
||||
package 'libxtst-dev'
|
||||
package 'libxss-dev'
|
||||
package 'libopencv-dev'
|
||||
package 'libtesseract-dev'
|
||||
package 'libprocps-dev'
|
||||
|
||||
2
.github/scripts/Build-Windows.ps1
vendored
2
.github/scripts/Build-Windows.ps1
vendored
@@ -71,7 +71,7 @@ function Build {
|
||||
|
||||
(Get-Content -Path ${ProjectRoot}/CMakeLists.txt -Raw) `
|
||||
-replace "project\((.*) VERSION (.*)\)", "project(${ProductName} VERSION ${ProductVersion})" `
|
||||
| Out-File -Path ${ProjectRoot}/CMakeLists.txt
|
||||
| Out-File -Path ${ProjectRoot}/CMakeLists.txt -NoNewline
|
||||
|
||||
Setup-Obs
|
||||
|
||||
|
||||
2
.github/scripts/utils.zsh/check_packages
vendored
2
.github/scripts/utils.zsh/check_packages
vendored
@@ -24,7 +24,7 @@ if (( ! ${+commands[packagesbuild]} )) {
|
||||
pushd
|
||||
mkcd ${project_root:h}/obs-build-dependencies
|
||||
|
||||
local packages_url='http://s.sudre.free.fr/Software/files/Packages.dmg'
|
||||
local packages_url='https://web.archive.org/web/20230727054218/http://s.sudre.free.fr/Software/files/Packages.dmg'
|
||||
local packages_hash='6afdd25386295974dad8f078b8f1e41cabebd08e72d970bf92f707c7e48b16c9'
|
||||
|
||||
if [[ ! -f Packages.dmg ]] {
|
||||
|
||||
7
.github/scripts/utils.zsh/setup_linux
vendored
7
.github/scripts/utils.zsh/setup_linux
vendored
@@ -34,13 +34,6 @@ if (( ! (${skips[(Ie)all]} + ${skips[(Ie)deps]}) )) {
|
||||
|
||||
log_info 'Installing obs plugin dependencies...'
|
||||
|
||||
sudo apt-get install -y \
|
||||
libxtst-dev \
|
||||
libxss-dev \
|
||||
libopencv-dev \
|
||||
libtesseract-dev \
|
||||
libprocps-dev
|
||||
|
||||
local -a _qt_packages=()
|
||||
|
||||
if (( QT_VERSION == 5 )) {
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -22,3 +22,6 @@
|
||||
[submodule "deps/cpp-httplib"]
|
||||
path = deps/cpp-httplib
|
||||
url = https://github.com/yhirose/cpp-httplib.git
|
||||
[submodule "deps/json"]
|
||||
path = deps/json
|
||||
url = https://github.com/nlohmann/json.git
|
||||
|
||||
@@ -93,8 +93,12 @@ target_sources(
|
||||
${LIB_NAME}
|
||||
PRIVATE src/macro-core/macro-action-audio.cpp
|
||||
src/macro-core/macro-action-audio.hpp
|
||||
src/macro-core/macro-action-clipboard.cpp
|
||||
src/macro-core/macro-action-clipboard.hpp
|
||||
src/macro-core/macro-action-edit.cpp
|
||||
src/macro-core/macro-action-edit.hpp
|
||||
src/macro-core/macro-action-factory.cpp
|
||||
src/macro-core/macro-action-factory.hpp
|
||||
src/macro-core/macro-action-file.cpp
|
||||
src/macro-core/macro-action-file.hpp
|
||||
src/macro-core/macro-action-filter.cpp
|
||||
@@ -171,6 +175,8 @@ target_sources(
|
||||
src/macro-core/macro-condition-display.hpp
|
||||
src/macro-core/macro-condition-edit.cpp
|
||||
src/macro-core/macro-condition-edit.hpp
|
||||
src/macro-core/macro-condition-factory.cpp
|
||||
src/macro-core/macro-condition-factory.hpp
|
||||
src/macro-core/macro-condition-file.cpp
|
||||
src/macro-core/macro-condition-file.hpp
|
||||
src/macro-core/macro-condition-filter.cpp
|
||||
@@ -213,6 +219,8 @@ target_sources(
|
||||
src/macro-core/macro-condition-streaming.hpp
|
||||
src/macro-core/macro-condition-studio-mode.cpp
|
||||
src/macro-core/macro-condition-studio-mode.hpp
|
||||
src/macro-core/macro-condition-tempvar.cpp
|
||||
src/macro-core/macro-condition-tempvar.hpp
|
||||
src/macro-core/macro-condition-timer.cpp
|
||||
src/macro-core/macro-condition-timer.hpp
|
||||
src/macro-core/macro-condition-transition.cpp
|
||||
@@ -229,6 +237,8 @@ target_sources(
|
||||
src/macro-core/macro-condition.hpp
|
||||
src/macro-core/macro-dock.cpp
|
||||
src/macro-core/macro-dock.hpp
|
||||
src/macro-core/macro-helpers.cpp
|
||||
src/macro-core/macro-helpers.hpp
|
||||
src/macro-core/macro-properties.cpp
|
||||
src/macro-core/macro-properties.hpp
|
||||
src/macro-core/macro-ref.cpp
|
||||
@@ -252,6 +262,8 @@ target_sources(
|
||||
src/utils/connection-manager.hpp
|
||||
src/utils/curl-helper.cpp
|
||||
src/utils/curl-helper.hpp
|
||||
src/utils/duration.cpp
|
||||
src/utils/duration.hpp
|
||||
src/utils/duration-control.cpp
|
||||
src/utils/duration-control.hpp
|
||||
src/utils/export-symbol-helper.hpp
|
||||
@@ -285,6 +297,8 @@ target_sources(
|
||||
src/utils/obs-module-helper.hpp
|
||||
src/utils/osc-helpers.cpp
|
||||
src/utils/osc-helpers.hpp
|
||||
src/utils/plugin-state-helpers.cpp
|
||||
src/utils/plugin-state-helpers.hpp
|
||||
src/utils/priority-helper.cpp
|
||||
src/utils/priority-helper.hpp
|
||||
src/utils/process-config.cpp
|
||||
@@ -307,14 +321,18 @@ target_sources(
|
||||
src/utils/slider-spinbox.hpp
|
||||
src/utils/source-selection.cpp
|
||||
src/utils/source-selection.hpp
|
||||
src/utils/source-setting.cpp
|
||||
src/utils/source-setting.hpp
|
||||
src/utils/string-list.cpp
|
||||
src/utils/string-list.hpp
|
||||
src/utils/striped-frame.cpp
|
||||
src/utils/striped-frame.hpp
|
||||
src/utils/switch-button.cpp
|
||||
src/utils/switch-button.hpp
|
||||
src/utils/sync-helper.cpp
|
||||
src/utils/sync-helper.hpp
|
||||
src/utils/sync-helpers.cpp
|
||||
src/utils/sync-helpers.hpp
|
||||
src/utils/temp-variable.cpp
|
||||
src/utils/temp-variable.hpp
|
||||
src/utils/transition-selection.cpp
|
||||
src/utils/transition-selection.hpp
|
||||
src/utils/utility.cpp
|
||||
@@ -378,6 +396,12 @@ target_include_directories(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/deps/obs-websocket/lib"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/deps/exprtk")
|
||||
|
||||
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/deps/json/CMakeLists.txt")
|
||||
add_subdirectory(deps/json)
|
||||
else()
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
endif()
|
||||
target_link_libraries(${LIB_NAME} PUBLIC nlohmann_json::nlohmann_json)
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE ADVSS_EXPORT_SYMBOLS=1)
|
||||
|
||||
# --- End of section ---
|
||||
@@ -446,27 +470,24 @@ else()
|
||||
|
||||
find_path(PROCPS_INCLUDE_DIR NAMES proc/procps.h)
|
||||
find_path(PROCPS2_INCLUDE_DIR NAMES libproc2/pids.h)
|
||||
find_library(PROCPS_LIBRARY NAMES procps)
|
||||
find_library(PROCPS2_LIBRARY NAMES proc2)
|
||||
if(PROCPS_INCLUDE_DIR AND PROCPS_LIBRARY)
|
||||
if(PROCPS_INCLUDE_DIR)
|
||||
message(STATUS "${PROJECT_NAME} using procps")
|
||||
set(PROC_INCLUDE_DIR "${PROCPS_INCLUDE_DIR}")
|
||||
set(PROC_LIBRARY "${PROCPS_LIBRARY}")
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE USE_PROCPS)
|
||||
elseif(PROCPS2_INCLUDE_DIR AND PROCPS2_LIBRARY)
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS_AVAILABLE)
|
||||
set(PROCESS_CONDITION_SUPPORTED 1)
|
||||
endif()
|
||||
if(PROCPS2_INCLUDE_DIR)
|
||||
message(STATUS "${PROJECT_NAME} using libproc2")
|
||||
set(PROC_INCLUDE_DIR "${PROCPS2_INCLUDE_DIR}")
|
||||
set(PROC_LIBRARY "${PROCPS2_LIBRARY}")
|
||||
else()
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"found neither procps nor libproc2!
|
||||
please either set ...
|
||||
PROCPS_INCLUDE_DIR and PROCPS_LIBRARY
|
||||
... or ...
|
||||
PROCPS2_INCLUDE_DIR and PROCPS2_LIBRARY")
|
||||
target_compile_definitions(${LIB_NAME} PRIVATE PROCPS2_AVAILABLE)
|
||||
set(PROCESS_CONDITION_SUPPORTED 1)
|
||||
endif()
|
||||
if(NOT DEFINED PROCESS_CONDITION_SUPPORTED)
|
||||
message(
|
||||
WARNING
|
||||
"found neither procps nor libproc2! Process condition will not be functional!"
|
||||
)
|
||||
endif()
|
||||
target_link_libraries(${LIB_NAME} PRIVATE "${PROC_LIBRARY}")
|
||||
target_include_directories(${LIB_NAME} PRIVATE "${PROC_INCLUDE_DIR}")
|
||||
|
||||
find_package(CURL)
|
||||
|
||||
@@ -159,7 +159,6 @@ AdvSceneSwitcher.condition.media="Medien"
|
||||
AdvSceneSwitcher.condition.media.source="Quelle"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Beliebige Medienquelle in"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="Alle Medienquellen in"
|
||||
AdvSceneSwitcher.condition.media.matchOnChange="Nur bei Änderung übereinstimmen (Hinweis: Diese Option wird in einer zukünftigen Version entfernt werden - bitte stattdessen Dauer-Modifikatoren verwenden)"
|
||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="Leider verhalten sich nicht alle Medien-Quell-Typen gleich (z.B. Medien-Quelle vs. VLC-Video-Quelle \"Gestoppt\"-Status).\nBitte experimentieren, was in eurem Setup funktioniert!"
|
||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}Status ist{{states}}und{{timeRestrictions}}{{time}}"
|
||||
AdvSceneSwitcher.condition.video="Video"
|
||||
@@ -221,9 +220,8 @@ AdvSceneSwitcher.condition.record="Aufnahme"
|
||||
AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Aufnahme gestoppt"
|
||||
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||
AdvSceneSwitcher.condition.process="Prozess"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}} läuft {{focused}} und ist fokusiert"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}läuft{{focused}}und ist fokusiert"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="Aktueller Vordergrundprozess: {{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="Leerlauf"
|
||||
AdvSceneSwitcher.condition.idle.entry="Keine Tastatur- oder Mauseingaben für {{duration}}"
|
||||
@@ -325,7 +323,9 @@ AdvSceneSwitcher.condition.date.entry.nextMatchDate="Nächster Treffer bei: %1"
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} Bei Wiederholung ausgewähltes Datum auf Wiederholungsdatum aktualisieren"
|
||||
AdvSceneSwitcher.condition.sceneTransform="Szenenelement transformieren"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Transformation erhalten"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="Auf{{scenes}}{{sources}}passt zur Transformation"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="Auf{{scenes}}{{sources}}{{types}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.matches="entspricht Transformation"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.changed="hat sich geändert"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line2="{{settings}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}} {{getSettings}}"
|
||||
AdvSceneSwitcher.condition.transition="Übergang"
|
||||
@@ -389,7 +389,6 @@ AdvSceneSwitcher.condition.variable.type.valueChanged="Wert verändert"
|
||||
AdvSceneSwitcher.condition.variable.type.equalsVariable="entspricht Variable"
|
||||
AdvSceneSwitcher.condition.variable.type.lessThanVariable="ist kleiner als die Variable"
|
||||
AdvSceneSwitcher.condition.variable.type.greaterThanVariable="ist größer als die Variable"
|
||||
AdvSceneSwitcher.condition.variable.entry="{{variables}}{{conditions}}{{strValue}}{{numValue}}{{variables2}}"
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Szene wechseln"
|
||||
@@ -468,8 +467,7 @@ AdvSceneSwitcher.action.media.type.stop="Stoppen"
|
||||
AdvSceneSwitcher.action.media.type.restart="Neu starten"
|
||||
AdvSceneSwitcher.action.media.type.next="Nächste"
|
||||
AdvSceneSwitcher.action.media.type.previous="Vorherige"
|
||||
AdvSceneSwitcher.action.media.type.seek="Suche nach"
|
||||
AdvSceneSwitcher.action.media.entry="{{actions}}{{duration}}{{mediaSources}}"
|
||||
AdvSceneSwitcher.action.media.type.seek.duration="Suche nach"
|
||||
AdvSceneSwitcher.action.macro="Makro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pausieren"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Nicht mehr pausieren"
|
||||
@@ -575,7 +573,6 @@ AdvSceneSwitcher.action.variable.invalidSelection="Ungültige Auswahl!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Aktionen 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.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}"
|
||||
|
||||
|
||||
; Transition Tab
|
||||
@@ -713,7 +710,7 @@ AdvSceneSwitcher.sceneSequenceTab.loadFail="Laden der Einstellungen ist fehlgesc
|
||||
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="Laden der Einstellungen war erfolgreich!"
|
||||
AdvSceneSwitcher.sceneSequenceTab.fileType="Text Dateien (*.txt)"
|
||||
AdvSceneSwitcher.sceneSequenceTab.interruptible="kann unterbrochen werden"
|
||||
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Andere Szenenwechselmethoden können diese Sequenz unterbrechen"
|
||||
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Andere Szenenwechselmethoden können diese Sequenz unterbrechen"
|
||||
AdvSceneSwitcher.sceneSequenceTab.entry="Wenn {{startScenes}} aktiv ist wechsle zu {{scenes}} nach {{delay}} mit {{transitions}} {{interruptible}}"
|
||||
AdvSceneSwitcher.sceneSequenceTab.extendEdit="Szenenfolge erweitern"
|
||||
AdvSceneSwitcher.sceneSequenceTab.extendEntry="Nach {{delay}} wechsle zu {{scenes}} mit {{transitions}}"
|
||||
|
||||
@@ -79,6 +79,7 @@ AdvSceneSwitcher.macroTab.edit.action="Action type:"
|
||||
AdvSceneSwitcher.macroTab.add="Add new macro"
|
||||
AdvSceneSwitcher.macroTab.name="Name:"
|
||||
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.runElse="Run macro (else)"
|
||||
AdvSceneSwitcher.macroTab.runFail="Running \"%1\" failed!\nEither one of the actions failed or the macro is running already."
|
||||
AdvSceneSwitcher.macroTab.runInParallel="Run macro in parallel to other macros"
|
||||
@@ -125,6 +126,8 @@ AdvSceneSwitcher.macroTab.currentDockButtonText.unpause="Unpause button text:"
|
||||
AdvSceneSwitcher.macroTab.currentDockStatusText.true="Conditions true text:"
|
||||
AdvSceneSwitcher.macroTab.currentDockStatusText.false="Conditions false text:"
|
||||
AdvSceneSwitcher.macroTab.currentDockHighlightIfExecuted="Highlight dock if macro actions were recently executed"
|
||||
AdvSceneSwitcher.macroTab.toggleElseActions.hide.tooltip="Hide else actions"
|
||||
AdvSceneSwitcher.macroTab.toggleElseActions.show.tooltip="Show else actions"
|
||||
|
||||
AdvSceneSwitcher.macroDock.pause="Pause"
|
||||
AdvSceneSwitcher.macroDock.unpause="Unpause"
|
||||
@@ -204,7 +207,6 @@ AdvSceneSwitcher.condition.media="Media"
|
||||
AdvSceneSwitcher.condition.media.source="Source"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Any media source on"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="All media sources on"
|
||||
AdvSceneSwitcher.condition.media.matchOnChange="Only match on change (Note: This option will be removed in a future version - please use duration modifiers instead)"
|
||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="Unfortunately not all media source types behave the same (e.g. Media Source vs. VLC Video Source \"Stopped\" state).\nSo please experiment what works for your setup!"
|
||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}state is{{states}}and{{timeRestrictions}}{{time}}"
|
||||
AdvSceneSwitcher.condition.video="Video"
|
||||
@@ -295,9 +297,10 @@ AdvSceneSwitcher.condition.record="Recording"
|
||||
AdvSceneSwitcher.condition.record.state.start="Recording running"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Recording paused"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Recording stopped"
|
||||
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||
AdvSceneSwitcher.condition.record.state.duration="Recording duration is longer than"
|
||||
AdvSceneSwitcher.condition.record.entry="{{condition}}{{duration}}"
|
||||
AdvSceneSwitcher.condition.process="Process"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}is running{{focused}}and is focused"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}is running{{focused}}and is focused"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="Current foreground process:{{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="Idle"
|
||||
AdvSceneSwitcher.condition.idle.entry="No keyboard or mouse inputs for{{duration}}"
|
||||
@@ -326,6 +329,7 @@ AdvSceneSwitcher.condition.macro.type.state="Macro condition state"
|
||||
AdvSceneSwitcher.condition.macro.type.multiState="Multiple macro condition state"
|
||||
AdvSceneSwitcher.condition.macro.type.actionDisabled="Macro action disabled"
|
||||
AdvSceneSwitcher.condition.macro.type.actionEnabled="Macro action enabled"
|
||||
AdvSceneSwitcher.condition.macro.type.paused="Macro is paused"
|
||||
AdvSceneSwitcher.condition.macro.type.selection="{{types}}"
|
||||
AdvSceneSwitcher.condition.macro.count.type.below="Less than"
|
||||
AdvSceneSwitcher.condition.macro.count.type.above="More than"
|
||||
@@ -341,6 +345,7 @@ AdvSceneSwitcher.condition.macro.count.entry.line1="{{macros}}was executed{{cond
|
||||
AdvSceneSwitcher.condition.macro.count.entry.line2="Current count:{{currentCount}}{{resetCount}}"
|
||||
AdvSceneSwitcher.condition.macro.actionState.disabled.entry="Action{{actionIndex}}of{{macros}}is disabled"
|
||||
AdvSceneSwitcher.condition.macro.actionState.enabled.entry="Action{{actionIndex}}of{{macros}}is enabled"
|
||||
AdvSceneSwitcher.condition.macro.paused.entry="Macro{{macros}}is paused"
|
||||
AdvSceneSwitcher.condition.source="Source"
|
||||
AdvSceneSwitcher.condition.source.type.active="Is active"
|
||||
AdvSceneSwitcher.condition.source.type.showing="Is showing"
|
||||
@@ -407,7 +412,9 @@ AdvSceneSwitcher.condition.date.entry.nextMatchDate="Next match at: %1"
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}}On repeat update selected date to repeat date"
|
||||
AdvSceneSwitcher.condition.sceneTransform="Scene item transform"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Get transform"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="On{{scenes}}{{sources}}matches transform"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="On{{scenes}}{{sources}}{{types}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.matches="matches transform"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.changed="has changed"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line2="{{settings}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}}{{getSettings}}"
|
||||
AdvSceneSwitcher.condition.transition="Transition"
|
||||
@@ -461,6 +468,7 @@ AdvSceneSwitcher.condition.websocket.type.event="Scene Switcher Event"
|
||||
AdvSceneSwitcher.condition.websocket.useRegex="Use regular expressions"
|
||||
AdvSceneSwitcher.condition.websocket.entry.request="{{type}}was received:"
|
||||
AdvSceneSwitcher.condition.websocket.entry.event="{{type}}was received from{{connection}}:"
|
||||
AdvSceneSwitcher.condition.temporaryVariable="Macro property"
|
||||
AdvSceneSwitcher.condition.variable="Variable"
|
||||
AdvSceneSwitcher.condition.variable.type.compare="equals"
|
||||
AdvSceneSwitcher.condition.variable.type.empty="is empty"
|
||||
@@ -471,7 +479,7 @@ AdvSceneSwitcher.condition.variable.type.valueChanged="value changed"
|
||||
AdvSceneSwitcher.condition.variable.type.equalsVariable="equals variable"
|
||||
AdvSceneSwitcher.condition.variable.type.lessThanVariable="is less than variable"
|
||||
AdvSceneSwitcher.condition.variable.type.greaterThanVariable="is greater than variable"
|
||||
AdvSceneSwitcher.condition.variable.entry="{{variables}}{{conditions}}{{strValue}}{{numValue}}{{variables2}}"
|
||||
AdvSceneSwitcher.condition.variable.entry="{{variables}}{{conditions}}{{strValue}}{{numValue}}{{variables2}}{{regex}}"
|
||||
AdvSceneSwitcher.condition.run="Run"
|
||||
AdvSceneSwitcher.condition.run.entry="Process exits before timeout of{{timeout}}seconds"
|
||||
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Check for exit code{{exitCode}}"
|
||||
@@ -488,6 +496,62 @@ AdvSceneSwitcher.condition.slideshow.condition.slideIndex="Current slide number
|
||||
AdvSceneSwitcher.condition.slideshow.condition.slidePath="Current slide path is"
|
||||
AdvSceneSwitcher.condition.slideshow.updateIntervalTooltip="Information about the slide show status will only be updated based on the configured time between slides"
|
||||
AdvSceneSwitcher.condition.slideshow.entry="{{sources}}{{conditions}}{{index}}{{path}}"
|
||||
AdvSceneSwitcher.condition.twitch="Twitch"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online="Stream went online"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.offline="Stream went offline"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.info.update="Channel information updated"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.follow="Follow received"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.subscription.start="Subscription (no resubscriptions included) started"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.subscription.end="Subscription ended"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.subscription.gift="Subscription(s) gifted"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.subscription.message="Resubscription chat message received"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.cheer="Cheer chat message received"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.raid.outbound="Raided someone's channel"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.raid.inbound="Raid to your channel occured"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.shoutout.outbound="Shoutout to someone's channel given"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.shoutout.inbound="Shoutout to your channel received"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.poll.start="Poll started"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.poll.progress="Poll votes changed (progress)"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.poll.end="Poll ended"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.prediction.start="Prediction started"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.prediction.progress="Prediction bets changed (progress)"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.prediction.lock="Prediction bets locked"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.prediction.end="Prediction ended"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.goal.start="Goal started"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.goal.progress="Goal follow stats changed (progress)"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.goal.end="Goal ended"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.hypeTrain.start="Hype Train started"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.hypeTrain.progress="Hype Train stats changed (progress)"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.hypeTrain.end="Hype Train ended"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.charityCampaign.start="Charity campaign started"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.charityCampaign.progress="Charity campaign stats changed (progress)"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.charityCampaign.donation="Charity campaign donation occured"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.charityCampaign.end="Charity campaign ended"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.shieldMode.start="Shield Mode enabled"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.shieldMode.end="Shield Mode disabled"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.points.reward.addition="Points reward added"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.points.reward.update="Points reward updated"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.points.reward.deletion="Points reward deleted"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.points.reward.redemption="Points reward redeemed"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.points.reward.redemption.update="Points reward redemption updated"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.user.ban="User banned from channel"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.user.unban="User unbanned from channel"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.user.moderator.addition="User added as channel moderator"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.user.moderator.deletion="User deleted from channel moderation"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.live="Stream went live"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.playlist="Stream started playlist"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.watchParty="Stream started watchparty"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.premiere="Stream started premiere"
|
||||
AdvSceneSwitcher.condition.twitch.type.event.channel.stream.online.rerun="Stream started rerun"
|
||||
AdvSceneSwitcher.condition.twitch.type.polling.channel.live="Stream is currently live"
|
||||
AdvSceneSwitcher.condition.twitch.type.polling.channel.title="Current title matches"
|
||||
AdvSceneSwitcher.condition.twitch.type.polling.channel.category="Current category is"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.message="Chat message received"
|
||||
AdvSceneSwitcher.condition.twitch.categorySelectionDisabled="Cannot select category without selecting a Twitch account first!"
|
||||
AdvSceneSwitcher.condition.twitch.entry="Channel{{channel}}{{conditions}}{{pointsReward}}{{streamTitle}}{{regex}}{{category}}"
|
||||
AdvSceneSwitcher.condition.twitch.entry.account="Check using account{{account}}"
|
||||
AdvSceneSwitcher.condition.twitch.tokenPermissionsInsufficient="Permissions of selected token are insufficient to perform selected action!"
|
||||
AdvSceneSwitcher.condition.twitch.title.title="Enter title"
|
||||
|
||||
; Macro Actions
|
||||
AdvSceneSwitcher.action.scene="Switch scene"
|
||||
@@ -545,6 +609,7 @@ AdvSceneSwitcher.action.streaming.type.username="Set username"
|
||||
AdvSceneSwitcher.action.streaming.type.password="Set password"
|
||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
|
||||
AdvSceneSwitcher.action.run="Run"
|
||||
AdvSceneSwitcher.action.run.entry.wait="{{wait}}Wait for process exit or at most {{timeout}}"
|
||||
AdvSceneSwitcher.action.sceneVisibility="Scene item visibility"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.show="Show"
|
||||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
|
||||
@@ -558,7 +623,11 @@ AdvSceneSwitcher.action.filter.type.disable="Disable"
|
||||
AdvSceneSwitcher.action.filter.type.toggle="Toggle"
|
||||
AdvSceneSwitcher.action.filter.type.settings="Set settings"
|
||||
AdvSceneSwitcher.action.filter.entry="On{{sources}}{{actions}}{{filters}}"
|
||||
AdvSceneSwitcher.action.filter.entry.settings="{{settings}}{{settingsInputMethod}}{{settingValue}}{{tempVar}}"
|
||||
AdvSceneSwitcher.action.filter.getSettings="Get current settings"
|
||||
AdvSceneSwitcher.action.filter.inputMethod.individualManual="Set to fixed value"
|
||||
AdvSceneSwitcher.action.filter.inputMethod.individualTempvar="Set to macro property"
|
||||
AdvSceneSwitcher.action.filter.inputMethod.json="Set setting JSON string"
|
||||
AdvSceneSwitcher.action.source="Source"
|
||||
AdvSceneSwitcher.action.source.type.enable="Enable"
|
||||
AdvSceneSwitcher.action.source.type.disable="Disable"
|
||||
@@ -569,8 +638,11 @@ AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="Can be used to refr
|
||||
AdvSceneSwitcher.action.source.type.deinterlaceMode="Set deinterlace mode"
|
||||
AdvSceneSwitcher.action.source.type.deinterlaceOrder="Set deinterlace field order"
|
||||
AdvSceneSwitcher.action.source.type.openInteractionDialog="Open interaction dialog"
|
||||
AdvSceneSwitcher.action.source.type.openFilterDialog="Open filter 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}}"
|
||||
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.getSettings="Get current settings"
|
||||
AdvSceneSwitcher.action.source.deinterlaceMode.disable="Disable"
|
||||
@@ -584,6 +656,9 @@ AdvSceneSwitcher.action.source.deinterlaceMode.yadif="Yadif"
|
||||
AdvSceneSwitcher.action.source.deinterlaceMode.yadif2x="Yadif 2x"
|
||||
AdvSceneSwitcher.action.source.deinterlaceOrder.topFieldFirst="Top Field First"
|
||||
AdvSceneSwitcher.action.source.deinterlaceOrder.bottomFieldFirst="Bottom Field First"
|
||||
AdvSceneSwitcher.action.source.inputMethod.individualManual="Set to fixed value"
|
||||
AdvSceneSwitcher.action.source.inputMethod.individualTempvar="Set to macro property"
|
||||
AdvSceneSwitcher.action.source.inputMethod.json="Set setting JSON string"
|
||||
AdvSceneSwitcher.action.media="Media"
|
||||
AdvSceneSwitcher.action.media.type.play="Play"
|
||||
AdvSceneSwitcher.action.media.type.pause="Pause"
|
||||
@@ -591,8 +666,10 @@ AdvSceneSwitcher.action.media.type.stop="Stop"
|
||||
AdvSceneSwitcher.action.media.type.restart="Restart"
|
||||
AdvSceneSwitcher.action.media.type.next="Next"
|
||||
AdvSceneSwitcher.action.media.type.previous="Previous"
|
||||
AdvSceneSwitcher.action.media.type.seek="Seek to"
|
||||
AdvSceneSwitcher.action.media.entry="{{actions}}{{duration}}{{mediaSources}}"
|
||||
AdvSceneSwitcher.action.media.type.seek.duration="Seek to duration"
|
||||
AdvSceneSwitcher.action.media.type.seek.percentage="Seek to percentage"
|
||||
AdvSceneSwitcher.action.media.entry="{{actions}}{{seekDuration}}{{seekPercentage}}{{mediaSources}}"
|
||||
AdvSceneSwitcher.action.media.seek.percentage.label="Percentage of total duration of the media"
|
||||
AdvSceneSwitcher.action.macro="Macro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pause"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Unpause"
|
||||
@@ -740,6 +817,10 @@ AdvSceneSwitcher.action.variable.type.mathExpression="Mathematical expression"
|
||||
AdvSceneSwitcher.action.variable.type.askForValue="Get user input"
|
||||
AdvSceneSwitcher.action.variable.type.environmentVariable="Set to environment variable value"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemCount="Set to scene item count of scene"
|
||||
AdvSceneSwitcher.action.variable.type.stringLength="Set to length of string"
|
||||
AdvSceneSwitcher.action.variable.type.extractJson="Extract json field with name"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar="Set to macro property"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemName="Set to scene item name at index"
|
||||
AdvSceneSwitcher.action.variable.askForValuePromptDefault="Assign value to variable \"%1\":"
|
||||
AdvSceneSwitcher.action.variable.askForValuePrompt="Assign value to variable:"
|
||||
AdvSceneSwitcher.action.variable.mathExpression.example="( 1 + 2 * 3 ) / 4"
|
||||
@@ -751,7 +832,7 @@ AdvSceneSwitcher.action.variable.invalidSelection="Invalid selection!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Getting variable values from %1 actions is not supported!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Getting variable values from %1 conditions is not supported!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Current value:"
|
||||
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}"
|
||||
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{sceneItemIndex}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
|
||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{replaceStr}}"
|
||||
@@ -778,17 +859,34 @@ AdvSceneSwitcher.action.sceneLock.type.unlock="unlock"
|
||||
AdvSceneSwitcher.action.sceneLock.type.toggle="toggle lock of"
|
||||
AdvSceneSwitcher.action.sceneLock.entry="On{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.twitch="Twitch"
|
||||
AdvSceneSwitcher.action.twitch.type.title="Set stream title"
|
||||
AdvSceneSwitcher.action.twitch.type.category="Set stream category"
|
||||
AdvSceneSwitcher.action.twitch.type.marker="Create stream marker"
|
||||
AdvSceneSwitcher.action.twitch.type.clip="Create stream clip"
|
||||
AdvSceneSwitcher.action.twitch.type.commercial="Start commercial with duration"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.title.set="Set stream title"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.category.set="Set stream category"
|
||||
AdvSceneSwitcher.action.twitch.type.raid.start="Start raid"
|
||||
AdvSceneSwitcher.action.twitch.type.commercial.start="Start commercial"
|
||||
AdvSceneSwitcher.action.twitch.type.marker.create="Create stream marker"
|
||||
AdvSceneSwitcher.action.twitch.type.clip.create="Create stream clip"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.announcement.send="Send chat announcement"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Enable chat's emote-only mode"
|
||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Disable chat's emote-only mode"
|
||||
AdvSceneSwitcher.action.twitch.type.sendChatMessage="Send chat message"
|
||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Cannot select category without selecting a Twitch account first!"
|
||||
AdvSceneSwitcher.action.twitch.entry="On{{account}}{{actions}}{{streamTitle}}{{category}}{{manualCategorySearch}}{{markerDescription}}{{clipHasDelay}}{{duration}}"
|
||||
AdvSceneSwitcher.action.twitch.tokenPermissionsInsufficient="Permissions of selected token are insufficient to perform selected action!"
|
||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="Add a slight delay before capturing the clip"
|
||||
AdvSceneSwitcher.action.twitch.marker.description="Describe marker"
|
||||
AdvSceneSwitcher.action.twitch.entry.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
|
||||
AdvSceneSwitcher.action.twitch.entry.chat="Using account{{account}}{{actions}}on{{channel}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}"
|
||||
AdvSceneSwitcher.action.twitch.title.title="Enter title"
|
||||
AdvSceneSwitcher.action.twitch.marker.description="Describe marker"
|
||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="Add a slight delay before capturing the clip"
|
||||
AdvSceneSwitcher.action.twitch.announcement.message="Enter message"
|
||||
AdvSceneSwitcher.action.twitch.announcement.primary="Primary (channel's accent color)"
|
||||
AdvSceneSwitcher.action.twitch.announcement.blue="Blue"
|
||||
AdvSceneSwitcher.action.twitch.announcement.green="Green"
|
||||
AdvSceneSwitcher.action.twitch.announcement.orange="Orange"
|
||||
AdvSceneSwitcher.action.twitch.announcement.purple="Purple"
|
||||
AdvSceneSwitcher.action.clipboard="Clipboard"
|
||||
AdvSceneSwitcher.action.clipboard.type.copy.text="Copy text"
|
||||
AdvSceneSwitcher.action.clipboard.type.copy.image="Copy image"
|
||||
AdvSceneSwitcher.action.clipboard.copy.text.text.placeholder="Enter text"
|
||||
AdvSceneSwitcher.action.clipboard.copy.image.url.placeholder="Enter direct image URL"
|
||||
AdvSceneSwitcher.action.clipboard.copy.image.url.tooltip="Currently supported formats: PNG, JPG/JPEG, BMP, GIF."
|
||||
|
||||
; Hotkey
|
||||
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher"
|
||||
@@ -819,6 +917,8 @@ AdvSceneSwitcher.item.nameReserved="Name reserved!"
|
||||
|
||||
AdvSceneSwitcher.macroSegmentSelection.invalid="Invalid selection!"
|
||||
|
||||
AdvSceneSwitcher.validation.text.maxLength="Only %1 characters are allowed in this field!"
|
||||
|
||||
AdvSceneSwitcher.variable.select="--select variable--"
|
||||
AdvSceneSwitcher.variable.add="Add new variable"
|
||||
AdvSceneSwitcher.variable.configure="Configure variable settings"
|
||||
@@ -830,6 +930,8 @@ AdvSceneSwitcher.variable.save.dontSave="Don't save variable value"
|
||||
AdvSceneSwitcher.variable.save.save="Save variable value"
|
||||
AdvSceneSwitcher.variable.save.default="Set to value"
|
||||
|
||||
AdvSceneSwitcher.tooltip.availableVariables="Variables are supported, use ${VarName} to retrieve the value of VarName"
|
||||
|
||||
AdvSceneSwitcher.connection.select="--select connection--"
|
||||
AdvSceneSwitcher.connection.add="Add new connection"
|
||||
AdvSceneSwitcher.connection.configure="Configure connection settings"
|
||||
@@ -927,21 +1029,53 @@ AdvSceneSwitcher.twitchToken.add="Add new connection"
|
||||
AdvSceneSwitcher.twitchToken.configure="Configure Twitch connection settings"
|
||||
AdvSceneSwitcher.twitchToken.value="Token:"
|
||||
AdvSceneSwitcher.twitchToken.invalid="Invalid twitch token"
|
||||
AdvSceneSwitcher.twitchToken.request="Request token"
|
||||
AdvSceneSwitcher.twitchToken.request="Connect Account"
|
||||
AdvSceneSwitcher.twitchToken.request.waiting="Waiting for token approval ..."
|
||||
AdvSceneSwitcher.twitchToken.request.fail="Failed to get token!"
|
||||
AdvSceneSwitcher.twitchToken.request.fail.browser="Authentication failed! (%1)\nYou can close this window now."
|
||||
AdvSceneSwitcher.twitchToken.request.fail.stateMismatch="State mismatch"
|
||||
AdvSceneSwitcher.twitchToken.request.success="Successfully received token!"
|
||||
AdvSceneSwitcher.twitchToken.request.success.browser="Authentication successful! You can close this window now."
|
||||
AdvSceneSwitcher.twitchToken.request.notSet="No token set - Please request new token!"
|
||||
AdvSceneSwitcher.twitchToken.request.notSet="Account is not connected!"
|
||||
AdvSceneSwitcher.twitchToken.permissions="Token permissions:"
|
||||
AdvSceneSwitcher.twitchToken.analytics.readExtensions="View analytics data for the Twitch Extensions owned by the authenticated account."
|
||||
AdvSceneSwitcher.twitchToken.analytics.readGames="View analytics data for the games owned by the authenticated account."
|
||||
AdvSceneSwitcher.twitchToken.bits.read="View Bits information for a channel."
|
||||
AdvSceneSwitcher.twitchToken.channel.manageBroadcast="Manage a channel’s broadcast configuration, including updating channel configuration and managing stream markers and stream tags."
|
||||
AdvSceneSwitcher.twitchToken.channel.startCommercial="Run commercials on a channel."
|
||||
AdvSceneSwitcher.twitchToken.channel.createClip="Create clips from channel's broadcasts."
|
||||
AdvSceneSwitcher.twitchToken.permissionsInsufficient="Permissions of selected token are insufficient to perform selected action!"
|
||||
AdvSceneSwitcher.twitchToken.channel.broadcast.manage="Manage a channel’s broadcast configuration, including updating channel configuration and managing stream markers and stream tags."
|
||||
AdvSceneSwitcher.twitchToken.channel.subscriptions.read="Read channel's subscribers list and info."
|
||||
AdvSceneSwitcher.twitchToken.moderator.followers.read="Read the followers of a broadcaster."
|
||||
AdvSceneSwitcher.twitchToken.bits.read="Read channel's Bits information."
|
||||
AdvSceneSwitcher.twitchToken.channel.raids.manage="Manage channel's raids."
|
||||
AdvSceneSwitcher.twitchToken.moderator.shoutouts.read="Read channel's shoutouts."
|
||||
AdvSceneSwitcher.twitchToken.moderator.shoutouts.manage="Manage channel's shoutouts."
|
||||
AdvSceneSwitcher.twitchToken.channel.polls.read="Read channel's polls' state."
|
||||
AdvSceneSwitcher.twitchToken.channel.polls.manage="Manage channel's polls."
|
||||
AdvSceneSwitcher.twitchToken.channel.predictions.read="Read channel's predictions' state."
|
||||
AdvSceneSwitcher.twitchToken.channel.predictions.manage="Manage channel's predictions."
|
||||
AdvSceneSwitcher.twitchToken.channel.goals.read="Read channel's creator goals."
|
||||
AdvSceneSwitcher.twitchToken.channel.hypeTrain.read="Read channel's Hype Train state."
|
||||
AdvSceneSwitcher.twitchToken.channel.charity.read="Read channel's charity campaigns' state and donations."
|
||||
AdvSceneSwitcher.twitchToken.moderator.shieldMode.read="Read channel's Shield Mode state."
|
||||
AdvSceneSwitcher.twitchToken.moderator.shieldMode.manage="Manage channel's Shield Mode."
|
||||
AdvSceneSwitcher.twitchToken.channel.redemptions.read="Read channel's point rewards and their redemptions."
|
||||
AdvSceneSwitcher.twitchToken.channel.redemptions.manage="Manage channel's point rewards and their redemptions."
|
||||
AdvSceneSwitcher.twitchToken.channel.moderate="Moderate the channel."
|
||||
AdvSceneSwitcher.twitchToken.moderator.bannedUsers.manage="Manage channel's banned users."
|
||||
AdvSceneSwitcher.twitchToken.user.blockedUsers.manage="Manage user's blocked users."
|
||||
AdvSceneSwitcher.twitchToken.moderation.read="Read channel's moderation data."
|
||||
AdvSceneSwitcher.twitchToken.channel.moderators.manage="Manage channel's moderators."
|
||||
AdvSceneSwitcher.twitchToken.channel.vips.manage="Manage channel's VIPs."
|
||||
AdvSceneSwitcher.twitchToken.channel.commercial.edit="Run commercials on a channel."
|
||||
AdvSceneSwitcher.twitchToken.channel.ads.manage="Manage channel's commercials."
|
||||
AdvSceneSwitcher.twitchToken.clips.edit="Create clips from channel's broadcasts."
|
||||
AdvSceneSwitcher.twitchToken.moderator.announcements.manage="Manage channel's chat announcements."
|
||||
AdvSceneSwitcher.twitchToken.moderator.chat.settings.manage="Manage channel's chat settings, such as emote-only or slow mode."
|
||||
AdvSceneSwitcher.twitchToken.user.whispers.manage="Manage user's whispers."
|
||||
AdvSceneSwitcher.twitchToken.chat.read="View live stream chat messages."
|
||||
AdvSceneSwitcher.twitchToken.chat.edit="Send live stream chat messages."
|
||||
|
||||
AdvSceneSwitcher.twitch.selection.channel.open="Open channel"
|
||||
AdvSceneSwitcher.twitch.selection.channel.open.tooltip.details="Open channel in external application handling the HTTPS protocol."
|
||||
AdvSceneSwitcher.twitch.selection.channel.open.tooltip.noAccount="Unable to check if channel exists without selecting a Twitch account first!"
|
||||
AdvSceneSwitcher.twitch.selection.channel.open.tooltip.noChannel="Channel with specified name was not found!"
|
||||
|
||||
AdvSceneSwitcher.twitchCategories.fetchStart="Fetching stream categories ..."
|
||||
AdvSceneSwitcher.twitchCategories.fetchStatus="Got %1 stream categories."
|
||||
@@ -955,6 +1089,424 @@ AdvSceneSwitcher.twitchCategories.searchFailed="No new categories were found for
|
||||
AdvSceneSwitcher.twitchCategories.searchSuccess="%1 new categories were found for \"%2\" and were added to the list!"
|
||||
AdvSceneSwitcher.twitchCategories.select="--select category--"
|
||||
|
||||
AdvSceneSwitcher.twitch.selection.points.reward.placeholder="--select points reward--"
|
||||
AdvSceneSwitcher.twitch.selection.points.reward.refresh="Manually refresh the list"
|
||||
AdvSceneSwitcher.twitch.selection.points.reward.option.any="Any"
|
||||
AdvSceneSwitcher.twitch.selection.points.reward.tooltip.noAccount="Can't select points reward without selecting a Twitch account first!"
|
||||
AdvSceneSwitcher.twitch.selection.points.reward.tooltip.noPermission="Can't select points reward because of insufficient token permissions!"
|
||||
AdvSceneSwitcher.twitch.selection.points.reward.tooltip.noChannel="Can't select points reward without entering a channel first!"
|
||||
AdvSceneSwitcher.twitch.selection.points.reward.tooltip.error="Can't select points reward because Twitch responded with an error! Check OBS logs for more details."
|
||||
|
||||
AdvSceneSwitcher.tempVar.select="--select value--"
|
||||
AdvSceneSwitcher.tempVar.selectionInfo.lastValues="Last values:"
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.broadcaster_user_id="Twitch broadcaster user id"
|
||||
AdvSceneSwitcher.tempVar.twitch.broadcaster_user_id.description="The numerical Twitch user ID of the broadcaster."
|
||||
AdvSceneSwitcher.tempVar.twitch.broadcaster_user_login="Twitch broadcaster user login"
|
||||
AdvSceneSwitcher.tempVar.twitch.broadcaster_user_login.description="The Twitch user login of the broadcaster"
|
||||
AdvSceneSwitcher.tempVar.twitch.broadcaster_user_name="Twitch broadcaster user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.broadcaster_user_name.description="The Twitch user name of the broadcaster"
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.follow="Follower Twitch user id"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.follow.description="The user ID for the user now following the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.follow="Follower Twitch user login"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.follow.description="The user login for the user now following the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.follow="Follower Twitch user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.follow.description="The user display name for the user now following the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.followed_at="Twitch follow timestamp"
|
||||
AdvSceneSwitcher.tempVar.twitch.followed_at.description="The timestamp of when the Twitch follow event occurred"
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.id.stream.online="Twitch stream id"
|
||||
AdvSceneSwitcher.tempVar.twitch.type.stream.online="Twitch stream type"
|
||||
AdvSceneSwitcher.tempVar.twitch.type.stream.online.description="The stream type. Valid values are: live, playlist, watch_party, premiere, rerun."
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.stream.online="Twitch stream start timestamp"
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.stream.online.description="The timestamp at which the stream went online at."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.title="Twitch stream title"
|
||||
AdvSceneSwitcher.tempVar.twitch.language="Twitch stream language code"
|
||||
AdvSceneSwitcher.tempVar.twitch.language.description="The broadcaster’s preferred language. The value is an ISO 639-1 two-letter language code (for example, en for English). The value is set to “other” if the language is not a Twitch supported language."
|
||||
AdvSceneSwitcher.tempVar.twitch.category_id="Twitch stream category id"
|
||||
AdvSceneSwitcher.tempVar.twitch.category_id.description="Numerical id identifying each Twitch streaming category"
|
||||
AdvSceneSwitcher.tempVar.twitch.category_name="Twitch stream category name"
|
||||
AdvSceneSwitcher.tempVar.twitch.content_classification_labels="Twitch stream classification labels"
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.subscribe="Subscriber Twitch user id"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.subscribe.description="The user ID for the user now subscribed to the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.subscribe="Subscriber Twitch user login"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.subscribe.description="The user login for the user now subscribed to the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.subscribe="Subscriber Twitch user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.subscribe.description="The user display name for the user now subscribed to the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.tier.subscribe="Twitch subscriber tier"
|
||||
AdvSceneSwitcher.tempVar.twitch.tier.subscribe.description="The tier of the subscription. Valid values are 1000, 2000, and 3000."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_gift.subscribe="Is gifted Twitch subscription"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_gift.subscribe.description="Valid values are true and false."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.subscribe.end="Subscriber Twitch user id"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.subscribe.end.description="The user ID for the user no longer subscribed to the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.subscribe.end="Subscriber Twitch user login"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.subscribe.end.description="The user login for the user no longer subscribed to the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.subscribe.end="Subscriber Twitch user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.subscribe.end.description="The user display name for the user no longer subscribed to the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_gift.subscribe="Was gifted Twitch subscription"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_gift.subscribe.description="Valid values are true and false."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.subscribe.gift="Subscriber Twitch user id"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.subscribe.gift.description="The user ID of the user who sent the subscription gift. Set to null if it was an anonymous subscription gift."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.subscribe.gift="Subscriber Twitch user login"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.subscribe.gift.description="The user login of the user who sent the gift. Set to null if it was an anonymous subscription gift."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.subscribe.gift="Subscriber Twitch user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.subscribe.gift.description="The user display name of the user who sent the gift. Set to null if it was an anonymous subscription gift."
|
||||
AdvSceneSwitcher.tempVar.twitch.total.subscribe="Number of subscriptions"
|
||||
AdvSceneSwitcher.tempVar.twitch.total.subscribe.description="The number of subscriptions in the subscription gift."
|
||||
AdvSceneSwitcher.tempVar.twitch.cumulative_total.subscribe="Total gifted subscriptions"
|
||||
AdvSceneSwitcher.tempVar.twitch.cumulative_total.subscribe.description="The number of subscriptions gifted by this user in the channel. This value is null for anonymous gifts or if the gifter has opted out of sharing this information."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_anonymous.subscribe="Was anonymous Twitch subscription gift"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_anonymous.subscribe.description="Valid values are true and false."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.subscribe.message="Subscriber Twitch user id"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.subscribe.message.description="The user ID of the user who sent a resubscription chat message."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.subscribe.message="Subscriber Twitch user login"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.subscribe.message.description="The user login of the user who sent a resubscription chat message."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.subscribe.message="Subscriber Twitch user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.subscribe.message.description="The user display name of the user who a resubscription chat message."
|
||||
AdvSceneSwitcher.tempVar.twitch.message.subscribe="Subscription message"
|
||||
AdvSceneSwitcher.tempVar.twitch.message.subscribe.description="An object that contains the resubscription message and emote information needed to recreate the message."
|
||||
AdvSceneSwitcher.tempVar.twitch.cumulative_months.subscribe="Number of months subscribed"
|
||||
AdvSceneSwitcher.tempVar.twitch.cumulative_months.subscribe.description="The total number of months the user has been subscribed to the channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.streak_months.subscribe="Subscription streak"
|
||||
AdvSceneSwitcher.tempVar.twitch.streak_months.subscribe.description="The number of consecutive months the user’s current subscription has been active. This value is null if the user has opted out of sharing this information."
|
||||
AdvSceneSwitcher.tempVar.twitch.duration_months.subscribe="Subscription duration"
|
||||
AdvSceneSwitcher.tempVar.twitch.duration_months.subscribe.description="The month duration of the subscription."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.cheer="Cheerer Twitch user id"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.cheer.description="The user ID for the user who cheered on the specified channel. This is null if is_anonymous is true."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.cheer="Cheerer Twitch user login"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.cheer.description="The user login for the user who cheered on the specified channel. This is null if is_anonymous is true."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.cheer="Cheerer Twitch user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.cheer.description="The user display name for the user who cheered on the specified channel. This is null if is_anonymous is true."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_anonymous.cheer="Is anonymous cheer"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_anonymous.cheer.description="Whether the user cheered anonymously or not."
|
||||
AdvSceneSwitcher.tempVar.twitch.message.cheer="Cheer message"
|
||||
AdvSceneSwitcher.tempVar.twitch.message.cheer.description="The message sent with the cheer."
|
||||
AdvSceneSwitcher.tempVar.twitch.bits="Bits amount"
|
||||
AdvSceneSwitcher.tempVar.twitch.bits.description="The number of bits cheered."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.id.poll="Poll ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.id.poll.description="ID of the poll."
|
||||
AdvSceneSwitcher.tempVar.twitch.title.poll="Poll title"
|
||||
AdvSceneSwitcher.tempVar.twitch.title.poll.description="Question displayed for the poll."
|
||||
AdvSceneSwitcher.tempVar.twitch.choices.poll="Choices"
|
||||
AdvSceneSwitcher.tempVar.twitch.choices.poll.description="An array of choices for the poll."
|
||||
AdvSceneSwitcher.tempVar.twitch.choices.pollEnd="Choices"
|
||||
AdvSceneSwitcher.tempVar.twitch.choices.pollEnd.description="An array of choices for the poll. Includes vote counts."
|
||||
AdvSceneSwitcher.tempVar.twitch.channel_points_voting.description="Channel points voting setting"
|
||||
AdvSceneSwitcher.tempVar.twitch.channel_points_voting.description="The Channel Points voting settings for the poll."
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.poll="Poll start time"
|
||||
AdvSceneSwitcher.tempVar.twitch.ends_at.poll="Poll end time"
|
||||
AdvSceneSwitcher.tempVar.twitch.status.poll="Poll status"
|
||||
AdvSceneSwitcher.tempVar.twitch.status.poll.description="The status of the poll. Valid values are completed, archived, and terminated."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.id.prediction="Prediction ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.id.prediction.description="Channel Points Prediction ID."
|
||||
AdvSceneSwitcher.tempVar.twitch.title.prediction="Prediction title"
|
||||
AdvSceneSwitcher.tempVar.twitch.title.prediction.description="Title for the Channel Points Prediction."
|
||||
AdvSceneSwitcher.tempVar.twitch.outcomes.prediction="Prediction outcomes"
|
||||
AdvSceneSwitcher.tempVar.twitch.outcomes.prediction.description="An array of outcomes for the Channel Points Prediction. Includes top_predictors."
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.prediction="Prediction start time"
|
||||
AdvSceneSwitcher.tempVar.twitch.locks_at.prediction="Prediction lock time"
|
||||
AdvSceneSwitcher.tempVar.twitch.ended_at.prediction="Prediction end time"
|
||||
AdvSceneSwitcher.tempVar.twitch.status.prediction="Prediction status"
|
||||
AdvSceneSwitcher.tempVar.twitch.status.prediction.description="The status of the Channel Points Prediction. Valid values are resolved and canceled."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.id.goal="Goal ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.type.goal="Goal type"
|
||||
AdvSceneSwitcher.tempVar.twitch.type.goal.description="The type of goal. Possible values are:\n
|
||||
follow — The goal is to increase followers.\n
|
||||
subscription — The goal is to increase subscriptions. This type shows the net increase or decrease in tier points associated with the subscriptions.\n
|
||||
subscription_count — The goal is to increase subscriptions. This type shows the net increase or decrease in the number of subscriptions.\n
|
||||
new_subscription — The goal is to increase subscriptions. This type shows only the net increase in tier points associated with the subscriptions (it does not account for users that unsubscribed since the goal started).\n
|
||||
new_subscription_count — The goal is to increase subscriptions. This type shows only the net increase in the number of subscriptions (it does not account for users that unsubscribed since the goal started)."
|
||||
AdvSceneSwitcher.tempVar.twitch.description.goal="Goal description"
|
||||
AdvSceneSwitcher.tempVar.twitch.description.goal.description="A description of the goal, if specified. The description may contain a maximum of 40 characters."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_achieved.goal="Goal is achieved"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_achieved.goal.description="A Boolean value that indicates whether the broadcaster achieved their goal. Is true if the goal was achieved; otherwise, false."
|
||||
AdvSceneSwitcher.tempVar.twitch.current_amount.goal="Goal current amount"
|
||||
AdvSceneSwitcher.tempVar.twitch.current_amount.goal.description="The goal's current value.\n
|
||||
The goal's type determines how this value is increased or decreased.\n
|
||||
If type is follow, this field is set to the broadcaster's current number of followers. This number increases with new followers and decreases when users unfollow the broadcaster.\n
|
||||
If type is subscription, this field is increased and decreased by the points value associated with the subscription tier. For example, if a tier-two subscription is worth 2 points, this field is increased or decreased by 2, not 1.\n
|
||||
If type is subscription_count, this field is increased by 1 for each new subscription and decreased by 1 for each user that unsubscribes.\n
|
||||
If type is new_subscription, this field is increased by the points value associated with the subscription tier. For example, if a tier-two subscription is worth 2 points, this field is increased by 2, not 1.\n
|
||||
If type is new_subscription_count, this field is increased by 1 for each new subscription."
|
||||
AdvSceneSwitcher.tempVar.twitch.target_amount.goal="Goal target amount"
|
||||
AdvSceneSwitcher.tempVar.twitch.target_amount.goal.description="The goal's target value. For example, if the broadcaster has 200 followers before creating the goal, and their goal is to double that number, this field is set to 400."
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.goal="Goal start time"
|
||||
AdvSceneSwitcher.tempVar.twitch.ended_at.goal="Goal end time"
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.id.hype="Hype train ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.total.hype="Hype train total points"
|
||||
AdvSceneSwitcher.tempVar.twitch.total.hype.description="Total points contributed to the Hype Train."
|
||||
AdvSceneSwitcher.tempVar.twitch.progress.hype="Hype train progress"
|
||||
AdvSceneSwitcher.tempVar.twitch.progress.hype.description="The number of points contributed to the Hype Train at the current level."
|
||||
AdvSceneSwitcher.tempVar.twitch.goal.hype="Hype train goal"
|
||||
AdvSceneSwitcher.tempVar.twitch.goal.hype.description="The number of points required to reach the next level."
|
||||
AdvSceneSwitcher.tempVar.twitch.top_contributions.hype="Hype train top contributors"
|
||||
AdvSceneSwitcher.tempVar.twitch.top_contributions.hype.description="The contributors with the most points contributed."
|
||||
AdvSceneSwitcher.tempVar.twitch.last_contribution.hype="Hype train last contributor"
|
||||
AdvSceneSwitcher.tempVar.twitch.last_contribution.hype.description="The most recent contribution."
|
||||
AdvSceneSwitcher.tempVar.twitch.level.hype="Hype train level"
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.hype="Hype train start time"
|
||||
AdvSceneSwitcher.tempVar.twitch.expires_at.hype="Hype train expiration time"
|
||||
AdvSceneSwitcher.tempVar.twitch.ended_at.hype="Hype train end time"
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_ends_at.hype="Hype train cooldown"
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_ends_at.hype.description="The time when the Hype Train cooldown ends so that the next Hype Train can start."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_id.shoutout="User ID (shouted out)"
|
||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_id.shoutout.description="An ID that identifies the broadcaster that received the Shoutout."
|
||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_login.shoutout="User login (shouted out)"
|
||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_login.shoutout.description="The user login that identifies the broadcaster that received the Shoutout."
|
||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_name.shoutout="User name (shouted out)"
|
||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_name.shoutout.description="The user name that identifies the broadcaster that received the Shoutout."
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_id.shoutout="User ID triggering shouting out"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_id.shoutout.description="An ID that identifies the moderator that sent the Shoutout. If the broadcaster sent the Shoutout, this ID is the same as the ID in broadcaster_user_id."
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_login.shoutout="User login triggering shouting out"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_login.shoutout.description="The user login that identifies the moderator that sent the Shoutout. If the broadcaster sent the Shoutout, this ID is the same as the ID in broadcaster_user_id."
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_name.shoutout="User name triggering shouting out"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_name.shoutout.description="The user login that identifies the moderator that sent the Shoutout. If the broadcaster sent the Shoutout, this ID is the same as the ID in broadcaster_user_id."
|
||||
AdvSceneSwitcher.tempVar.twitch.viewer_count.shoutout="Viewer count"
|
||||
AdvSceneSwitcher.tempVar.twitch.viewer_count.shoutout.description="The number of users that were watching the broadcaster's stream at the time of the Shoutout."
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.shoutout="Shoutout start time"
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.shoutout.description="The UTC timestamp (in RFC3339 format) of when the moderator sent the Shoutout."
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_ends_at.shoutout="Shoutout cooldown end time"
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_ends_at.shoutout.description="The UTC timestamp (in RFC3339 format) of when the broadcaster may send a Shoutout to a different broadcaster."
|
||||
AdvSceneSwitcher.tempVar.twitch.target_cooldown_ends_at.shoutout="Shoutout target cooldown end time"
|
||||
AdvSceneSwitcher.tempVar.twitch.target_cooldown_ends_at.shoutout.description="The UTC timestamp (in RFC3339 format) of when the broadcaster may send another Shoutout to the selected broadcaster."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_id.shoutoutReceived="User ID shouting out"
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_id.shoutoutReceived.description="An ID that identifies the broadcaster that received the Shoutout."
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_login.shoutoutReceived="User login shouting out"
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_login.shoutoutReceived.description="The user login that identifies the broadcaster that received the Shoutout."
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_name.shoutoutReceived="User name shouting out"
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_name.shoutoutReceived.description="The user name that identifies the broadcaster that received the Shoutout."
|
||||
AdvSceneSwitcher.tempVar.twitch.viewer_count.shoutoutReceived="Viewer count"
|
||||
AdvSceneSwitcher.tempVar.twitch.viewer_count.shoutoutReceived.description="The number of users that were watching the from-broadcaster's stream at the time of the Shoutout."
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.shoutoutReceived="Shoutout time"
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.shoutoutReceived.description="The UTC timestamp (in RFC3339 format) of when the moderator sent the Shoutout."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.id.reward="Reward id"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.reward="User id redeeming the reward"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.reward="User login redeeming the reward"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.reward="User name redeeming the reward"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_input.reward="User input for reward"
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.reward="Reward Information"
|
||||
AdvSceneSwitcher.tempVar.twitch.reward.reward.description="Basic information about the reward that was redeemed, at the time it was redeemed."
|
||||
AdvSceneSwitcher.tempVar.twitch.status.reward="Reward status"
|
||||
AdvSceneSwitcher.tempVar.twitch.status.reward.description="Defaults to unfulfilled. Possible values are unknown, unfulfilled, fulfilled, and canceled."
|
||||
AdvSceneSwitcher.tempVar.twitch.redeemed_at.reward="Redemption time"
|
||||
AdvSceneSwitcher.tempVar.twitch.redeemed_at.reward.description="RFC3339 timestamp of when the reward was redeemed."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_enabled.reward="Reward is enabled"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_enabled.reward.description="Is the reward currently enabled. If false, the reward won’t show up to viewers."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_paused.reward="Reward is paused"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_paused.reward.description="Is the reward currently paused. If true, viewers can’t redeem."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_in_stock.reward="Reward is in stock"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_in_stock.reward.description="Is the reward currently in stock. If false, viewers can’t redeem."
|
||||
AdvSceneSwitcher.tempVar.twitch.title.reward="Reward title"
|
||||
AdvSceneSwitcher.tempVar.twitch.cost.reward="Reward cost"
|
||||
AdvSceneSwitcher.tempVar.twitch.prompt.reward="Reward description"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_user_input_required.reward="Reward requires user input"
|
||||
AdvSceneSwitcher.tempVar.twitch.should_redemptions_skip_request_queue.reward="Redemptions skip request queue"
|
||||
AdvSceneSwitcher.tempVar.twitch.should_redemptions_skip_request_queue.reward.description="Should redemptions be set to fulfilled status immediately when redeemed and skip the request queue instead of the normal unfulfilled status."
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_stream.reward="Reward maximum per stream"
|
||||
AdvSceneSwitcher.tempVar.twitch.max_per_user_per_stream.reward="Reward maximum per user per stream"
|
||||
AdvSceneSwitcher.tempVar.twitch.background_color.reward="Reward background color"
|
||||
AdvSceneSwitcher.tempVar.twitch.image.reward="Reward image"
|
||||
AdvSceneSwitcher.tempVar.twitch.image.reward.description="Set of custom images of 1x, 2x and 4x sizes for the reward. Can be null if no images have been uploaded."
|
||||
AdvSceneSwitcher.tempVar.twitch.default_image.reward="Reward default image"
|
||||
AdvSceneSwitcher.tempVar.twitch.default_image.reward.description="Set of default images of 1x, 2x and 4x sizes for the reward."
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.reward="Reward cooldown"
|
||||
AdvSceneSwitcher.tempVar.twitch.global_cooldown.reward.description="Whether a cooldown is enabled and what the cooldown is in seconds."
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_expires_at.reward="Reward cooldown expiration"
|
||||
AdvSceneSwitcher.tempVar.twitch.cooldown_expires_at.reward.description="Timestamp of the cooldown expiration. null if the reward isn’t on cooldown."
|
||||
AdvSceneSwitcher.tempVar.twitch.redemptions_redeemed_current_stream.reward="Redemption count"
|
||||
AdvSceneSwitcher.tempVar.twitch.redemptions_redeemed_current_stream.reward.description="The number of redemptions redeemed during the current live stream. Counts against the max_per_stream limit. null if the broadcasters stream isn’t live or max_per_stream isn’t enabled."
|
||||
AdvSceneSwitcher.tempVar.twitch.redemptions_redeemed_current_stream.reward.description="The number of redemptions redeemed during the current live stream. Counts against the max_per_stream limit. null if the broadcasters stream isn’t live or max_per_stream isn’t enabled."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.charity_name="Charity name"
|
||||
AdvSceneSwitcher.tempVar.twitch.charity_description="Charity description"
|
||||
AdvSceneSwitcher.tempVar.twitch.charity_logo="Charity logo"
|
||||
AdvSceneSwitcher.tempVar.twitch.charity_logo.description="A URL to an image of the charity’s logo. The image’s type is PNG and its size is 100px X 100px."
|
||||
AdvSceneSwitcher.tempVar.twitch.id.charity="Charity id"
|
||||
AdvSceneSwitcher.tempVar.twitch.id.charity.description="An ID that identifies the donation. The ID is unique across campaigns."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.charity="Donor user id"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.charity.description="An ID that identifies the user that donated to the campaign."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.charity="Donor login name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.charity.description="The user login that identifies the user that donated to the campaign."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.charity="Donor user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.charity.description="The user name that identifies the user that donated to the campaign."
|
||||
AdvSceneSwitcher.tempVar.twitch.amount.charity="Donation amount"
|
||||
AdvSceneSwitcher.tempVar.twitch.amount.charity.description="An object that contains the amount of money that the user donated."
|
||||
AdvSceneSwitcher.tempVar.twitch.current_amount.charity="Current donation amount"
|
||||
AdvSceneSwitcher.tempVar.twitch.current_amount.charity.description="An object that contains the current amount of donations that the campaign has received."
|
||||
AdvSceneSwitcher.tempVar.twitch.target_amount.charity="Charity target amount"
|
||||
AdvSceneSwitcher.tempVar.twitch.target_amount.charity.description="An object that contains the campaign’s target fundraising goal."
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.charity="Charity start date"
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.charity.description="The UTC timestamp (in RFC3339 format) of when the broadcaster started the charity campaign."
|
||||
AdvSceneSwitcher.tempVar.twitch.stopped_at.charity="Charity start date"
|
||||
AdvSceneSwitcher.tempVar.twitch.stopped_at.charity.description="The UTC timestamp (in RFC3339 format) of when the broadcaster stopped the campaign."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_id.shieldMode="Moderator user ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_id.shieldMode.description="An ID that identifies the moderator that updated the Shield Mode’s status. If the broadcaster updated the status, this ID will be the same as the broadcaster's ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_login.shieldMode="Moderator login name"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_login.shieldMode.description="Login name that identifies the moderator that updated the Shield Mode’s status. If the broadcaster updated the status, this login name will be the same as the broadcaster's login name"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_name.shieldMode="Moderator user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_name.shieldMode.description="User name that identifies the moderator that updated the Shield Mode’s status. If the broadcaster updated the status, this user name will be the same as the broadcaster's user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.shieldMode="Shield Mode start time"
|
||||
AdvSceneSwitcher.tempVar.twitch.started_at.shieldMode.description="The UTC timestamp (in RFC3339 format) of when the moderator activated Shield Mode."
|
||||
AdvSceneSwitcher.tempVar.twitch.ended_at.shieldMode="Shield Mode end time"
|
||||
AdvSceneSwitcher.tempVar.twitch.ended_at.shieldMode.description="The UTC timestamp (in RFC3339 format) of when the moderator deactivated Shield Mode."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.game_name="Game name"
|
||||
AdvSceneSwitcher.tempVar.twitch.game_name.description="The name of the game that the broadcaster is playing or last played. The value is an empty string if the broadcaster has never played a game."
|
||||
AdvSceneSwitcher.tempVar.twitch.game_id="Game ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.game_id.description="An ID that uniquely identifies the game that the broadcaster is playing or last played. The value is an empty string if the broadcaster has never played a game."
|
||||
AdvSceneSwitcher.tempVar.twitch.delay="Stream delay"
|
||||
AdvSceneSwitcher.tempVar.twitch.delay.description="The value of the broadcaster’s stream delay setting, in seconds.\nThis field’s value defaults to zero unless 1) the request specifies a user access token, 2) the ID in the broadcaster_id query parameter matches the user ID in the access token, and 3) the broadcaster has partner status and they set a non-zero stream delay value."
|
||||
AdvSceneSwitcher.tempVar.twitch.tags="Stream tags"
|
||||
AdvSceneSwitcher.tempVar.twitch.tags.description="The tags applied to the channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_mature="Is mature content"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_mature.description="A Boolean value that indicates whether the stream is meant for mature audiences."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_branded_content="Is branded content"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_branded_content.description="Boolean flag indicating if the channel has branded content."
|
||||
AdvSceneSwitcher.tempVar.twitch.thumbnail_url="Thumbnail URL"
|
||||
AdvSceneSwitcher.tempVar.twitch.thumbnail_url.description="A URL to an image of a frame from the last 5 minutes of the stream. Replace the width and height placeholders in the URL ({width}x{height}) with the size of the image you want, in pixels."
|
||||
AdvSceneSwitcher.tempVar.twitch.viewer_count.live="Viewer count"
|
||||
AdvSceneSwitcher.tempVar.twitch.viewer_count.live.description="The number of users watching the stream."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.ban="Banned user id"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.ban.description="The user ID for the user who was banned on the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.ban="Banned login name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.ban.description="The user login for the user who was banned on the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.ban="Banned user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.ban.description="The user display name for the user who was banned on the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_id.ban="Moderator user id"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_id.ban.description="The user ID of the issuer of the ban."
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_login.ban="Moderator login name"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_login.ban.description="The user login of the issuer of the ban."
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_name.ban="Moderator user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_name.ban.description="The user name of the issuer of the ban."
|
||||
AdvSceneSwitcher.tempVar.twitch.reason.ban="Ban reason"
|
||||
AdvSceneSwitcher.tempVar.twitch.ends_at.ban="Ban end date"
|
||||
AdvSceneSwitcher.tempVar.twitch.ends_at.ban.description="The UTC date and time (in RFC3339 format) of when the timeout ends. Is null if the user was banned instead of put in a timeout."
|
||||
AdvSceneSwitcher.tempVar.twitch.is_permanent.ban="Is permanent ban"
|
||||
AdvSceneSwitcher.tempVar.twitch.is_permanent.ban.description="Indicates whether the ban is permanent (true) or a timeout (false). If true, ends_at will be null."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.unban="Banned user id"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.unban.description="The user ID for the user who was unbanned on the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.unban="Banned login name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.unban.description="The user login for the user who was unbanned on the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.unban="Banned user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.unban.description="The user display name for the user who was unbanned on the specified channel."
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_id.unban="Moderator user id"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_id.unban.description="The user ID of the issuer of the unban."
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_login.unban="Moderator login name"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_login.unban.description="The user login of the issuer of the unban."
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_name.unban="Moderator user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.moderator_user_name.unban.description="The user name of the issuer of the unban."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.addMod="User id"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.addMod.description="The user ID of the new moderator."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.addMod="Login name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.addMod.description="The user login of the new moderator."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.addMod="User name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.addMod.description="The display name of the new moderator."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.removeMod="User id"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_id.removeMod.description="The user ID of the removed moderator."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.removeMod="Login name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.removeMod.description="The user login of the removed moderator."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.removeMod="User name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.removeMod.description="The display name of the removed moderator."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.chatter="User login"
|
||||
AdvSceneSwitcher.tempVar.twitch.chatter.description="The user login of the person who sent the chat message."
|
||||
AdvSceneSwitcher.tempVar.twitch.chat_message="Chat message"
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_id.raid="Raid creator user ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_id.raid.description="The broadcaster ID that created the raid."
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_login.raid="Raid creator user login"
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_login.raid.description="The broadcaster login that created the raid."
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_name.raid="Raid creator user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_name.raid.description="The broadcaster display name that created the raid."
|
||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_id.raid="Raid receiver user ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_id.raid.description="The broadcaster ID that created the raid."
|
||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_login.raid="Raid receiver user login"
|
||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_login.raid.description="The broadcaster login that created the raid."
|
||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_name.raid="Raid receiver user name"
|
||||
AdvSceneSwitcher.tempVar.twitch.to_broadcaster_user_name.raid.description="The broadcaster display name that created the raid."
|
||||
AdvSceneSwitcher.tempVar.twitch.viewers.raid="Raid participants"
|
||||
AdvSceneSwitcher.tempVar.twitch.viewers.raid.description="The number of viewers in the raid."
|
||||
|
||||
AdvSceneSwitcher.tempVar.audio.output_volume="Output volume"
|
||||
AdvSceneSwitcher.tempVar.audio.output_volume.description="The volume the audio source is outputting."
|
||||
AdvSceneSwitcher.tempVar.audio.configured_volume="Configured volume"
|
||||
AdvSceneSwitcher.tempVar.audio.configured_volume.description="The volume level configured for the source."
|
||||
AdvSceneSwitcher.tempVar.audio.muted="Source muted"
|
||||
AdvSceneSwitcher.tempVar.audio.sync_offset="Source audio sync offset"
|
||||
AdvSceneSwitcher.tempVar.audio.monitor="Source audio monitor type"
|
||||
AdvSceneSwitcher.tempVar.audio.balance="Source audio balance"
|
||||
|
||||
AdvSceneSwitcher.tempVar.clipboard.mimeType.primary="Primary clipboard item MIME type"
|
||||
AdvSceneSwitcher.tempVar.clipboard.mimeType.primary.description="Highest priority MIME type of the current item stored in clipboard, if available."
|
||||
AdvSceneSwitcher.tempVar.clipboard.mimeType.all="All clipboard item MIME types"
|
||||
AdvSceneSwitcher.tempVar.clipboard.mimeType.all.description="All MIME types of the current item stored in clipboard separated with space, if available."
|
||||
|
||||
AdvSceneSwitcher.tempVar.scene.current="Current scene"
|
||||
AdvSceneSwitcher.tempVar.scene.previous="Previous scene"
|
||||
AdvSceneSwitcher.tempVar.scene.preview="Preview scene"
|
||||
|
||||
AdvSceneSwitcher.tempVar.window.window="Window title"
|
||||
AdvSceneSwitcher.tempVar.window.window.description="The window title of the current foreground window."
|
||||
|
||||
AdvSceneSwitcher.tempVar.timer.seconds="Seconds"
|
||||
AdvSceneSwitcher.tempVar.timer.minutes="Minutes"
|
||||
AdvSceneSwitcher.tempVar.timer.hours="Hours"
|
||||
AdvSceneSwitcher.tempVar.timer.days="Days"
|
||||
|
||||
AdvSceneSwitcher.tempVar.date.year="Year"
|
||||
AdvSceneSwitcher.tempVar.date.month="Month"
|
||||
AdvSceneSwitcher.tempVar.date.day="Day"
|
||||
AdvSceneSwitcher.tempVar.date.hour="Hour"
|
||||
AdvSceneSwitcher.tempVar.date.minute="Minute"
|
||||
AdvSceneSwitcher.tempVar.date.second="Second"
|
||||
AdvSceneSwitcher.tempVar.date.dayOfWeek="Day of week"
|
||||
|
||||
AdvSceneSwitcher.tempVar.midi.type="Message type"
|
||||
AdvSceneSwitcher.tempVar.midi.channel="Channel"
|
||||
AdvSceneSwitcher.tempVar.midi.note="Note"
|
||||
AdvSceneSwitcher.tempVar.midi.value1="Value 1"
|
||||
AdvSceneSwitcher.tempVar.midi.value2="Value 2"
|
||||
|
||||
AdvSceneSwitcher.tempVar.macro.runCount="Run count"
|
||||
AdvSceneSwitcher.tempVar.macro.runCount.description="The number of times a macro was executed."
|
||||
AdvSceneSwitcher.tempVar.macro.matchedCount="Matched count"
|
||||
AdvSceneSwitcher.tempVar.macro.matchedCount.description="The number of macros of which the condition state was true."
|
||||
|
||||
AdvSceneSwitcher.tempVar.process.name="Process name"
|
||||
|
||||
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.video.patternCount="Pattern count"
|
||||
AdvSceneSwitcher.tempVar.video.patternCount.description="The number of times the given pattern has been found in a given video input frame."
|
||||
AdvSceneSwitcher.tempVar.video.objectCount="Object count"
|
||||
AdvSceneSwitcher.tempVar.video.objectCount.description="The number of objects the given model has identified in a given video input frame."
|
||||
AdvSceneSwitcher.tempVar.video.brightness="Average brightness"
|
||||
AdvSceneSwitcher.tempVar.video.brightness.description="The average brightness in a given video input frame in a range from 0 to 1 (dark to bright)."
|
||||
AdvSceneSwitcher.tempVar.video.text="OCR text"
|
||||
AdvSceneSwitcher.tempVar.video.text.description="The text detected in a given video input frame."
|
||||
AdvSceneSwitcher.tempVar.video.color="Average color"
|
||||
AdvSceneSwitcher.tempVar.video.color.description="The average RGB color in a given video input frame in HexArgb format."
|
||||
|
||||
AdvSceneSwitcher.selectScene="--select scene--"
|
||||
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
||||
AdvSceneSwitcher.selectCurrentScene="Current Scene"
|
||||
@@ -980,6 +1532,7 @@ AdvSceneSwitcher.enterText="--enter text--"
|
||||
AdvSceneSwitcher.enterURL="--enter URL--"
|
||||
AdvSceneSwitcher.selectHotkey="--select hotkey--"
|
||||
AdvSceneSwitcher.selectDisplay="--select display--"
|
||||
AdvSceneSwitcher.selectSetting="--select setting--"
|
||||
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved"
|
||||
AdvSceneSwitcher.selectWindowTip="Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB"
|
||||
|
||||
@@ -1001,6 +1554,8 @@ AdvSceneSwitcher.sceneItemSelection.type.all.entry="All sources"
|
||||
AdvSceneSwitcher.sceneItemSelection.all="All"
|
||||
AdvSceneSwitcher.sceneItemSelection.any="Any"
|
||||
|
||||
AdvSceneSwitcher.filterSelection.all="All filters"
|
||||
|
||||
AdvSceneSwitcher.status.active="Active"
|
||||
AdvSceneSwitcher.status.inactive="Inactive"
|
||||
AdvSceneSwitcher.running="Plugin running"
|
||||
|
||||
@@ -41,17 +41,17 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportar los a
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importar los ajustes para Advanced Scene Switcher ..."
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Archivos de texto (*.txt)"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="La importacion la configuracion de escenas fallo"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Configuración de escenas importada correctamente"
|
||||
AdvSceneSwitcher.generalTab.priority.fileContent="Contenido del archivo"
|
||||
AdvSceneSwitcher.generalTab.priority.sceneSequence="Secuencia de escenas"
|
||||
AdvSceneSwitcher.generalTab.priority.idleDetection="Detección de inactivos"
|
||||
AdvSceneSwitcher.generalTab.priority.executable="Ejecutable"
|
||||
AdvSceneSwitcher.generalTab.priority.screenRegion="Región de pantalla"
|
||||
AdvSceneSwitcher.generalTab.priority.windowTitle="Título de la ventana"
|
||||
AdvSceneSwitcher.generalTab.priority.media="Medios"
|
||||
AdvSceneSwitcher.generalTab.priority.time="Tiempo"
|
||||
AdvSceneSwitcher.generalTab.priority.audio="Audio"
|
||||
AdvSceneSwitcher.generalTab.priority.video="Video"
|
||||
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Configuración de escenas importada correctamente"
|
||||
AdvSceneSwitcher.generalTab.priority.fileContent="Contenido del archivo"
|
||||
AdvSceneSwitcher.generalTab.priority.sceneSequence="Secuencia de escenas"
|
||||
AdvSceneSwitcher.generalTab.priority.idleDetection="Detección de inactivos"
|
||||
AdvSceneSwitcher.generalTab.priority.executable="Ejecutable"
|
||||
AdvSceneSwitcher.generalTab.priority.screenRegion="Región de pantalla"
|
||||
AdvSceneSwitcher.generalTab.priority.windowTitle="Título de la ventana"
|
||||
AdvSceneSwitcher.generalTab.priority.media="Medios"
|
||||
AdvSceneSwitcher.generalTab.priority.time="Tiempo"
|
||||
AdvSceneSwitcher.generalTab.priority.audio="Audio"
|
||||
AdvSceneSwitcher.generalTab.priority.video="Video"
|
||||
AdvSceneSwitcher.generalTab.priority.macro="Macro"
|
||||
AdvSceneSwitcher.generalTab.setTransitionBy="Al cambiar las transiciones:"
|
||||
AdvSceneSwitcher.generalTab.transitionOverride="Establecer anulaciones de transición"
|
||||
@@ -61,38 +61,38 @@ AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="Al menos una opci
|
||||
; Macro Tab
|
||||
AdvSceneSwitcher.macroTab.title="Macro"
|
||||
AdvSceneSwitcher.macroTab.macros="Macros"
|
||||
AdvSceneSwitcher.macroTab.priorityWarning="Nota: Se recomienda configurar las macros para que sean la funcionalidad de máxima prioridad.\nEsta configuración se puede cambiar en la ficha General."
|
||||
AdvSceneSwitcher.macroTab.help="Las macros le permiten ejecutar una cadena de acciones en función de varias condiciones.\n\nHaga clic en el símbolo más resaltado para agregar una nueva macro."
|
||||
AdvSceneSwitcher.macroTab.editConditionHelp="Esta sección le permite definir las condiciones de la macro.\n\nSeleccione una macro existente o agregue una nueva a la izquierda.\nLuego haga clic en el botón más a continuación para agregar una nueva condición."
|
||||
AdvSceneSwitcher.macroTab.priorityWarning="Nota: Se recomienda configurar las macros para que sean la funcionalidad de máxima prioridad.\nEsta configuración se puede cambiar en la ficha General."
|
||||
AdvSceneSwitcher.macroTab.help="Las macros le permiten ejecutar una cadena de acciones en función de varias condiciones.\n\nHaga clic en el símbolo más resaltado para agregar una nueva macro."
|
||||
AdvSceneSwitcher.macroTab.editConditionHelp="Esta sección le permite definir las condiciones de la macro.\n\nSeleccione una macro existente o agregue una nueva a la izquierda.\nLuego haga clic en el botón más a continuación para agregar una nueva condición."
|
||||
AdvSceneSwitcher.macroTab.editActionHelp="Esta sección le permite definir acciones de la macro.\n\nSeleccione una macro existente o agregue una nueva a la izquierda.\nLuego haga clic en el botón más a continuación para agregar una nueva acción"
|
||||
AdvSceneSwitcher.macroTab.edit="Editar macro"
|
||||
AdvSceneSwitcher.macroTab.edit.logic="Tipo de lógica:"
|
||||
AdvSceneSwitcher.macroTab.edit.condition="Tipo de condición:"
|
||||
AdvSceneSwitcher.macroTab.edit.logic="Tipo de lógica:"
|
||||
AdvSceneSwitcher.macroTab.edit.condition="Tipo de condición:"
|
||||
AdvSceneSwitcher.macroTab.edit.action="Tipo de acción:"
|
||||
AdvSceneSwitcher.macroTab.add="Agregar nueva macro"
|
||||
AdvSceneSwitcher.macroTab.name="Nombre:"
|
||||
AdvSceneSwitcher.macroTab.run="Ejecutar macro"
|
||||
AdvSceneSwitcher.macroTab.runFail="Error al ejecutar \"%1\" si se ha producido un error en una de las acciones o si la macro ya se está ejecutando."
|
||||
AdvSceneSwitcher.macroTab.runInParallel="Ejecutar macro en paralelo a otras macros"
|
||||
AdvSceneSwitcher.macroTab.onChange="Realizar acciones solo en el cambio de condición"
|
||||
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
||||
AdvSceneSwitcher.macroTab.exists="El nombre de la macro ya existe"
|
||||
AdvSceneSwitcher.macroTab.copy="Crear copia"
|
||||
AdvSceneSwitcher.macroTab.expandAll="Expandir todo"
|
||||
AdvSceneSwitcher.macroTab.collapseAll="Contraer todo"
|
||||
AdvSceneSwitcher.macroTab.maximize="Maximizar"
|
||||
AdvSceneSwitcher.macroTab.add="Agregar nueva macro"
|
||||
AdvSceneSwitcher.macroTab.name="Nombre:"
|
||||
AdvSceneSwitcher.macroTab.run="Ejecutar macro"
|
||||
AdvSceneSwitcher.macroTab.runFail="Error al ejecutar \"%1\" si se ha producido un error en una de las acciones o si la macro ya se está ejecutando."
|
||||
AdvSceneSwitcher.macroTab.runInParallel="Ejecutar macro en paralelo a otras macros"
|
||||
AdvSceneSwitcher.macroTab.onChange="Realizar acciones solo en el cambio de condición"
|
||||
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
||||
AdvSceneSwitcher.macroTab.exists="El nombre de la macro ya existe"
|
||||
AdvSceneSwitcher.macroTab.copy="Crear copia"
|
||||
AdvSceneSwitcher.macroTab.expandAll="Expandir todo"
|
||||
AdvSceneSwitcher.macroTab.collapseAll="Contraer todo"
|
||||
AdvSceneSwitcher.macroTab.maximize="Maximizar"
|
||||
AdvSceneSwitcher.macroTab.minimize="Minimizar"
|
||||
AdvSceneSwitcher.macroTab.highlightExecutedMacros="Resaltar macros ejecutadas recientemente"
|
||||
AdvSceneSwitcher.macroTab.highlightTrueConditions="Resaltar condiciones de la macro seleccionada, que se evaluaron como verdaderas recientemente"
|
||||
AdvSceneSwitcher.macroTab.highlightPerformedActions="Resaltar acciones realizadas recientemente de la macro seleccionada actualmente"
|
||||
AdvSceneSwitcher.macroTab.highlightExecutedMacros="Resaltar macros ejecutadas recientemente"
|
||||
AdvSceneSwitcher.macroTab.highlightTrueConditions="Resaltar condiciones de la macro seleccionada, que se evaluaron como verdaderas recientemente"
|
||||
AdvSceneSwitcher.macroTab.highlightPerformedActions="Resaltar acciones realizadas recientemente de la macro seleccionada actualmente"
|
||||
|
||||
; Lógica de macros
|
||||
AdvSceneSwitcher.logic.none="Omitir entrada"
|
||||
AdvSceneSwitcher.logic.and="Y"
|
||||
AdvSceneSwitcher.logic.or="O"
|
||||
AdvSceneSwitcher.logic.andNot="Y no"
|
||||
AdvSceneSwitcher.logic.orNot="O no"
|
||||
AdvSceneSwitcher.logic.rootNone="Si"
|
||||
; Lógica de macros
|
||||
AdvSceneSwitcher.logic.none="Omitir entrada"
|
||||
AdvSceneSwitcher.logic.and="Y"
|
||||
AdvSceneSwitcher.logic.or="O"
|
||||
AdvSceneSwitcher.logic.andNot="Y no"
|
||||
AdvSceneSwitcher.logic.orNot="O no"
|
||||
AdvSceneSwitcher.logic.rootNone="Si"
|
||||
AdvSceneSwitcher.logic.not="Si no"
|
||||
|
||||
; Macro Conditions
|
||||
@@ -129,7 +129,6 @@ AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFil
|
||||
AdvSceneSwitcher.condition.media="Medios"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Cualquier fuente multimedia activada"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="Todas las fuentes de medios activadas"
|
||||
AdvSceneSwitcher.condition.media.matchOnChange="Solo coincidir con el cambio (Nota: esta opción se eliminará en una versión futura; use modificadores de duración en su lugar)"
|
||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="Desafortunadamente, no todos los tipos de fuentes de medios se comportan de la misma manera (p. ej., fuente de medios frente a estado \"Detenido\" de fuente de video VLC).\n¡Así que experimente lo que funciona para su configuración!"
|
||||
AdvSceneSwitcher.condition.media.entry="El estado de{{sourceTypes}}{{mediaSources}}{{scenes}}es{{states}}y{{timeRestrictions}}{{time}}"
|
||||
AdvSceneSwitcher.condition.video="Video"
|
||||
@@ -182,9 +181,8 @@ AdvSceneSwitcher.condition.record="Grabación"
|
||||
AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Grabación detenida"
|
||||
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||
AdvSceneSwitcher.condition.process="Proceso"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}} se está ejecutando {{focused}} y está enfocado"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}se está ejecutando{{focused}}y está enfocado"
|
||||
AdvSceneSwitcher.condition.idle="Inactivo"
|
||||
AdvSceneSwitcher.condition.idle.entry="No hay entradas de teclado o ratón durante {{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Estado del complemento"
|
||||
@@ -275,7 +273,8 @@ AdvSceneSwitcher.condition.date.entry.nextMatchDate="Próxima coincidencia en: %
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} Al repetir actualizar la fecha seleccionada para repetir la fecha"
|
||||
AdvSceneSwitcher.condition.sceneTransform="Transformar elemento de escena"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtener transformación"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="En{{scenes}}{{sources}}coincide con la transformación"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="En{{scenes}}{{sources}}{{types}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.matches="coincide con la transformación"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line2="{{settings}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}} {{getSettings}}"
|
||||
AdvSceneSwitcher.condition.transition="Transición"
|
||||
@@ -386,8 +385,7 @@ AdvSceneSwitcher.action.media.type.stop="Detener"
|
||||
AdvSceneSwitcher.action.media.type.restart="Reiniciar"
|
||||
AdvSceneSwitcher.action.media.type.next="Siguiente"
|
||||
AdvSceneSwitcher.action.media.type.previous="Anterior"
|
||||
AdvSceneSwitcher.action.media.type.seek="Buscar"
|
||||
AdvSceneSwitcher.action.media.entry="{{actions}}{{duration}}{{mediaSources}}"
|
||||
AdvSceneSwitcher.action.media.type.seek.duration="Buscar"
|
||||
AdvSceneSwitcher.action.macro="Macro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pausa"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Reanudar"
|
||||
@@ -566,7 +564,7 @@ AdvSceneSwitcher.fileTab.help="Esta pestaña te permitirá cambiar escenas autom
|
||||
; Random Tab
|
||||
AdvSceneSwitcher.randomTab.title="Aleatorio"
|
||||
AdvSceneSwitcher.randomTab.randomDisabledWarning="Funcionalidad deshabilitada - para activarla, selecciona \"Si no se cumple ninguna condición de cambio, cambiar a cualquier escena en la pestaña Aleatorio\" en la pestaña General"
|
||||
AdvSceneSwitcher.randomTab.entry="Si no se cumple ninguna condición de cambio, cambiar a {{scenes}} usando {{transitions}} después de {{delay}}"
|
||||
AdvSceneSwitcher.randomTab.entry="Si no se cumple ninguna condición de cambio, cambiar a {{scenes}} usando {{transitions}} después de {{delay}}"
|
||||
AdvSceneSwitcher.randomTab.help="El selector de escenas elegirá aleatoriamente una entrada en esta pestaña para cambiar durante el tiempo configurado.\nTen en cuenta que la misma entrada no se elegirá dos veces seguidas.\n\nHaz clic en el símbolo más resaltado para continuar."
|
||||
|
||||
; Time Tab
|
||||
|
||||
@@ -197,7 +197,6 @@ AdvSceneSwitcher.condition.media="Média"
|
||||
AdvSceneSwitcher.condition.media.source="Source"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Toute source média sur la scène"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="Toutes les sources média sur la scène"
|
||||
AdvSceneSwitcher.condition.media.matchOnChange="Ne correspondre qu'au changement (Remarque : Cette option sera supprimée dans une version future - veuillez plutôt utiliser les modificateurs de durée)"
|
||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="Malheureusement, toutes les sources média ne se comportent pas de la même manière (par exemple, l'état \"Arrêté\" de la source Media par rapport à la source Vidéo VLC).\nPar conséquent, veuillez expérimenter ce qui fonctionne le mieux pour votre configuration !"
|
||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}l'état est{{states}}et{{timeRestrictions}}{{time}}"
|
||||
AdvSceneSwitcher.condition.video="Vidéo"
|
||||
@@ -286,7 +285,7 @@ AdvSceneSwitcher.condition.record.state.start="Enregistrement en cours"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Enregistrement en pause"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Arrêt de l'enregistrement"
|
||||
AdvSceneSwitcher.condition.process="Processus"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}en cours d'exécution{{focused}}et est au premier plan"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}en cours d'exécution{{focused}}et est au premier plan"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="Processus au premier plan actuel :{{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="Inactif"
|
||||
AdvSceneSwitcher.condition.idle.entry="Aucune entrée de clavier ou de souris pendant{{duration}}"
|
||||
@@ -355,7 +354,7 @@ AdvSceneSwitcher.condition.hotkey="Raccourci clavier"
|
||||
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.entry.line1="Raccourci clavier est enfoncé"
|
||||
AdvSceneSwitcher.condition.hotkey.entry.line2="Nom : {{name}}"
|
||||
AdvSceneSwitcher.condition.hotkey.entry.line2="Nom :{{name}}"
|
||||
AdvSceneSwitcher.condition.replay="Tampon de répétition"
|
||||
AdvSceneSwitcher.condition.replay.state.stopped="Tampon de répétition arrêté"
|
||||
AdvSceneSwitcher.condition.replay.state.started="Tampon de répétition démarré"
|
||||
@@ -386,7 +385,8 @@ AdvSceneSwitcher.condition.date.entry.nextMatchDate="Prochaine correspondance à
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}}À la répétition, mettre à jour la date sélectionnée pour la date de répétition"
|
||||
AdvSceneSwitcher.condition.sceneTransform="Transformation de l'élément de la scène"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtenir la transformation"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="Sur{{scenes}}{{sources}}correspond à la transformation"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="Sur{{scenes}}{{sources}}{{types}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.matches="correspond à la transformation"
|
||||
AdvSceneSwitcher.condition.transition="Transition"
|
||||
AdvSceneSwitcher.condition.transition.type.current="Le type de transition actuel est"
|
||||
AdvSceneSwitcher.condition.transition.type.duration="La durée de la transition actuelle est"
|
||||
@@ -426,7 +426,7 @@ AdvSceneSwitcher.condition.stats.condition.above="au-dessus de"
|
||||
AdvSceneSwitcher.condition.stats.condition.equals="égal à"
|
||||
AdvSceneSwitcher.condition.stats.condition.below="en dessous de"
|
||||
AdvSceneSwitcher.condition.stats.dockHint="Vous pouvez ouvrir le dock \"Statistiques\" pour voir l'état actuel"
|
||||
AdvSceneSwitcher.condition.stats.entry="{{stats}} est {{condition}} {{value}}"
|
||||
AdvSceneSwitcher.condition.stats.entry="{{stats}}est{{condition}}{{value}}"
|
||||
AdvSceneSwitcher.condition.profile="Profil"
|
||||
AdvSceneSwitcher.condition.profile.entry="Le profil actif actuel est{{profiles}}"
|
||||
AdvSceneSwitcher.condition.websocket="Websocket"
|
||||
@@ -434,7 +434,7 @@ AdvSceneSwitcher.condition.websocket.type.request="Demande de commutation de sc
|
||||
AdvSceneSwitcher.condition.websocket.type.event="Événement de commutation de scène"
|
||||
AdvSceneSwitcher.condition.websocket.useRegex="Utiliser des expressions régulières"
|
||||
AdvSceneSwitcher.condition.websocket.entry.request="{{type}}a été reçu :"
|
||||
AdvSceneSwitcher.condition.websocket.entry.event="{{type}}a été reçu de{{connection}} :"
|
||||
AdvSceneSwitcher.condition.websocket.entry.event="{{type}}a été reçu de{{connection}}:"
|
||||
AdvSceneSwitcher.condition.variable="Variable"
|
||||
AdvSceneSwitcher.condition.variable.type.compare="est égal à"
|
||||
AdvSceneSwitcher.condition.variable.type.empty="est vide"
|
||||
@@ -556,7 +556,7 @@ AdvSceneSwitcher.action.media.type.stop="Arrêt"
|
||||
AdvSceneSwitcher.action.media.type.restart="Redémarrage"
|
||||
AdvSceneSwitcher.action.media.type.next="Suivant"
|
||||
AdvSceneSwitcher.action.media.type.previous="Précédent"
|
||||
AdvSceneSwitcher.action.media.type.seek="Recherche vers"
|
||||
AdvSceneSwitcher.action.media.type.seek.duration="Recherche vers"
|
||||
AdvSceneSwitcher.action.macro="Macro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Pause"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Reprendre"
|
||||
@@ -594,15 +594,15 @@ AdvSceneSwitcher.action.hotkey.leftMeta="Méta gauche"
|
||||
AdvSceneSwitcher.action.hotkey.rightMeta="Touche Droite Meta"
|
||||
AdvSceneSwitcher.action.hotkey.onlyOBS="Envoyer la pression de touche uniquement à OBS"
|
||||
AdvSceneSwitcher.action.hotkey.disabled="Impossible de simuler des pressions de touche globales - la fonctionnalité est limitée à l'envoi de la pression de touche à OBS uniquement !"
|
||||
AdvSceneSwitcher.action.hotkey.entry.custom="Appuyer sur {{actionType}} {{keys}} pendant {{duration}}"
|
||||
AdvSceneSwitcher.action.hotkey.entry.obs="Appuyer sur {{actionType}} {{hotkeyType}} {{obsHotkeys}}"
|
||||
AdvSceneSwitcher.action.hotkey.entry.custom="Appuyer sur{{actionType}}{{keys}}pendant{{duration}}"
|
||||
AdvSceneSwitcher.action.hotkey.entry.obs="Appuyer sur{{actionType}}{{hotkeyType}}{{obsHotkeys}}"
|
||||
AdvSceneSwitcher.action.sceneOrder="Ordre des éléments de la scène"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveUp="Déplacer vers le haut"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveDown="Déplacer vers le bas"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveTop="Déplacer en haut"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Déplacer en bas"
|
||||
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Déplacer à la position"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Sur {{scenes}} {{actions}} {{sources}} {{position}}"
|
||||
AdvSceneSwitcher.action.sceneOrder.entry="Sur{{scenes}}{{actions}}{{sources}}{{position}}"
|
||||
AdvSceneSwitcher.action.sceneTransform="Transformation de l'élément de la scène"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.manual="Transform"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.reset="Réinitialiser la transformation"
|
||||
@@ -615,11 +615,11 @@ AdvSceneSwitcher.action.sceneTransform.type.centerToScreen="Centrer à l'écran"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.centerVertically="Centrer verticalement"
|
||||
AdvSceneSwitcher.action.sceneTransform.type.centerHorizontally="Centrer horizontalement"
|
||||
AdvSceneSwitcher.action.sceneTransform.getTransform="Obtenir la transformation"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="Sur {{scenes}} {{action}} {{rotation}} {{sources}}"
|
||||
AdvSceneSwitcher.action.sceneTransform.entry="Sur{{scenes}}{{action}}{{rotation}}{{sources}}"
|
||||
AdvSceneSwitcher.action.file="Fichier"
|
||||
AdvSceneSwitcher.action.file.type.write="Écrire"
|
||||
AdvSceneSwitcher.action.file.type.append="Ajouter"
|
||||
AdvSceneSwitcher.action.file.entry="{{actions}} vers {{filePath}} :"
|
||||
AdvSceneSwitcher.action.file.entry="{{actions}}vers{{filePath}}:"
|
||||
AdvSceneSwitcher.action.studioMode="Mode studio"
|
||||
AdvSceneSwitcher.action.studioMode.type.swap="Permuter la scène de prévisualisation et la scène du programme"
|
||||
AdvSceneSwitcher.action.studioMode.type.setScene="Définir la scène de prévisualisation sur"
|
||||
@@ -630,15 +630,15 @@ AdvSceneSwitcher.action.transition.type.scene="Transition de scène"
|
||||
AdvSceneSwitcher.action.transition.type.sceneOverride="Remplacement de la transition de scène"
|
||||
AdvSceneSwitcher.action.transition.type.sourceShow="Transition d'affichage de la source"
|
||||
AdvSceneSwitcher.action.transition.type.sourceHide="Transition de masquage de la source"
|
||||
AdvSceneSwitcher.action.transition.entry.line1="Modifier {{type}} {{scenes}} {{sources}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}} Définir le type de transition sur {{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}} Définir la durée de la transition à {{duration}} secondes"
|
||||
AdvSceneSwitcher.action.transition.entry.line1="Modifier{{type}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line2="{{setTransition}}Définir le type de transition sur{{transitions}}"
|
||||
AdvSceneSwitcher.action.transition.entry.line3="{{setDuration}}Définir la durée de la transition à{{duration}}secondes"
|
||||
AdvSceneSwitcher.action.timer="Minuterie"
|
||||
AdvSceneSwitcher.action.timer.type.pause="Mettre en pause"
|
||||
AdvSceneSwitcher.action.timer.type.continue="Continuer"
|
||||
AdvSceneSwitcher.action.timer.type.reset="Réinitialiser"
|
||||
AdvSceneSwitcher.action.timer.type.setTimeRemaining="Définir le temps restant de"
|
||||
AdvSceneSwitcher.action.timer.entry="{{timerAction}} minuteries sur {{macros}} {{duration}}"
|
||||
AdvSceneSwitcher.action.timer.entry="{{timerAction}}minuteries sur{{macros}}{{duration}}"
|
||||
AdvSceneSwitcher.action.random="Aléatoire"
|
||||
AdvSceneSwitcher.action.random.allowRepeat="Autoriser l'exécution consécutive du même macro"
|
||||
AdvSceneSwitcher.action.random.entry="Exécuter au hasard l'un des macros suivants (les macros en pause sont ignorées)"
|
||||
@@ -654,11 +654,11 @@ AdvSceneSwitcher.action.screenshot.type.source="Source"
|
||||
AdvSceneSwitcher.action.screenshot.type.scene="Scène"
|
||||
AdvSceneSwitcher.action.screenshot.mainOutput="Sortie principale d'OBS"
|
||||
AdvSceneSwitcher.action.screenshot.blackscreenNote="Les sources ou les scènes qui ne sont pas toujours rendues peuvent entraîner des parties de captures d'écran vides."
|
||||
AdvSceneSwitcher.action.screenshot.entry="Capturer {{targetType}} {{sources}} {{scenes}} et enregistrer à l'emplacement {{saveType}}"
|
||||
AdvSceneSwitcher.action.screenshot.entry="Capturer{{targetType}}{{sources}}{{scenes}}et enregistrer à l'emplacement{{saveType}}"
|
||||
AdvSceneSwitcher.action.profile="Profil"
|
||||
AdvSceneSwitcher.action.profile.entry="Changer le profil actif vers {{profiles}}"
|
||||
AdvSceneSwitcher.action.profile.entry="Changer le profil actif vers{{profiles}}"
|
||||
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.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)"
|
||||
@@ -674,17 +674,17 @@ AdvSceneSwitcher.action.websocket.type.request="Requête"
|
||||
AdvSceneSwitcher.action.websocket.type.event="Événement"
|
||||
AdvSceneSwitcher.action.websocket.settingsConflictGeneric="Possible conflit de paramètres : Sélection de message websocket générique avec une connexion qui suit le protocole OBS !"
|
||||
AdvSceneSwitcher.action.websocket.settingsConflictOBS="Possible conflit de paramètres : Connexion sélectionnée qui ne prend en charge que des messages websocket génériques, alors que le type de message nécessite le protocole OBS !"
|
||||
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.request="Envoyer {{api}} de type {{type}} via {{connection}}"
|
||||
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.event="Envoyer {{api}} de type {{type}} aux clients connectés"
|
||||
AdvSceneSwitcher.action.websocket.entry.generic="Envoyer {{api}} via {{connection}}"
|
||||
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.request="Envoyer{{api}}de type{{type}}via{{connection}}"
|
||||
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.event="Envoyer{{api}}de type{{type}}aux clients connectés"
|
||||
AdvSceneSwitcher.action.websocket.entry.generic="Envoyer{{api}}via{{connection}}"
|
||||
AdvSceneSwitcher.action.http="HTTP"
|
||||
AdvSceneSwitcher.action.http.setHeaders="Définir les en-têtes"
|
||||
AdvSceneSwitcher.action.http.headers="En-têtes :"
|
||||
AdvSceneSwitcher.action.http.addHeader="Ajouter un en-tête"
|
||||
AdvSceneSwitcher.action.http.type.get="GET"
|
||||
AdvSceneSwitcher.action.http.type.post="POST"
|
||||
AdvSceneSwitcher.action.http.entry.line1="Envoyer {{method}} vers {{url}}"
|
||||
AdvSceneSwitcher.action.http.entry.line2="Délai d'attente : {{timeout}} secondes"
|
||||
AdvSceneSwitcher.action.http.entry.line1="Envoyer{{method}}vers{{url}}"
|
||||
AdvSceneSwitcher.action.http.entry.line2="Délai d'attente :{{timeout}}secondes"
|
||||
AdvSceneSwitcher.action.variable="Variable"
|
||||
AdvSceneSwitcher.action.variable.type.set="Définir sur une valeur fixe"
|
||||
AdvSceneSwitcher.action.variable.type.append="Ajouter"
|
||||
@@ -710,8 +710,8 @@ AdvSceneSwitcher.action.variable.invalidSelection="Sélection invalide !"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="La récupération de valeurs de variables à partir d'actions %1 n'est pas prise en charge !"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="La récupération de valeurs de variables à partir de conditions %1 n'est pas prise en charge !"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Valeur actuelle :"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Début de la sous-chaîne : {{subStringStart}} Taille de la sous-chaîne : {{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Attribuer la valeur du match {{regexMatchIdx}} en utilisant une expression régulière :"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière :"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.customPrompt="{{useCustomPrompt}}Utiliser un message personnalisé{{inputPrompt}}"
|
||||
AdvSceneSwitcher.action.variable.entry.userInput.placeholder="{{useInputPlaceholder}}Remplir avec un indicateur de position{{inputPlaceholder}}"
|
||||
AdvSceneSwitcher.action.projector="Projecteur"
|
||||
@@ -723,39 +723,32 @@ AdvSceneSwitcher.action.projector.type.multiview="Multivue"
|
||||
AdvSceneSwitcher.action.projector.display="Affichage"
|
||||
AdvSceneSwitcher.action.projector.windowed="Fenêtré"
|
||||
AdvSceneSwitcher.action.projector.fullscreen="Plein écran"
|
||||
AdvSceneSwitcher.action.projector.entry="Ouvrir le projecteur {{windowTypes}} de {{types}} {{scenes}} {{sources}}"
|
||||
AdvSceneSwitcher.action.projector.entry.monitor="sur {{monitors}}"
|
||||
AdvSceneSwitcher.action.projector.entry="Ouvrir le projecteur{{windowTypes}}de{{types}}{{scenes}}{{sources}}"
|
||||
AdvSceneSwitcher.action.projector.entry.monitor="sur{{monitors}}"
|
||||
AdvSceneSwitcher.action.midi="MIDI"
|
||||
AdvSceneSwitcher.action.midi.entry="Envoyer un message à {{device}} :"
|
||||
AdvSceneSwitcher.action.midi.entry.listen="Définir la sélection de messages MIDI sur les messages entrants de {{listenDevices}} : {{listenButton}}"
|
||||
AdvSceneSwitcher.action.midi.entry="Envoyer un message à{{device}}:"
|
||||
AdvSceneSwitcher.action.midi.entry.listen="Définir la sélection de messages MIDI sur les messages entrants de{{listenDevices}}:{{listenButton}}"
|
||||
AdvSceneSwitcher.action.osc="Open Sound Control"
|
||||
AdvSceneSwitcher.action.sceneLock="Verrouillage de l'élément de scène"
|
||||
AdvSceneSwitcher.action.sceneLock.type.lock="verrouiller"
|
||||
AdvSceneSwitcher.action.sceneLock.type.unlock="déverrouiller"
|
||||
AdvSceneSwitcher.action.sceneLock.type.toggle="basculer le verrouillage de"
|
||||
AdvSceneSwitcher.action.sceneLock.entry="Sur {{scenes}} {{actions}} {{sources}}"
|
||||
AdvSceneSwitcher.action.sceneLock.entry="Sur{{scenes}}{{actions}}{{sources}}"
|
||||
AdvSceneSwitcher.action.twitch="Twitch"
|
||||
AdvSceneSwitcher.action.twitch.type.title="Définir le titre du flux"
|
||||
AdvSceneSwitcher.action.twitch.type.category="Définir la catégorie du flux"
|
||||
AdvSceneSwitcher.action.twitch.type.marker="Create stream marker"
|
||||
AdvSceneSwitcher.action.twitch.type.clip="Create stream clip"
|
||||
AdvSceneSwitcher.action.twitch.type.commercial="Démarrer une publicité d'une durée de"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.title.set="Définir le titre du flux"
|
||||
AdvSceneSwitcher.action.twitch.type.channel.info.category.set="Définir la catégorie du flux"
|
||||
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.entry="Sur {{account}} {{actions}} {{streamTitle}} {{category}} {{manualCategorySearch}} {{markerDescription}} {{clipHasDelay}} {{duration}}"
|
||||
AdvSceneSwitcher.action.twitch.tokenPermissionsInsufficient="Permissions of selected token are insufficient to perform selected action!"
|
||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="Add a slight delay before capturing the clip"
|
||||
AdvSceneSwitcher.action.twitch.marker.description="Describe marker"
|
||||
AdvSceneSwitcher.action.twitch.title.title="Enter title"
|
||||
|
||||
; Transition Tab
|
||||
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.transitionsHelp="<html><head/><body><p>Ces paramètres n'affectent <span style=\"font-style:italic;\">que</span> les transitions provoquées par le commutateur de scènes - Consultez la <a href=\"https://obsproject.com/forum/resources/transition-table.1174/\"><span style=\" text-decoration: underline; color:#268bd2;\">Table de transitions</span></a> si vous souhaitez les configurer pour des changements de scène manuels.<br/>Les paramètres définis ici ont la priorité sur les paramètres de transition configurés ailleurs dans le commutateur de scènes.<br/><br/>Cliquez sur le symbole plus ci-dessous pour ajouter une nouvelle entrée.</p></body></html>"
|
||||
AdvSceneSwitcher.transitionTab.defaultTransition="Changer la transition si la scène est active"
|
||||
AdvSceneSwitcher.transitionTab.entry="Passer de {{scenes}} à {{scenes2}} en utilisant {{transitions}} avec une durée de {{duration}}"
|
||||
AdvSceneSwitcher.transitionTab.defaultTransitionEntry="Lorsque la scène {{scenes}} est active, changer la transition de scène par défaut en {{transitions}}"
|
||||
AdvSceneSwitcher.transitionTab.entry="Passer de{{scenes}}à{{scenes2}}en utilisant{{transitions}}avec une durée de{{duration}}"
|
||||
AdvSceneSwitcher.transitionTab.defaultTransitionEntry="Lorsque la scène{{scenes}}est active, changer la transition de scène par défaut en{{transitions}}"
|
||||
AdvSceneSwitcher.transitionTab.defaultTransitionsHelp="Cliquez sur le symbole plus pour ajouter une entrée."
|
||||
AdvSceneSwitcher.transitionTab.defaultTransition.delay="Changer la transition après le délai de {{defTransitionDelay}} après le changement de scène."
|
||||
AdvSceneSwitcher.transitionTab.defaultTransition.delay="Changer la transition après le délai de{{defTransitionDelay}}après le changement de scène."
|
||||
AdvSceneSwitcher.transitionTab.defaultTransition.delay.help="Le délai est utilisé pour éviter les changements de scène annulés, qui peuvent se produire si le type de transition est modifié alors qu'une transition est encore en cours."
|
||||
|
||||
; Pause Scenes Tab
|
||||
@@ -766,7 +759,7 @@ AdvSceneSwitcher.pauseTab.pauseInFocus2="est au premier plan"
|
||||
AdvSceneSwitcher.pauseTab.pauseTypeScene="la scène est active"
|
||||
AdvSceneSwitcher.pauseTab.pauseTypeWindow="la fenêtre est au premier plan"
|
||||
AdvSceneSwitcher.pauseTab.pauseTargetAll="tous"
|
||||
AdvSceneSwitcher.pauseTab.pauseEntry="Mettre en pause {{pauseTargets}}vérifications lorsque {{pauseTypes}}{{scenes}}{{windows}}"
|
||||
AdvSceneSwitcher.pauseTab.pauseEntry="Mettre en pause{{pauseTargets}}vérifications lorsque{{pauseTypes}}{{scenes}}{{windows}}"
|
||||
AdvSceneSwitcher.pauseTab.help="Sur cet onglet, vous pouvez configurer la pause des méthodes de commutation individuelles si une scène est active ou si une fenêtre est au premier plan.\n\nCliquez sur le symbole plus en surbrillance pour continuer."
|
||||
|
||||
; Window Title Tab
|
||||
@@ -784,7 +777,7 @@ AdvSceneSwitcher.windowTitleTab.ignoreWindowsHelp="Si un titre de fenêtre est i
|
||||
AdvSceneSwitcher.executableTab.title="Exécutable"
|
||||
AdvSceneSwitcher.executableTab.implemented="Implémenté par dasOven"
|
||||
AdvSceneSwitcher.executableTab.requiresFocus="uniquement si au premier plan"
|
||||
AdvSceneSwitcher.executableTab.entry="Lorsque {{processes}} est en cours d'exécution, basculer vers {{scenes}} en utilisant {{transitions}} {{requiresFocus}}"
|
||||
AdvSceneSwitcher.executableTab.entry="Lorsque{{processes}}est en cours d'exécution, basculer vers{{scenes}}en utilisant{{transitions}}{{requiresFocus}}"
|
||||
AdvSceneSwitcher.executableTab.help="Cet onglet vous permettra de basculer automatiquement entre les scènes si un processus est en cours d'exécution.\nCela peut être utile dans des situations où le nom de la fenêtre pourrait changer ou n'est pas connu.\n\nCliquez sur le symbole plus en surbrillance pour continuer."
|
||||
|
||||
; Screen Region Tab
|
||||
@@ -937,7 +930,7 @@ AdvSceneSwitcher.sceneGroupTab.title="Groupe de Scènes"
|
||||
AdvSceneSwitcher.sceneGroupTab.list="Groupes de Scènes"
|
||||
AdvSceneSwitcher.sceneGroupTab.edit="Modifier les Groupes de Scènes"
|
||||
AdvSceneSwitcher.sceneGroupTab.edit.name="Nom :"
|
||||
AdvSceneSwitcher.sceneGroupTab.edit.type="Type : {{type}}"
|
||||
AdvSceneSwitcher.sceneGroupTab.edit.type="Type :{{type}}"
|
||||
AdvSceneSwitcher.sceneGroupTab.type.count="Compteur"
|
||||
AdvSceneSwitcher.sceneGroupTab.type.time="Temps"
|
||||
AdvSceneSwitcher.sceneGroupTab.type.random="Aléatoire"
|
||||
@@ -1122,12 +1115,9 @@ AdvSceneSwitcher.twitchToken.request.success="Jeton obtenu avec succès !"
|
||||
AdvSceneSwitcher.twitchToken.request.success.browser="Authentification réussie ! Vous pouvez maintenant fermer cette fenêtre."
|
||||
AdvSceneSwitcher.twitchToken.request.notSet="Aucun jeton défini - Veuillez demander un nouveau jeton !"
|
||||
AdvSceneSwitcher.twitchToken.permissions="Permissions du jeton :"
|
||||
AdvSceneSwitcher.twitchToken.analytics.readExtensions="Afficher les données d'analyse pour les extensions Twitch détenues par le compte authentifié."
|
||||
AdvSceneSwitcher.twitchToken.analytics.readGames="Afficher les données d'analyse pour les jeux détenus par le compte authentifié."
|
||||
AdvSceneSwitcher.twitchToken.bits.read="Afficher les informations sur les Bits pour une chaîne."
|
||||
AdvSceneSwitcher.twitchToken.channel.manageBroadcast="Gérer la configuration de diffusion d'une chaîne, y compris la mise à jour de la configuration de la chaîne et la gestion des marqueurs de diffusion en continu et des balises de diffusion en continu."
|
||||
AdvSceneSwitcher.twitchToken.channel.startCommercial="Lancer des publicités sur une chaîne."
|
||||
AdvSceneSwitcher.twitchToken.channel.createClip="Create clips from channel's broadcasts."
|
||||
AdvSceneSwitcher.twitchToken.channel.broadcast.manage="Gérer la configuration de diffusion d'une chaîne, y compris la mise à jour de la configuration de la chaîne et la gestion des marqueurs de diffusion en continu et des balises de diffusion en continu."
|
||||
AdvSceneSwitcher.twitchToken.channel.commercial.edit="Lancer des publicités sur une chaîne."
|
||||
|
||||
AdvSceneSwitcher.twitchCategories.fetchStart="Récupération des catégories de streams..."
|
||||
AdvSceneSwitcher.twitchCategories.fetchStatus="Obtenu %1 catégories de streams."
|
||||
|
||||
@@ -107,7 +107,7 @@ AdvSceneSwitcher.condition.record.state.start="Запись запущена"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Запись приостановлена"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Запись остановлена"
|
||||
AdvSceneSwitcher.condition.process="Процесс"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}} запущен {{focused}} и сфокусирован"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}запущен{{focused}}и сфокусирован"
|
||||
AdvSceneSwitcher.condition.idle="Простой"
|
||||
AdvSceneSwitcher.condition.idle.entry="Не было ни клавиатуры, ни мыши в течении{{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Состояние плагина"
|
||||
|
||||
@@ -119,7 +119,6 @@ AdvSceneSwitcher.condition.file.entry.line3="{{checkModificationDate}}{{checkFil
|
||||
AdvSceneSwitcher.condition.media="Medya"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="Herhangi bir medya kaynağı"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="Tüm medya kaynakları "
|
||||
AdvSceneSwitcher.condition.media.matchOnChange="Yalnızca değişiklikle eşleştirin (Not: Bu seçenek gelecekteki bir sürümde kaldırılacaktır - lütfen bunun yerine zaman kısıtlamalarını kullanın)"
|
||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}durumu{{states}}ve{{timeRestrictions}}{{time}}"
|
||||
AdvSceneSwitcher.condition.video="Video"
|
||||
AdvSceneSwitcher.condition.video.condition.match="Tam olarak eşleşir"
|
||||
@@ -159,9 +158,8 @@ AdvSceneSwitcher.condition.record="Kayıt"
|
||||
AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
|
||||
AdvSceneSwitcher.condition.record.state.stop="Kayıt durdu"
|
||||
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||
AdvSceneSwitcher.condition.process="İşlem"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}} çalışıyor {{focused}} ve odaklandı"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}çalışıyor{{focused}}ve odaklandı"
|
||||
AdvSceneSwitcher.condition.idle="Boşta"
|
||||
AdvSceneSwitcher.condition.idle.entry="...için klavye veya fare girişi yok {{duration}}"
|
||||
AdvSceneSwitcher.condition.pluginState="Eklenti durumu"
|
||||
@@ -231,7 +229,8 @@ AdvSceneSwitcher.condition.date.state.before="Önce"
|
||||
AdvSceneSwitcher.condition.date.state.between="Arasında"
|
||||
AdvSceneSwitcher.condition.sceneTransform="Sahne öğesi dönüşümü"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Dönüşümü al"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="Açık{{scenes}}{{sources}} dönüşümle eşleşir"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="Açık{{scenes}}{{sources}}{{types}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.matches="dönüşümle eşleşir"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line2="{{settings}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}} {{getSettings}}"
|
||||
AdvSceneSwitcher.condition.transition="Geçiş"
|
||||
@@ -316,7 +315,6 @@ AdvSceneSwitcher.action.media.type.stop="Dur"
|
||||
AdvSceneSwitcher.action.media.type.restart="Yeniden Başlat"
|
||||
AdvSceneSwitcher.action.media.type.next="Sonraki"
|
||||
AdvSceneSwitcher.action.media.type.previous="Önceki"
|
||||
AdvSceneSwitcher.action.media.entry="{{actions}}{{duration}}{{mediaSources}}"
|
||||
AdvSceneSwitcher.action.macro="Makro"
|
||||
AdvSceneSwitcher.action.macro.type.pause="Duraklat"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="Duraklatma"
|
||||
|
||||
@@ -185,7 +185,6 @@ AdvSceneSwitcher.condition.media="媒体"
|
||||
AdvSceneSwitcher.condition.media.source="源"
|
||||
AdvSceneSwitcher.condition.media.anyOnScene="任何媒体源"
|
||||
AdvSceneSwitcher.condition.media.allOnScene="所有媒体源"
|
||||
AdvSceneSwitcher.condition.media.matchOnChange="仅在更改时匹配(注意:此选项将在未来版本中删除-请改用时间限制)"
|
||||
AdvSceneSwitcher.condition.media.inconsistencyInfo="不幸的是,并非所有媒体源类型的行为都相同(例如,媒体源与VLC视频源“停止”状态)。\n所以,请尝试适合您的设置!"
|
||||
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}} 的状态是 {{states}} 和 {{timeRestrictions}}{{time}}"
|
||||
AdvSceneSwitcher.condition.video="视频"
|
||||
@@ -267,9 +266,8 @@ AdvSceneSwitcher.condition.record="录制"
|
||||
AdvSceneSwitcher.condition.record.state.start="录制运行中"
|
||||
AdvSceneSwitcher.condition.record.state.pause="录制暂停"
|
||||
AdvSceneSwitcher.condition.record.state.stop="录制停止"
|
||||
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||
AdvSceneSwitcher.condition.process="进程"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}} 是正在运行 {{focused}} 并且是获得焦点"
|
||||
AdvSceneSwitcher.condition.process.entry="{{processes}}{{regex}}是正在运行{{focused}}并且是获得焦点"
|
||||
AdvSceneSwitcher.condition.process.entry.focus="当前焦点进程: {{focusProcess}}"
|
||||
AdvSceneSwitcher.condition.idle="闲置检测"
|
||||
AdvSceneSwitcher.condition.idle.entry="没有键盘或鼠标输入{{duration}}"
|
||||
@@ -371,7 +369,8 @@ AdvSceneSwitcher.condition.date.entry.nextMatchDate="下一次匹配 在: %1"
|
||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} 重复时,将选定的日期更新为重复日期"
|
||||
AdvSceneSwitcher.condition.sceneTransform="场景项目被改变"
|
||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="内容或者设置被改变了"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="在 {{scenes}} {{sources}} 匹配变换"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line1="在 {{scenes}} {{sources}} {{types}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.type.matches="匹配变换"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line2="{{settings}}"
|
||||
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}} {{getSettings}}"
|
||||
AdvSceneSwitcher.condition.transition="转场"
|
||||
@@ -435,7 +434,6 @@ AdvSceneSwitcher.condition.variable.type.valueChanged="值已更改"
|
||||
AdvSceneSwitcher.condition.variable.type.equalsVariable="等于变量"
|
||||
AdvSceneSwitcher.condition.variable.type.lessThanVariable="小于变量"
|
||||
AdvSceneSwitcher.condition.variable.type.greaterThanVariable="大于变量"
|
||||
AdvSceneSwitcher.condition.variable.entry="{{variables}}{{conditions}}{{strValue}}{{numValue}}{{variables2}}"
|
||||
AdvSceneSwitcher.condition.run="运行"
|
||||
AdvSceneSwitcher.condition.run.entry="进程在超时 {{timeout}} 秒之前退出"
|
||||
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}检查退出代码{{exitCode}}"
|
||||
@@ -527,8 +525,7 @@ AdvSceneSwitcher.action.media.type.stop="停止"
|
||||
AdvSceneSwitcher.action.media.type.restart="重新启动"
|
||||
AdvSceneSwitcher.action.media.type.next="下一个"
|
||||
AdvSceneSwitcher.action.media.type.previous="上一个"
|
||||
AdvSceneSwitcher.action.media.type.seek="时间轴定位"
|
||||
AdvSceneSwitcher.action.media.entry="{{actions}}{{duration}}{{mediaSources}}"
|
||||
AdvSceneSwitcher.action.media.type.seek.duration="时间轴定位"
|
||||
AdvSceneSwitcher.action.macro="宏"
|
||||
AdvSceneSwitcher.action.macro.type.pause="暂停"
|
||||
AdvSceneSwitcher.action.macro.type.unpause="取消暂停"
|
||||
@@ -652,7 +649,6 @@ AdvSceneSwitcher.action.variable.invalidSelection="无效选择!"
|
||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="不支持从 %1 个操作获取变量值!"
|
||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="不支持从 %1 条件中获取变量值!"
|
||||
AdvSceneSwitcher.action.variable.currentSegmentValue="当前值:"
|
||||
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringIndex="子字符串开始:{{subStringStart}} 子字符串大小:{{subStringSize}}"
|
||||
AdvSceneSwitcher.action.variable.entry.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
|
||||
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{replaceStr}}"
|
||||
|
||||
11
data/res/images/DarkNotEqual.svg
Normal file
11
data/res/images/DarkNotEqual.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" version="1.1">
|
||||
<!-- Created with SVG-edit - https://github.com/SVG-Edit/svgedit-->
|
||||
|
||||
<g class="layer">
|
||||
<title>Layer 1</title>
|
||||
<rect fill="#fefefe" height="2.25" id="svg_1" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="13" x="1.5" y="4"/>
|
||||
<rect fill="#fefefe" height="2.25" id="svg_2" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="13" x="1.5" y="10"/>
|
||||
<rect fill="#fefefe" height="1" id="svg_4" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(0.341951, -0.926734, 0.939718, 0.337226, -1.948, 13.2448)" width="14" x="1" y="7"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 931 B |
11
data/res/images/LightNotEqual.svg
Normal file
11
data/res/images/LightNotEqual.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" version="1.1">
|
||||
<!-- Created with SVG-edit - https://github.com/SVG-Edit/svgedit-->
|
||||
|
||||
<g class="layer">
|
||||
<title>Layer 1</title>
|
||||
<rect fill="#202020" height="2.25" id="svg_1" stroke="#202020" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="13" x="1.5" y="4"/>
|
||||
<rect fill="#202020" height="2.25" id="svg_2" stroke="#202020" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="13" x="1.5" y="10"/>
|
||||
<rect fill="#202020" height="1" id="svg_4" stroke="#202020" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(0.341951, -0.926734, 0.939718, 0.337226, -1.948, 13.2448)" width="14" x="1" y="7"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 931 B |
2
deps/asio
vendored
2
deps/asio
vendored
Submodule deps/asio updated: b73dc1d2c0...c465349fa5
1
deps/json
vendored
Submodule
1
deps/json
vendored
Submodule
Submodule deps/json added at bc889afb4c
2
deps/websocketpp
vendored
2
deps/websocketpp
vendored
Submodule deps/websocketpp updated: c6d7e295bf...56123c8759
@@ -119,7 +119,7 @@
|
||||
<string notr="true">ms</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>50</number>
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>20000</number>
|
||||
@@ -1275,6 +1275,22 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="toggleElseActions">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "status-control.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "curl-helper.hpp"
|
||||
@@ -10,6 +11,7 @@
|
||||
#include <QMainWindow>
|
||||
#include <QAction>
|
||||
#include <QFileDialog>
|
||||
#include <QTextStream>
|
||||
#include <QDirIterator>
|
||||
#include <regex>
|
||||
#include <filesystem>
|
||||
@@ -115,10 +117,27 @@ void AdvSceneSwitcher::LoadUI()
|
||||
loading = false;
|
||||
}
|
||||
|
||||
bool AdvSceneSwitcher::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
auto eventType = event->type();
|
||||
if (obj == ui->macroElseActions && eventType == QEvent::Resize) {
|
||||
QResizeEvent *resizeEvent = static_cast<QResizeEvent *>(event);
|
||||
|
||||
if (resizeEvent->size().height() == 0) {
|
||||
SetElseActionsStateToHidden();
|
||||
return QDialog::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
SetElseActionsStateToVisible();
|
||||
}
|
||||
|
||||
return QDialog::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Saving and loading
|
||||
******************************************************************************/
|
||||
static void AskForBackup(obs_data_t *obj);
|
||||
static void AskForBackup(const QString &json);
|
||||
|
||||
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
||||
{
|
||||
@@ -139,16 +158,25 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
||||
switcher->Stop();
|
||||
|
||||
switcher->m.lock();
|
||||
obs_data_t *obj =
|
||||
OBSDataAutoRelease obj =
|
||||
obs_data_get_obj(save_data, "advanced-scene-switcher");
|
||||
if (!obj) {
|
||||
obj = obs_data_create();
|
||||
}
|
||||
if (switcher->VersionChanged(obj, g_GIT_SHA1)) {
|
||||
AskForBackup(obj);
|
||||
auto json = obs_data_get_json(obj);
|
||||
static QString jsonQString = json ? json : "";
|
||||
std::thread t([]() {
|
||||
obs_queue_task(
|
||||
OBS_TASK_UI,
|
||||
[](void *) {
|
||||
AskForBackup(jsonQString);
|
||||
},
|
||||
nullptr, false);
|
||||
});
|
||||
t.detach();
|
||||
}
|
||||
switcher->LoadSettings(obj);
|
||||
obs_data_release(obj);
|
||||
switcher->m.unlock();
|
||||
|
||||
if (!switcher->stop) {
|
||||
@@ -157,12 +185,12 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
||||
}
|
||||
}
|
||||
|
||||
static void AskForBackup(obs_data_t *obj)
|
||||
static void AskForBackup(const QString &json)
|
||||
{
|
||||
bool backupSettings = DisplayMessage(
|
||||
obs_module_text("AdvSceneSwitcher.askBackup"), true);
|
||||
const bool backupWasConfirmed = DisplayMessage(
|
||||
obs_module_text("AdvSceneSwitcher.askBackup"), true, false);
|
||||
|
||||
if (!backupSettings) {
|
||||
if (!backupWasConfirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -181,8 +209,8 @@ static void AskForBackup(obs_data_t *obj)
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs_data_save_json(obj, file.fileName().toUtf8().constData());
|
||||
auto out = QTextStream(&file);
|
||||
out << json;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
@@ -209,7 +237,6 @@ void SwitcherData::Thread()
|
||||
// if a longer transition is used than the configured check interval
|
||||
bool setPrevSceneAfterLinger = false;
|
||||
bool macroMatch = false;
|
||||
macroSceneSwitched = false;
|
||||
endTime = std::chrono::high_resolution_clock::now();
|
||||
auto runTime =
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
@@ -320,19 +347,12 @@ void SwitcherData::SetPreconditions()
|
||||
// Process name
|
||||
GetForegroundProcessName(currentForegroundProcess);
|
||||
|
||||
// Cursor
|
||||
std::pair<int, int> cursorPos = GetCursorPos();
|
||||
cursorPosChanged = cursorPos.first != switcher->lastCursorPos.first ||
|
||||
cursorPos.second != switcher->lastCursorPos.second;
|
||||
lastCursorPos = GetCursorPos();
|
||||
// Macro
|
||||
InvalidateMacroTempVarValues();
|
||||
}
|
||||
|
||||
void ClearWebsocketMessages();
|
||||
|
||||
void SwitcherData::ResetForNextInterval()
|
||||
{
|
||||
// Core reset functions
|
||||
ClearWebsocketMessages();
|
||||
// Plugin reset functions
|
||||
for (const auto &func : resetIntervalSteps) {
|
||||
func();
|
||||
@@ -408,7 +428,7 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
|
||||
|
||||
static void ResetMacros()
|
||||
{
|
||||
for (auto &m : switcher->macros) {
|
||||
for (auto &m : GetMacros()) {
|
||||
m->ResetRunCount();
|
||||
m->ResetTimers();
|
||||
}
|
||||
@@ -451,9 +471,9 @@ void SwitcherData::Stop()
|
||||
if (th && th->isRunning()) {
|
||||
stop = true;
|
||||
cv.notify_all();
|
||||
abortMacroWait = true;
|
||||
macroWaitCv.notify_all();
|
||||
macroTransitionCv.notify_all();
|
||||
SetMacroAbortWait(true);
|
||||
GetMacroWaitCV().notify_all();
|
||||
GetMacroTransitionCV().notify_all();
|
||||
|
||||
// Not waiting if a dialog was closed is a workaround to avoid
|
||||
// deadlocks when a variable input dialog is opened while Stop()
|
||||
@@ -526,9 +546,6 @@ extern "C" void FreeSceneSwitcher()
|
||||
|
||||
static void handleSceneChange()
|
||||
{
|
||||
switcher->lastSceneChangeTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Stop waiting if scene was changed
|
||||
if (switcher->SceneChangedDuringWait()) {
|
||||
switcher->cv.notify_one();
|
||||
@@ -595,28 +612,9 @@ static void handlePeviewSceneChange()
|
||||
}
|
||||
}
|
||||
|
||||
static void setReplayBufferSaved()
|
||||
static void handleTransitionEnd()
|
||||
{
|
||||
switcher->replayBufferSaved = true;
|
||||
}
|
||||
|
||||
static void setTranstionEnd()
|
||||
{
|
||||
switcher->lastTransitionEndTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
switcher->macroTransitionCv.notify_all();
|
||||
}
|
||||
|
||||
static void setStreamStarting()
|
||||
{
|
||||
switcher->lastStreamStartingTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
static void setStreamStopping()
|
||||
{
|
||||
switcher->lastStreamStoppingTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
GetMacroTransitionCV().notify_all();
|
||||
}
|
||||
|
||||
static void handleShutdown()
|
||||
@@ -625,10 +623,10 @@ static void handleShutdown()
|
||||
return;
|
||||
}
|
||||
switcher->obsIsShuttingDown = true;
|
||||
if (switcher->shutdownConditionCount) {
|
||||
if (ShutdownCheckIsNecessary()) {
|
||||
switcher->Stop();
|
||||
switcher->CheckMacros();
|
||||
switcher->RunMacros();
|
||||
CheckMacros();
|
||||
RunMacros();
|
||||
|
||||
// Unfortunately this will not work as OBS will now allow saving
|
||||
// the scene collection data at this point, So any OBS specific
|
||||
@@ -685,19 +683,8 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
||||
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
|
||||
resetLiveTime();
|
||||
break;
|
||||
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(26, 0, 0)
|
||||
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED:
|
||||
setReplayBufferSaved();
|
||||
break;
|
||||
#endif
|
||||
case OBS_FRONTEND_EVENT_TRANSITION_STOPPED:
|
||||
setTranstionEnd();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_STREAMING_STARTING:
|
||||
setStreamStarting();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_STREAMING_STOPPING:
|
||||
setStreamStopping();
|
||||
handleTransitionEnd();
|
||||
break;
|
||||
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(27, 2, 0)
|
||||
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING:
|
||||
@@ -756,6 +743,9 @@ void OpenSettingsWindow()
|
||||
}
|
||||
}
|
||||
|
||||
void SetupConnectionManager();
|
||||
void SetupWebsocketHelpers();
|
||||
|
||||
extern "C" void InitSceneSwitcher(obs_module_t *module, translateFunc translate)
|
||||
{
|
||||
blog(LOG_INFO, "version: %s", g_GIT_TAG);
|
||||
@@ -766,6 +756,8 @@ extern "C" void InitSceneSwitcher(obs_module_t *module, translateFunc translate)
|
||||
PlatformInit();
|
||||
LoadPlugins();
|
||||
SetupDock();
|
||||
SetupConnectionManager();
|
||||
SetupWebsocketHelpers();
|
||||
|
||||
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
|
||||
obs_frontend_add_event_callback(OBSEvent, switcher);
|
||||
|
||||
@@ -39,6 +39,9 @@ public:
|
||||
void RestoreWindowGeo();
|
||||
void CheckFirstTimeSetup();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
/* --- Begin of general tab section --- */
|
||||
public:
|
||||
void SetupGeneralTab();
|
||||
@@ -115,6 +118,7 @@ public slots:
|
||||
void on_actionUp_clicked();
|
||||
void on_actionDown_clicked();
|
||||
void on_actionBottom_clicked();
|
||||
void on_toggleElseActions_clicked();
|
||||
void on_elseActionAdd_clicked();
|
||||
void on_elseActionRemove_clicked();
|
||||
void on_elseActionTop_clicked();
|
||||
@@ -146,6 +150,8 @@ public slots:
|
||||
void MaximizeElseActions();
|
||||
void MinimizeConditions();
|
||||
void MaximizeConditions();
|
||||
void SetElseActionsStateToHidden();
|
||||
void SetElseActionsStateToVisible();
|
||||
void MacroActionSelectionChanged(int idx);
|
||||
void MacroActionReorder(int to, int target);
|
||||
void AddMacroAction(int idx);
|
||||
@@ -178,6 +184,7 @@ signals:
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void MacroSegmentOrderChanged();
|
||||
void SegmentTempVarsChanged();
|
||||
void HighlightMacrosChanged(bool value);
|
||||
void HighlightActionsChanged(bool value);
|
||||
void HighlightElseActionsChanged(bool value);
|
||||
@@ -333,7 +340,7 @@ public slots:
|
||||
void on_timeUp_clicked();
|
||||
void on_timeDown_clicked();
|
||||
|
||||
// Video tab
|
||||
// Audio tab
|
||||
public:
|
||||
void SetupAudioTab();
|
||||
public slots:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "status-control.hpp"
|
||||
#include "file-selection.hpp"
|
||||
#include "filter-combo-box.hpp"
|
||||
#include "variable.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "version.h"
|
||||
|
||||
@@ -33,7 +34,7 @@ void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = SwitcherData::NoMatch::NO_SWITCH;
|
||||
switcher->switchIfNotMatching = NoMatchBehavior::NO_SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
ui->randomDisabledWarning->setVisible(true);
|
||||
}
|
||||
@@ -45,7 +46,7 @@ void AdvSceneSwitcher::on_noMatchSwitch_clicked()
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = SwitcherData::NoMatch::SWITCH;
|
||||
switcher->switchIfNotMatching = NoMatchBehavior::SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
|
||||
ui->randomDisabledWarning->setVisible(true);
|
||||
@@ -58,7 +59,7 @@ void AdvSceneSwitcher::on_noMatchRandomSwitch_clicked()
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
switcher->switchIfNotMatching = SwitcherData::NoMatch::RANDOM_SWITCH;
|
||||
switcher->switchIfNotMatching = NoMatchBehavior::RANDOM_SWITCH;
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
ui->randomDisabledWarning->setVisible(false);
|
||||
}
|
||||
@@ -499,17 +500,20 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
||||
return;
|
||||
}
|
||||
|
||||
// New post load steps to be declared during load
|
||||
postLoadSteps.clear();
|
||||
|
||||
// Needs to be loaded before any entries which might rely on scene group
|
||||
// selections to be available.
|
||||
loadSceneGroups(obj);
|
||||
LoadVariables(obj);
|
||||
LoadConnections(obj);
|
||||
|
||||
for (const auto &func : loadSteps) {
|
||||
func(obj);
|
||||
}
|
||||
|
||||
LoadMacros(obj);
|
||||
LoadGlobalMacroProperties(obj);
|
||||
loadWindowTitleSwitches(obj);
|
||||
loadScreenRegionSwitches(obj);
|
||||
loadPauseSwitches(obj);
|
||||
@@ -529,6 +533,10 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
||||
LoadHotkeys(obj);
|
||||
LoadUISettings(obj);
|
||||
|
||||
for (const auto &func : postLoadSteps) {
|
||||
func();
|
||||
}
|
||||
|
||||
// Reset on startup and scene collection change
|
||||
switcher->lastOpenedTab = -1;
|
||||
startupLoadDone = true;
|
||||
@@ -542,7 +550,7 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
|
||||
|
||||
saveSceneGroups(obj);
|
||||
SaveMacros(obj);
|
||||
SaveConnections(obj);
|
||||
SaveGlobalMacroProperties(obj);
|
||||
SaveVariables(obj);
|
||||
saveWindowTitleSwitches(obj);
|
||||
saveScreenRegionSwitches(obj);
|
||||
@@ -617,9 +625,9 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
|
||||
interval = obs_data_get_int(obj, "interval");
|
||||
|
||||
obs_data_set_default_int(obj, "switch_if_not_matching",
|
||||
static_cast<int>(NoMatch::NO_SWITCH));
|
||||
switchIfNotMatching =
|
||||
(NoMatch)obs_data_get_int(obj, "switch_if_not_matching");
|
||||
static_cast<int>(NoMatchBehavior::NO_SWITCH));
|
||||
switchIfNotMatching = static_cast<NoMatchBehavior>(
|
||||
obs_data_get_int(obj, "switch_if_not_matching"));
|
||||
std::string nonMatchingSceneName =
|
||||
obs_data_get_string(obj, "non_matching_scene");
|
||||
nonMatchingScene = GetWeakSourceByName(nonMatchingSceneName.c_str());
|
||||
@@ -793,12 +801,13 @@ void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
|
||||
return;
|
||||
}
|
||||
|
||||
if (switchIfNotMatching == NoMatch::SWITCH && nonMatchingScene) {
|
||||
if (switchIfNotMatching == NoMatchBehavior::SWITCH &&
|
||||
nonMatchingScene) {
|
||||
match = true;
|
||||
scene = nonMatchingScene;
|
||||
transition = nullptr;
|
||||
}
|
||||
if (switchIfNotMatching == NoMatch::RANDOM_SWITCH) {
|
||||
if (switchIfNotMatching == NoMatchBehavior::RANDOM_SWITCH) {
|
||||
match = checkRandom(scene, transition, sleep);
|
||||
}
|
||||
}
|
||||
@@ -949,11 +958,11 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
||||
{
|
||||
PopulateSceneSelection(ui->noMatchSwitchScene, false);
|
||||
|
||||
if (switcher->switchIfNotMatching == SwitcherData::NoMatch::SWITCH) {
|
||||
if (switcher->switchIfNotMatching == NoMatchBehavior::SWITCH) {
|
||||
ui->noMatchSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(true);
|
||||
} else if (switcher->switchIfNotMatching ==
|
||||
SwitcherData::NoMatch::NO_SWITCH) {
|
||||
NoMatchBehavior::NO_SWITCH) {
|
||||
ui->noMatchDontSwitch->setChecked(true);
|
||||
ui->noMatchSwitchScene->setEnabled(false);
|
||||
} else {
|
||||
|
||||
@@ -160,7 +160,9 @@ enum class HotkeyType {
|
||||
Key_NumpadMultiply,
|
||||
Key_NumpadDivide,
|
||||
Key_NumpadDecimal,
|
||||
Key_NumpadEnter
|
||||
Key_NumpadEnter,
|
||||
|
||||
Key_Tilde,
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -12,6 +12,11 @@ namespace advss {
|
||||
static QMetaObject::Connection addPulse;
|
||||
SceneGroupEditWidget *typeEdit = nullptr;
|
||||
|
||||
std::deque<SceneGroup> &GetSceneGroups()
|
||||
{
|
||||
return switcher->sceneGroups;
|
||||
}
|
||||
|
||||
void SceneGroup::advanceIdx()
|
||||
{
|
||||
currentIdx++;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
@@ -87,5 +87,6 @@ private:
|
||||
|
||||
SceneGroup *GetSceneGroupByName(const char *name);
|
||||
SceneGroup *GetSceneGroupByQString(const QString &name);
|
||||
std::deque<SceneGroup> &GetSceneGroups();
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -119,7 +119,7 @@ void SwitcherData::writeToStatusFile(const QString &msg)
|
||||
if (file.open(QIODevice::ReadWrite)) {
|
||||
QTextStream stream(&file);
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
stream << msg << endl;
|
||||
stream << msg << "\n";
|
||||
#else
|
||||
stream << msg << Qt::endl;
|
||||
#endif
|
||||
@@ -177,17 +177,17 @@ static std::string getRemoteData(std::string &url)
|
||||
{
|
||||
std::string readBuffer;
|
||||
|
||||
switcher->curl.SetOpt(CURLOPT_URL, url.c_str());
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &readBuffer);
|
||||
CurlHelper::SetOpt(CURLOPT_URL, url.c_str());
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &readBuffer);
|
||||
|
||||
// Set timeout to at least one second
|
||||
int timeout = switcher->interval / 1000;
|
||||
if (timeout == 0) {
|
||||
timeout = 1;
|
||||
}
|
||||
switcher->curl.SetOpt(CURLOPT_TIMEOUT, 1);
|
||||
switcher->curl.Perform();
|
||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT, 1);
|
||||
CurlHelper::Perform();
|
||||
|
||||
return readBuffer;
|
||||
}
|
||||
@@ -422,7 +422,7 @@ void AdvSceneSwitcher::SetupFileTab()
|
||||
obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning2"));
|
||||
ui->remoteFileWarningLabel->hide();
|
||||
|
||||
if (switcher->curl.Initialized()) {
|
||||
if (CurlHelper::Initialized()) {
|
||||
ui->libcurlWarning->setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,8 +143,7 @@ void AdvSceneSwitcher::SetupRandomTab()
|
||||
border-radius: 7px; \
|
||||
border-color: rgb(0,0,0,0) \
|
||||
}");
|
||||
if (switcher->switchIfNotMatching !=
|
||||
SwitcherData::NoMatch::RANDOM_SWITCH) {
|
||||
if (switcher->switchIfNotMatching != NoMatchBehavior::RANDOM_SWITCH) {
|
||||
if (!switcher->disableHints) {
|
||||
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
||||
QColor(0, 0, 0, 0));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "platform-funcs.hpp"
|
||||
#include "hotkey.hpp"
|
||||
#include "log-helper.hpp"
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xatom.h>
|
||||
@@ -25,9 +26,10 @@
|
||||
#include <QStringList>
|
||||
#include <QRegularExpression>
|
||||
#include <QLibrary>
|
||||
#ifdef USE_PROCPS
|
||||
#ifdef PROCPS_AVAILABLE
|
||||
#include <proc/readproc.h>
|
||||
#else
|
||||
#endif
|
||||
#ifdef PROCPS2_AVAILABLE
|
||||
#include <libproc2/pids.h>
|
||||
#endif
|
||||
#include <fstream>
|
||||
@@ -53,6 +55,31 @@ std::chrono::high_resolution_clock::time_point lastMouseLeftClickTime{};
|
||||
std::chrono::high_resolution_clock::time_point lastMouseMiddleClickTime{};
|
||||
std::chrono::high_resolution_clock::time_point lastMouseRightClickTime{};
|
||||
|
||||
static QLibrary *libprocps = nullptr;
|
||||
#ifdef PROCPS_AVAILABLE
|
||||
typedef PROCTAB *(*openproc_func)(int flags);
|
||||
typedef void (*closeproc_func)(PROCTAB *PT);
|
||||
typedef proc_t *(*readproc_func)(PROCTAB *__restrict const PT,
|
||||
proc_t *__restrict p);
|
||||
static openproc_func openproc_ = nullptr;
|
||||
static closeproc_func closeproc_ = nullptr;
|
||||
static readproc_func readproc_ = nullptr;
|
||||
#endif
|
||||
static bool libprocpsSupported = false;
|
||||
|
||||
static QLibrary *libproc2 = nullptr;
|
||||
#ifdef PROCPS2_AVAILABLE
|
||||
typedef int (*procps_pids_new_func)(struct pids_info **info,
|
||||
enum pids_item *items, int numitems);
|
||||
typedef struct pids_stack *(*procps_pids_get_func)(struct pids_info *info,
|
||||
enum pids_fetch_type which);
|
||||
typedef int (*procps_pids_unref_func)(struct pids_info **info);
|
||||
static procps_pids_new_func procps_pids_new_ = nullptr;
|
||||
static procps_pids_get_func procps_pids_get_ = nullptr;
|
||||
static procps_pids_unref_func procps_pids_unref_ = nullptr;
|
||||
#endif
|
||||
static bool libprocps2Supported = false;
|
||||
|
||||
Display *disp()
|
||||
{
|
||||
if (!xdisplay) {
|
||||
@@ -338,46 +365,57 @@ std::optional<std::string> GetTextInWindow(const std::string &)
|
||||
return {};
|
||||
}
|
||||
|
||||
#ifdef USE_PROCPS
|
||||
void GetProcessList(QStringList &processes)
|
||||
static void getProcessListProcps(QStringList &processes)
|
||||
{
|
||||
processes.clear();
|
||||
PROCTAB *proc = openproc(PROC_FILLSTAT);
|
||||
#ifdef PROCPS_AVAILABLE
|
||||
PROCTAB *proc = openproc_(PROC_FILLSTAT);
|
||||
proc_t proc_info;
|
||||
memset(&proc_info, 0, sizeof(proc_info));
|
||||
while (readproc(proc, &proc_info) != NULL) {
|
||||
while (readproc_(proc, &proc_info) != NULL) {
|
||||
QString procName(proc_info.cmd);
|
||||
if (!procName.isEmpty() && !processes.contains(procName)) {
|
||||
processes << procName;
|
||||
}
|
||||
}
|
||||
closeproc(proc);
|
||||
closeproc_(proc);
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
void GetProcessList(QStringList &processes)
|
||||
|
||||
static void getProcessListProcps2(QStringList &processes)
|
||||
{
|
||||
processes.clear();
|
||||
#ifdef PROCPS2_AVAILABLE
|
||||
struct pids_info *info = NULL;
|
||||
struct pids_stack *stack;
|
||||
enum pids_item Items[] = {
|
||||
PIDS_CMD,
|
||||
};
|
||||
|
||||
if (procps_pids_new(&info, Items, sizeof(Items) / sizeof(Items[0])) <
|
||||
if (procps_pids_new_(&info, Items, sizeof(Items) / sizeof(Items[0])) <
|
||||
0) {
|
||||
return;
|
||||
}
|
||||
|
||||
while ((stack = procps_pids_get(info, PIDS_FETCH_TASKS_ONLY))) {
|
||||
while ((stack = procps_pids_get_(info, PIDS_FETCH_TASKS_ONLY))) {
|
||||
auto cmd = PIDS_VAL(0, str, stack, info);
|
||||
QString procName(cmd);
|
||||
if (!procName.isEmpty() && !processes.contains(procName)) {
|
||||
processes << procName;
|
||||
}
|
||||
}
|
||||
procps_pids_unref(&info);
|
||||
}
|
||||
procps_pids_unref_(&info);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetProcessList(QStringList &processes)
|
||||
{
|
||||
processes.clear();
|
||||
if (libprocpsSupported) {
|
||||
getProcessListProcps(processes);
|
||||
return;
|
||||
}
|
||||
if (libprocps2Supported) {
|
||||
getProcessListProcps2(processes);
|
||||
}
|
||||
}
|
||||
|
||||
long getForegroundProcessPid()
|
||||
{
|
||||
@@ -517,6 +555,9 @@ static std::unordered_map<HotkeyType, long> keyTable = {
|
||||
{HotkeyType::Key_8, XK_8},
|
||||
{HotkeyType::Key_9, XK_9},
|
||||
|
||||
// Other
|
||||
{HotkeyType::Key_Tilde, XK_asciitilde},
|
||||
|
||||
{HotkeyType::Key_F1, XK_F1},
|
||||
{HotkeyType::Key_F2, XK_F2},
|
||||
{HotkeyType::Key_F3, XK_F3},
|
||||
@@ -633,6 +674,58 @@ void PressKeys(const std::vector<HotkeyType> keys, int duration)
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
static void initXtst()
|
||||
{
|
||||
libXtstHandle = new QLibrary("libXtst", nullptr);
|
||||
pressFunc = (keyPressFunc)libXtstHandle->resolve("XTestFakeKeyEvent");
|
||||
int _;
|
||||
canSimulateKeyPresses = pressFunc &&
|
||||
XQueryExtension(disp(), "XTEST", &_, &_, &_);
|
||||
}
|
||||
|
||||
static void initXss()
|
||||
{
|
||||
libXssHandle = new QLibrary("libXss", nullptr);
|
||||
allocSSFunc = (XScreenSaverAllocInfoFunc)libXssHandle->resolve(
|
||||
"XScreenSaverAllocInfo");
|
||||
querySSFunc = (XScreenSaverQueryInfoFunc)libXssHandle->resolve(
|
||||
"XScreenSaverQueryInfo");
|
||||
int _;
|
||||
canGetIdleTime = allocSSFunc && querySSFunc &&
|
||||
XQueryExtension(disp(), ScreenSaverName, &_, &_, &_);
|
||||
}
|
||||
|
||||
static void initProcps()
|
||||
{
|
||||
#ifdef PROCPS_AVAILABLE
|
||||
libprocps = new QLibrary("libprocps", nullptr);
|
||||
openproc_ = (openproc_func)libprocps->resolve("openproc");
|
||||
closeproc_ = (closeproc_func)libprocps->resolve("closeproc");
|
||||
readproc_ = (readproc_func)libprocps->resolve("readproc");
|
||||
if (openproc_ && closeproc_ && readproc_) {
|
||||
libprocpsSupported = true;
|
||||
blog(LOG_INFO, "libprocps symbols resolved successfully!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void initProc2()
|
||||
{
|
||||
#ifdef PROCPS2_AVAILABLE
|
||||
libproc2 = new QLibrary("libproc2", nullptr);
|
||||
procps_pids_new_ =
|
||||
(procps_pids_new_func)libproc2->resolve("procps_pids_new");
|
||||
procps_pids_get_ =
|
||||
(procps_pids_get_func)libproc2->resolve("procps_pids_get");
|
||||
procps_pids_unref_ =
|
||||
(procps_pids_unref_func)libproc2->resolve("procps_pids_unref");
|
||||
if (procps_pids_new_ && procps_pids_get_ && procps_pids_unref_) {
|
||||
libprocps2Supported = true;
|
||||
blog(LOG_INFO, "libproc2 symbols resolved successfully!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void PlatformInit()
|
||||
{
|
||||
auto display = disp();
|
||||
@@ -640,31 +733,26 @@ void PlatformInit()
|
||||
return;
|
||||
}
|
||||
|
||||
libXtstHandle = new QLibrary("libXtst", nullptr);
|
||||
pressFunc = (keyPressFunc)libXtstHandle->resolve("XTestFakeKeyEvent");
|
||||
int _;
|
||||
canSimulateKeyPresses = pressFunc &&
|
||||
XQueryExtension(disp(), "XTEST", &_, &_, &_);
|
||||
initXtst();
|
||||
initXss();
|
||||
initProcps();
|
||||
initProc2();
|
||||
}
|
||||
|
||||
libXssHandle = new QLibrary("libXss", nullptr);
|
||||
allocSSFunc = (XScreenSaverAllocInfoFunc)libXssHandle->resolve(
|
||||
"XScreenSaverAllocInfo");
|
||||
querySSFunc = (XScreenSaverQueryInfoFunc)libXssHandle->resolve(
|
||||
"XScreenSaverQueryInfo");
|
||||
canGetIdleTime = allocSSFunc && querySSFunc &&
|
||||
XQueryExtension(disp(), ScreenSaverName, &_, &_, &_);
|
||||
static void cleanupHelper(QLibrary *lib)
|
||||
{
|
||||
if (lib) {
|
||||
delete lib;
|
||||
lib = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformCleanup()
|
||||
{
|
||||
if (libXtstHandle) {
|
||||
delete libXtstHandle;
|
||||
libXtstHandle = nullptr;
|
||||
}
|
||||
if (libXssHandle) {
|
||||
delete libXssHandle;
|
||||
libXssHandle = nullptr;
|
||||
}
|
||||
cleanupHelper(libXtstHandle);
|
||||
cleanupHelper(libXssHandle);
|
||||
cleanupHelper(libprocps);
|
||||
cleanupHelper(libproc2);
|
||||
cleanupDisplay();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "macro-action-audio.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -36,16 +36,41 @@ const static std::map<MacroActionAudio::FadeType, std::string> fadeTypes = {
|
||||
"AdvSceneSwitcher.action.audio.fade.type.rate"},
|
||||
};
|
||||
|
||||
namespace {
|
||||
struct FadeInfo {
|
||||
std::atomic_bool active = {false};
|
||||
std::atomic_int id = {0};
|
||||
};
|
||||
}
|
||||
|
||||
static FadeInfo masterAudioFade;
|
||||
static std::unordered_map<std::string, FadeInfo> audioFades;
|
||||
|
||||
constexpr auto fadeInterval = std::chrono::milliseconds(100);
|
||||
constexpr float minFade = 0.000001f;
|
||||
|
||||
// For backwards compatibility
|
||||
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(29, 0, 0)
|
||||
static float get_master_volume()
|
||||
{
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
static void set_master_volume(float)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
auto get_master_volume = obs_get_master_volume;
|
||||
auto set_master_volume = obs_set_master_volume;
|
||||
#endif
|
||||
|
||||
void MacroActionAudio::SetFadeActive(bool value)
|
||||
{
|
||||
if (_action == Action::SOURCE_VOLUME) {
|
||||
switcher->activeAudioFades[_audioSource.ToString()].active =
|
||||
value;
|
||||
audioFades[_audioSource.ToString()].active = value;
|
||||
} else {
|
||||
switcher->masterAudioFade.active = value;
|
||||
masterAudioFade.active = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,14 +78,13 @@ bool MacroActionAudio::FadeActive()
|
||||
{
|
||||
bool active = true;
|
||||
if (_action == Action::SOURCE_VOLUME) {
|
||||
auto it = switcher->activeAudioFades.find(
|
||||
_audioSource.ToString());
|
||||
if (it == switcher->activeAudioFades.end()) {
|
||||
auto it = audioFades.find(_audioSource.ToString());
|
||||
if (it == audioFades.end()) {
|
||||
return false;
|
||||
}
|
||||
active = it->second.active;
|
||||
} else {
|
||||
active = switcher->masterAudioFade.active;
|
||||
active = masterAudioFade.active;
|
||||
}
|
||||
|
||||
return active;
|
||||
@@ -70,14 +94,13 @@ std::atomic_int *MacroActionAudio::GetFadeIdPtr()
|
||||
{
|
||||
|
||||
if (_action == Action::SOURCE_VOLUME) {
|
||||
auto it = switcher->activeAudioFades.find(
|
||||
_audioSource.ToString());
|
||||
if (it == switcher->activeAudioFades.end()) {
|
||||
auto it = audioFades.find(_audioSource.ToString());
|
||||
if (it == audioFades.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &it->second.id;
|
||||
}
|
||||
return &switcher->masterAudioFade.id;
|
||||
return &masterAudioFade.id;
|
||||
}
|
||||
|
||||
void MacroActionAudio::SetVolume(float vol)
|
||||
@@ -87,7 +110,7 @@ void MacroActionAudio::SetVolume(float vol)
|
||||
obs_source_set_volume(s, vol);
|
||||
obs_source_release(s);
|
||||
} else {
|
||||
obs_set_master_volume(vol);
|
||||
set_master_volume(vol);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +125,7 @@ float MacroActionAudio::GetVolume()
|
||||
curVol = obs_source_get_volume(s);
|
||||
obs_source_release(s);
|
||||
} else {
|
||||
curVol = obs_get_master_volume();
|
||||
curVol = get_master_volume();
|
||||
}
|
||||
return curVol;
|
||||
}
|
||||
@@ -287,15 +310,13 @@ std::string MacroActionAudio::GetShortDesc() const
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[action, name] : actionTypes) {
|
||||
if (action == MacroActionAudio::Action::MONITOR) {
|
||||
if (obs_audio_monitoring_available()) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(action));
|
||||
}
|
||||
} else {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(action));
|
||||
if (action == MacroActionAudio::Action::MONITOR &&
|
||||
!obs_audio_monitoring_available()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(action));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -473,6 +494,14 @@ void MacroActionAudioEdit::SetWidgetVisibility()
|
||||
_wait->setVisible(hasVolumeControl(_entryData->_action) &&
|
||||
_entryData->_fade);
|
||||
|
||||
// TODO: Remove this in a future version:
|
||||
if (_entryData->_action != MacroActionAudio::Action::MASTER_VOLUME &&
|
||||
obs_get_version() >= MAKE_SEMANTIC_VERSION(29, 0, 0)) {
|
||||
_actions->removeItem(_actions->findText(obs_module_text(
|
||||
actionTypes.at(MacroActionAudio::Action::MASTER_VOLUME)
|
||||
.c_str())));
|
||||
}
|
||||
|
||||
updateGeometry();
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
256
src/macro-core/macro-action-clipboard.cpp
Normal file
256
src/macro-core/macro-action-clipboard.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
#include "macro-action-clipboard.hpp"
|
||||
#include "curl-helper.hpp"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QImage>
|
||||
#include <QMimeData>
|
||||
|
||||
namespace advss {
|
||||
|
||||
const std::string MacroActionClipboard::id = "clipboard";
|
||||
|
||||
bool MacroActionClipboard::_registered = MacroActionFactory::Register(
|
||||
MacroActionClipboard::id,
|
||||
{MacroActionClipboard::Create, MacroActionClipboardEdit::Create,
|
||||
"AdvSceneSwitcher.action.clipboard"});
|
||||
|
||||
const static std::map<MacroActionClipboard::Action, std::string> actionTypes = {
|
||||
{MacroActionClipboard::Action::COPY_TEXT,
|
||||
"AdvSceneSwitcher.action.clipboard.type.copy.text"},
|
||||
{MacroActionClipboard::Action::COPY_IMAGE,
|
||||
"AdvSceneSwitcher.action.clipboard.type.copy.image"},
|
||||
};
|
||||
|
||||
static size_t writeCallback(void *ptr, size_t size, size_t nmemb,
|
||||
QByteArray *buffer)
|
||||
{
|
||||
buffer->append((char *)ptr, nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
static std::optional<QImage> getImageFromUrl(const char *url)
|
||||
{
|
||||
QByteArray response;
|
||||
|
||||
CurlHelper::SetOpt(CURLOPT_URL, url);
|
||||
CurlHelper::SetOpt(CURLOPT_HTTPGET, 1L);
|
||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT_MS, 30000);
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, writeCallback);
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &response);
|
||||
auto code = CurlHelper::Perform();
|
||||
|
||||
if (code != CURLE_OK) {
|
||||
blog(LOG_WARNING,
|
||||
"Retrieving image failed in %s with error: %s", __func__,
|
||||
CurlHelper::GetError(code));
|
||||
return {};
|
||||
}
|
||||
|
||||
return QImage::fromData(response);
|
||||
}
|
||||
|
||||
static void setMimeTypeParams(ClipboardQueueParams *params,
|
||||
QClipboard *clipboard)
|
||||
{
|
||||
auto mimeData = clipboard->mimeData();
|
||||
if (!mimeData) {
|
||||
return;
|
||||
}
|
||||
auto mimeTypeList = mimeData->formats();
|
||||
if (mimeTypeList.empty()) {
|
||||
return;
|
||||
}
|
||||
params->mimeTypePrimary = mimeTypeList.first().toStdString();
|
||||
params->mimeTypeAll = mimeTypeList.join(" ").toStdString();
|
||||
}
|
||||
|
||||
static void copyText(void *param)
|
||||
{
|
||||
auto params = static_cast<ClipboardTextQueueParams *>(param);
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
|
||||
clipboard->setText(params->text.c_str());
|
||||
|
||||
setMimeTypeParams(params, clipboard);
|
||||
}
|
||||
|
||||
static void copyImageFromUrl(void *param)
|
||||
{
|
||||
auto params = static_cast<ClipboardImageQueueParams *>(param);
|
||||
auto url = params->url.c_str();
|
||||
auto image = getImageFromUrl(url);
|
||||
|
||||
if (!image || (*image).isNull()) {
|
||||
blog(LOG_WARNING, "Failed to convert %s URL to image!", url);
|
||||
return;
|
||||
}
|
||||
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setImage(*image);
|
||||
|
||||
setMimeTypeParams(params, clipboard);
|
||||
}
|
||||
|
||||
bool MacroActionClipboard::PerformAction()
|
||||
{
|
||||
switch (_action) {
|
||||
case Action::COPY_TEXT: {
|
||||
ClipboardTextQueueParams params{"", "", _text};
|
||||
obs_queue_task(OBS_TASK_UI, copyText, ¶ms, true);
|
||||
SetTempVarValues(params);
|
||||
break;
|
||||
}
|
||||
case Action::COPY_IMAGE: {
|
||||
ClipboardImageQueueParams params{"", "", _url};
|
||||
obs_queue_task(OBS_TASK_UI, copyImageFromUrl, ¶ms, true);
|
||||
SetTempVarValues(params);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroActionClipboard::SetupTempVars()
|
||||
{
|
||||
MacroAction::SetupTempVars();
|
||||
|
||||
AddTempvar(
|
||||
"mimeType.primary",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.clipboard.mimeType.primary"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.clipboard.mimeType.primary.description"));
|
||||
AddTempvar(
|
||||
"mimeType.all",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.clipboard.mimeType.all"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.clipboard.mimeType.all.description"));
|
||||
}
|
||||
|
||||
void MacroActionClipboard::SetTempVarValues(const ClipboardQueueParams ¶ms)
|
||||
{
|
||||
SetTempVarValue("mimeType.primary", params.mimeTypePrimary);
|
||||
SetTempVarValue("mimeType.all", params.mimeTypeAll);
|
||||
}
|
||||
|
||||
bool MacroActionClipboard::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
_text.Save(obj, "text");
|
||||
_url.Save(obj, "url");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroActionClipboard::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
_text.Load(obj, "text");
|
||||
_url.Load(obj, "url");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[action, name] : actionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(action));
|
||||
}
|
||||
}
|
||||
|
||||
MacroActionClipboardEdit::MacroActionClipboardEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionClipboard> entryData)
|
||||
: QWidget(parent),
|
||||
_actions(new FilterComboBox(this)),
|
||||
_text(new VariableLineEdit(this)),
|
||||
_url(new VariableLineEdit(this))
|
||||
{
|
||||
populateActionSelection(_actions);
|
||||
_url->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.action.clipboard.copy.image.url.tooltip"));
|
||||
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
QWidget::connect(_text, SIGNAL(editingFinished()), this,
|
||||
SLOT(TextChanged()));
|
||||
QWidget::connect(_url, SIGNAL(editingFinished()), this,
|
||||
SLOT(UrlChanged()));
|
||||
|
||||
auto mainLayout = new QHBoxLayout();
|
||||
mainLayout->addWidget(_actions);
|
||||
mainLayout->addWidget(_text);
|
||||
mainLayout->addWidget(_url);
|
||||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroActionClipboardEdit::ActionChanged(int index)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<MacroActionClipboard::Action>(
|
||||
_actions->itemData(index).toInt());
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionClipboardEdit::TextChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_text = _text->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionClipboardEdit::UrlChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_url = _url->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroActionClipboardEdit::SetWidgetVisibility()
|
||||
{
|
||||
_text->setVisible(_entryData->_action ==
|
||||
MacroActionClipboard::Action::COPY_TEXT);
|
||||
_url->setVisible(_entryData->_action ==
|
||||
MacroActionClipboard::Action::COPY_IMAGE);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionClipboardEdit::UpdateEntryData()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_actions->setCurrentIndex(
|
||||
_actions->findData(static_cast<int>(_entryData->_action)));
|
||||
_text->setText(_entryData->_text);
|
||||
_url->setText(_entryData->_url);
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
89
src/macro-core/macro-action-clipboard.hpp
Normal file
89
src/macro-core/macro-action-clipboard.hpp
Normal file
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "filter-combo-box.hpp"
|
||||
|
||||
#include <variable-line-edit.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct ClipboardQueueParams {
|
||||
std::string mimeTypePrimary;
|
||||
std::string mimeTypeAll;
|
||||
};
|
||||
|
||||
struct ClipboardTextQueueParams : ClipboardQueueParams {
|
||||
StringVariable text;
|
||||
};
|
||||
|
||||
struct ClipboardImageQueueParams : ClipboardQueueParams {
|
||||
StringVariable url;
|
||||
};
|
||||
|
||||
class MacroActionClipboard : public MacroAction {
|
||||
public:
|
||||
MacroActionClipboard(Macro *m) : MacroAction(m) {}
|
||||
static std::shared_ptr<MacroAction> Create(Macro *m)
|
||||
{
|
||||
return std::make_shared<MacroActionClipboard>(m);
|
||||
}
|
||||
std::string GetId() const { return id; };
|
||||
|
||||
bool PerformAction();
|
||||
bool Save(obs_data_t *obj) const;
|
||||
bool Load(obs_data_t *obj);
|
||||
|
||||
enum class Action {
|
||||
COPY_TEXT,
|
||||
COPY_IMAGE,
|
||||
};
|
||||
|
||||
Action _action = Action::COPY_TEXT;
|
||||
|
||||
StringVariable _text = obs_module_text(
|
||||
"AdvSceneSwitcher.action.clipboard.copy.text.text.placeholder");
|
||||
StringVariable _url = obs_module_text(
|
||||
"AdvSceneSwitcher.action.clipboard.copy.image.url.placeholder");
|
||||
|
||||
private:
|
||||
void SetupTempVars();
|
||||
void SetTempVarValues(const ClipboardQueueParams ¶ms);
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionClipboardEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroActionClipboardEdit(
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroActionClipboard> entryData = nullptr);
|
||||
static QWidget *Create(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
return new MacroActionClipboardEdit(
|
||||
parent, std::dynamic_pointer_cast<MacroActionClipboard>(
|
||||
action));
|
||||
}
|
||||
void UpdateEntryData();
|
||||
|
||||
protected:
|
||||
std::shared_ptr<MacroActionClipboard> _entryData;
|
||||
|
||||
private slots:
|
||||
void ActionChanged(int index);
|
||||
void TextChanged();
|
||||
void UrlChanged();
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
bool _loading = true;
|
||||
|
||||
FilterComboBox *_actions;
|
||||
VariableLineEdit *_text;
|
||||
VariableLineEdit *_url;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-properties.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "macro-action-scene-switch.hpp"
|
||||
#include "section.hpp"
|
||||
#include "switch-button.hpp"
|
||||
@@ -10,61 +12,9 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::map<std::string, MacroActionInfo> &MacroActionFactory::GetMap()
|
||||
{
|
||||
static std::map<std::string, MacroActionInfo> _methods;
|
||||
return _methods;
|
||||
}
|
||||
|
||||
bool MacroActionFactory::Register(const std::string &id, MacroActionInfo info)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it == GetMap().end()) {
|
||||
GetMap()[id] = info;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
|
||||
Macro *m)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end())
|
||||
return it->second._createFunc(m);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QWidget *MacroActionFactory::CreateWidget(const std::string &id,
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end())
|
||||
return it->second._createWidgetFunc(parent, action);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string MacroActionFactory::GetActionName(const std::string &id)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._name;
|
||||
}
|
||||
return "unknown action";
|
||||
}
|
||||
|
||||
std::string MacroActionFactory::GetIdByName(const QString &name)
|
||||
{
|
||||
for (auto it : GetMap()) {
|
||||
if (name == obs_module_text(it.second._name.c_str())) {
|
||||
return it.first;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (auto &[_, action] : MacroActionFactory::GetActionTypes()) {
|
||||
for (const auto &[_, action] : MacroActionFactory::GetActionTypes()) {
|
||||
QString entry(obs_module_text(action._name.c_str()));
|
||||
if (list->findText(entry) == -1) {
|
||||
list->addItem(entry);
|
||||
@@ -80,7 +30,8 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> *entryData,
|
||||
const std::string &id)
|
||||
: MacroSegmentEdit(switcher->macroProperties._highlightActions, parent),
|
||||
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightActions,
|
||||
parent),
|
||||
_actionSelection(new FilterComboBox()),
|
||||
_enable(new SwitchButton()),
|
||||
_entryData(entryData)
|
||||
@@ -134,10 +85,11 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
auto idx = _entryData->get()->GetIndex();
|
||||
auto macro = _entryData->get()->GetMacro();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
_entryData->reset();
|
||||
*_entryData = MacroActionFactory::Create(id, macro);
|
||||
(*_entryData)->SetIndex(idx);
|
||||
(*_entryData)->PostLoad();
|
||||
}
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
@@ -184,7 +136,7 @@ void MacroActionEdit::ActionEnableChanged(bool value)
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
(*_entryData)->SetEnabled(value);
|
||||
SetDisableEffect(!value);
|
||||
}
|
||||
@@ -204,7 +156,7 @@ void MacroActionEdit::SetEnableAppearance(bool value)
|
||||
SetDisableEffect(!value);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroSegment> MacroActionEdit::Data()
|
||||
std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
||||
{
|
||||
return *_entryData;
|
||||
}
|
||||
@@ -228,7 +180,7 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
|
||||
id = temp.GetId();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
macro->Actions().emplace(
|
||||
macro->Actions().begin() + idx,
|
||||
MacroActionFactory::Create(id, macro.get()));
|
||||
@@ -236,6 +188,7 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
|
||||
auto data = obs_data_create();
|
||||
macro->Actions().at(idx - 1)->Save(data);
|
||||
macro->Actions().at(idx)->Load(data);
|
||||
macro->Actions().at(idx)->PostLoad();
|
||||
obs_data_release(data);
|
||||
}
|
||||
macro->UpdateActionIndices();
|
||||
@@ -278,11 +231,11 @@ void AdvSceneSwitcher::RemoveMacroAction(int idx)
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
ui->actionsList->Remove(idx);
|
||||
macro->Actions().erase(macro->Actions().begin() + idx);
|
||||
switcher->abortMacroWait = true;
|
||||
switcher->macroWaitCv.notify_all();
|
||||
SetMacroAbortWait(true);
|
||||
GetMacroWaitCV().notify_all();
|
||||
macro->UpdateActionIndices();
|
||||
SetActionData(*macro);
|
||||
}
|
||||
@@ -423,7 +376,7 @@ void AdvSceneSwitcher::SwapActions(Macro *m, int pos1, int pos2)
|
||||
std::swap(pos1, pos2);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
iter_swap(m->Actions().begin() + pos1, m->Actions().begin() + pos2);
|
||||
m->UpdateActionIndices();
|
||||
auto widget1 = static_cast<MacroActionEdit *>(
|
||||
@@ -483,7 +436,7 @@ void AdvSceneSwitcher::MacroElseActionReorder(int to, int from)
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
auto action = macro->ElseActions().at(from);
|
||||
macro->ElseActions().erase(macro->ElseActions().begin() + from);
|
||||
macro->ElseActions().insert(macro->ElseActions().begin() + to,
|
||||
@@ -516,7 +469,7 @@ void AdvSceneSwitcher::AddMacroElseAction(int idx)
|
||||
id = temp.GetId();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
macro->ElseActions().emplace(
|
||||
macro->ElseActions().begin() + idx,
|
||||
MacroActionFactory::Create(id, macro.get()));
|
||||
@@ -525,6 +478,7 @@ void AdvSceneSwitcher::AddMacroElseAction(int idx)
|
||||
macro->ElseActions().at(idx - 1)->Save(data);
|
||||
macro->ElseActions().at(idx)->Load(data);
|
||||
}
|
||||
macro->ElseActions().at(idx)->PostLoad();
|
||||
macro->UpdateElseActionIndices();
|
||||
ui->elseActionsList->Insert(
|
||||
idx, new MacroActionEdit(
|
||||
@@ -547,11 +501,11 @@ void AdvSceneSwitcher::RemoveMacroElseAction(int idx)
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
ui->elseActionsList->Remove(idx);
|
||||
macro->ElseActions().erase(macro->ElseActions().begin() + idx);
|
||||
switcher->abortMacroWait = true;
|
||||
switcher->macroWaitCv.notify_all();
|
||||
SetMacroAbortWait(true);
|
||||
GetMacroWaitCV().notify_all();
|
||||
macro->UpdateElseActionIndices();
|
||||
SetActionData(*macro);
|
||||
}
|
||||
@@ -569,7 +523,7 @@ void AdvSceneSwitcher::SwapElseActions(Macro *m, int pos1, int pos2)
|
||||
std::swap(pos1, pos2);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
iter_swap(m->ElseActions().begin() + pos1,
|
||||
m->ElseActions().begin() + pos2);
|
||||
m->UpdateElseActionIndices();
|
||||
@@ -632,7 +586,7 @@ void AdvSceneSwitcher::MacroActionReorder(int to, int from)
|
||||
return;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto lock = LockContext();
|
||||
auto action = macro->Actions().at(from);
|
||||
macro->Actions().erase(macro->Actions().begin() + from);
|
||||
macro->Actions().insert(macro->Actions().begin() + to, action);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "macro-action.hpp"
|
||||
#include "macro-action-factory.hpp"
|
||||
#include "filter-combo-box.hpp"
|
||||
|
||||
#include <memory>
|
||||
@@ -8,32 +9,6 @@ namespace advss {
|
||||
|
||||
class SwitchButton;
|
||||
|
||||
struct MacroActionInfo {
|
||||
using TCreateMethod = std::shared_ptr<MacroAction> (*)(Macro *m);
|
||||
using TCreateWidgetMethod = QWidget *(*)(QWidget *parent,
|
||||
std::shared_ptr<MacroAction>);
|
||||
TCreateMethod _createFunc = nullptr;
|
||||
TCreateWidgetMethod _createWidgetFunc = nullptr;
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
class MacroActionFactory {
|
||||
public:
|
||||
MacroActionFactory() = delete;
|
||||
|
||||
static bool Register(const std::string &id, MacroActionInfo);
|
||||
static std::shared_ptr<MacroAction> Create(const std::string &id,
|
||||
Macro *m);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action);
|
||||
static auto GetActionTypes() { return GetMap(); }
|
||||
static std::string GetActionName(const std::string &id);
|
||||
static std::string GetIdByName(const QString &name);
|
||||
|
||||
private:
|
||||
static std::map<std::string, MacroActionInfo> &GetMap();
|
||||
};
|
||||
|
||||
class MacroActionEdit : public MacroSegmentEdit {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -50,7 +25,7 @@ private slots:
|
||||
void UpdateActionState();
|
||||
|
||||
private:
|
||||
std::shared_ptr<MacroSegment> Data();
|
||||
std::shared_ptr<MacroSegment> Data() const;
|
||||
void SetDisableEffect(bool);
|
||||
void SetEnableAppearance(bool);
|
||||
|
||||
|
||||
57
src/macro-core/macro-action-factory.cpp
Normal file
57
src/macro-core/macro-action-factory.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
#include "macro-action-factory.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::map<std::string, MacroActionInfo> &MacroActionFactory::GetMap()
|
||||
{
|
||||
static std::map<std::string, MacroActionInfo> _methods;
|
||||
return _methods;
|
||||
}
|
||||
|
||||
bool MacroActionFactory::Register(const std::string &id, MacroActionInfo info)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it == GetMap().end()) {
|
||||
GetMap()[id] = info;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
|
||||
Macro *m)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end())
|
||||
return it->second._create(m);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QWidget *MacroActionFactory::CreateWidget(const std::string &id,
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end())
|
||||
return it->second._createWidget(parent, action);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string MacroActionFactory::GetActionName(const std::string &id)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._name;
|
||||
}
|
||||
return "unknown action";
|
||||
}
|
||||
|
||||
std::string MacroActionFactory::GetIdByName(const QString &name)
|
||||
{
|
||||
for (auto it : GetMap()) {
|
||||
if (name == obs_module_text(it.second._name.c_str())) {
|
||||
return it.first;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
34
src/macro-core/macro-action-factory.hpp
Normal file
34
src/macro-core/macro-action-factory.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "macro-action.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct MacroActionInfo {
|
||||
using CreateAction = std::shared_ptr<MacroAction> (*)(Macro *m);
|
||||
using CreateActionWidget = QWidget *(*)(QWidget *parent,
|
||||
std::shared_ptr<MacroAction>);
|
||||
CreateAction _create = nullptr;
|
||||
CreateActionWidget _createWidget = nullptr;
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
class MacroActionFactory {
|
||||
public:
|
||||
MacroActionFactory() = delete;
|
||||
|
||||
static bool Register(const std::string &id, MacroActionInfo);
|
||||
static std::shared_ptr<MacroAction> Create(const std::string &id,
|
||||
Macro *m);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action);
|
||||
static auto GetActionTypes() { return GetMap(); }
|
||||
static std::string GetActionName(const std::string &id);
|
||||
static std::string GetIdByName(const QString &name);
|
||||
|
||||
private:
|
||||
static std::map<std::string, MacroActionInfo> &GetMap();
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -21,26 +21,69 @@ const static std::map<MacroActionFilter::Action, std::string> actionTypes = {
|
||||
"AdvSceneSwitcher.action.filter.type.settings"},
|
||||
};
|
||||
|
||||
bool MacroActionFilter::PerformAction()
|
||||
const static std::map<MacroActionFilter::SettingsInputMethod, std::string>
|
||||
inputMethods = {
|
||||
{MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL,
|
||||
"AdvSceneSwitcher.action.filter.inputMethod.individualManual"},
|
||||
{MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR,
|
||||
"AdvSceneSwitcher.action.filter.inputMethod.individualTempvar"},
|
||||
{MacroActionFilter::SettingsInputMethod::JSON_STRING,
|
||||
"AdvSceneSwitcher.action.filter.inputMethod.json"},
|
||||
};
|
||||
|
||||
static void performActionHelper(
|
||||
MacroActionFilter::Action action, const OBSWeakSource &filter,
|
||||
MacroActionFilter::SettingsInputMethod settingsInputMethod,
|
||||
const SourceSetting &setting, const std::string &manualSettingValue,
|
||||
const TempVariableRef &tempVar, Macro *macro,
|
||||
const StringVariable &settingsString)
|
||||
{
|
||||
auto s = obs_weak_source_get_source(_filter.GetFilter(_source));
|
||||
switch (_action) {
|
||||
case Action::ENABLE:
|
||||
obs_source_set_enabled(s, true);
|
||||
OBSSourceAutoRelease source = obs_weak_source_get_source(filter);
|
||||
switch (action) {
|
||||
case MacroActionFilter::Action::ENABLE:
|
||||
obs_source_set_enabled(source, true);
|
||||
break;
|
||||
case Action::DISABLE:
|
||||
obs_source_set_enabled(s, false);
|
||||
case MacroActionFilter::Action::DISABLE:
|
||||
obs_source_set_enabled(source, false);
|
||||
break;
|
||||
case Action::TOGGLE:
|
||||
obs_source_set_enabled(s, !obs_source_enabled(s));
|
||||
case MacroActionFilter::Action::TOGGLE:
|
||||
obs_source_set_enabled(source, !obs_source_enabled(source));
|
||||
break;
|
||||
case Action::SETTINGS:
|
||||
SetSourceSettings(s, _settings);
|
||||
case MacroActionFilter::Action::SETTINGS:
|
||||
switch (settingsInputMethod) {
|
||||
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL:
|
||||
SetSourceSetting(source, setting, manualSettingValue);
|
||||
break;
|
||||
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR: {
|
||||
auto var = tempVar.GetTempVariable(macro);
|
||||
if (!var) {
|
||||
break;
|
||||
}
|
||||
auto value = var->Value();
|
||||
if (!value) {
|
||||
break;
|
||||
}
|
||||
SetSourceSetting(source, setting, *value);
|
||||
break;
|
||||
}
|
||||
case MacroActionFilter::SettingsInputMethod::JSON_STRING:
|
||||
SetSourceSettings(source, settingsString);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
obs_source_release(s);
|
||||
}
|
||||
|
||||
bool MacroActionFilter::PerformAction()
|
||||
{
|
||||
auto filters = _filter.GetFilters(_source);
|
||||
for (const auto &filter : filters) {
|
||||
performActionHelper(_action, filter, _settingsInputMethod,
|
||||
_setting, _manualSettingValue, _tempVar,
|
||||
GetMacro(), _settingsString);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -64,7 +107,12 @@ bool MacroActionFilter::Save(obs_data_t *obj) const
|
||||
_source.Save(obj);
|
||||
_filter.Save(obj, "filter");
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
_settings.Save(obj, "settings");
|
||||
obs_data_set_int(obj, "inputMethod",
|
||||
static_cast<int>(_settingsInputMethod));
|
||||
_setting.Save(obj);
|
||||
_manualSettingValue.Save(obj, "manualSettingValue");
|
||||
_tempVar.Save(obj);
|
||||
_settingsString.Save(obj, "settings");
|
||||
obs_data_set_int(obj, "version", 1);
|
||||
return true;
|
||||
}
|
||||
@@ -85,7 +133,17 @@ bool MacroActionFilter::Load(obs_data_t *obj)
|
||||
} else {
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
}
|
||||
_settings.Load(obj, "settings");
|
||||
// TODO: Remove fallback in future version
|
||||
if (obs_data_has_user_value(obj, "inputMethod")) {
|
||||
_settingsInputMethod = static_cast<SettingsInputMethod>(
|
||||
obs_data_get_int(obj, "inputMethod"));
|
||||
} else {
|
||||
_settingsInputMethod = SettingsInputMethod::JSON_STRING;
|
||||
}
|
||||
_setting.Load(obj);
|
||||
_settingsString.Load(obj, "settings");
|
||||
_manualSettingValue.Load(obj, "manualSettingValue");
|
||||
_tempVar.Load(obj, GetMacro());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -104,6 +162,15 @@ static inline void populateActionSelection(QComboBox *list)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void populateSettingsInputMethods(QComboBox *list)
|
||||
{
|
||||
list->clear();
|
||||
for (const auto &[value, name] : inputMethods) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
|
||||
MacroActionFilterEdit::MacroActionFilterEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionFilter> entryData)
|
||||
: QWidget(parent),
|
||||
@@ -112,7 +179,12 @@ MacroActionFilterEdit::MacroActionFilterEdit(
|
||||
_actions(new QComboBox()),
|
||||
_getSettings(new QPushButton(obs_module_text(
|
||||
"AdvSceneSwitcher.action.filter.getSettings"))),
|
||||
_settings(new VariableTextEdit(this))
|
||||
_settingsLayout(new QHBoxLayout()),
|
||||
_settingsInputMethods(new QComboBox(this)),
|
||||
_manualSettingValue(new VariableTextEdit(this, 5, 1, 1)),
|
||||
_tempVars(new TempVariableSelection(this)),
|
||||
_filterSettings(new SourceSettingSelection(this)),
|
||||
_settingsString(new VariableTextEdit(this))
|
||||
{
|
||||
_filters->setSizeAdjustPolicy(QComboBox::AdjustToContents);
|
||||
|
||||
@@ -121,6 +193,8 @@ MacroActionFilterEdit::MacroActionFilterEdit(
|
||||
sources.sort();
|
||||
_sources->SetSourceNameList(sources);
|
||||
|
||||
populateSettingsInputMethods(_settingsInputMethods);
|
||||
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
QWidget::connect(_sources,
|
||||
@@ -131,27 +205,48 @@ MacroActionFilterEdit::MacroActionFilterEdit(
|
||||
SLOT(FilterChanged(const FilterSelection &)));
|
||||
QWidget::connect(_getSettings, SIGNAL(clicked()), this,
|
||||
SLOT(GetSettingsClicked()));
|
||||
QWidget::connect(_settings, SIGNAL(textChanged()), this,
|
||||
SLOT(SettingsChanged()));
|
||||
QWidget::connect(_settingsString, SIGNAL(textChanged()), this,
|
||||
SLOT(SettingsStringChanged()));
|
||||
QWidget::connect(_tempVars,
|
||||
SIGNAL(SelectionChanged(const TempVariableRef &)),
|
||||
this, SLOT(SelectionChanged(const TempVariableRef &)));
|
||||
QWidget::connect(_settingsInputMethods,
|
||||
SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(SettingsInputMethodChanged(int)));
|
||||
QWidget::connect(_manualSettingValue, SIGNAL(textChanged()), this,
|
||||
SLOT(ManualSettingsValueChanged()));
|
||||
QWidget::connect(_filterSettings,
|
||||
SIGNAL(SelectionChanged(const SourceSetting &)), this,
|
||||
SLOT(SelectionChanged(const SourceSetting &)));
|
||||
|
||||
QHBoxLayout *entryLayout = new QHBoxLayout;
|
||||
auto entrylayout = new QHBoxLayout;
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{sources}}", _sources}, {"{{filters}}", _filters},
|
||||
{"{{actions}}", _actions}, {"{{settings}}", _settings},
|
||||
{"{{sources}}", _sources},
|
||||
{"{{filters}}", _filters},
|
||||
{"{{actions}}", _actions},
|
||||
{"{{settings}}", _filterSettings},
|
||||
{"{{settingsInputMethod}}", _settingsInputMethods},
|
||||
{"{{settingValue}}", _manualSettingValue},
|
||||
{"{{tempVar}}", _tempVars},
|
||||
{"{{getSettings}}", _getSettings},
|
||||
};
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.filter.entry"),
|
||||
entryLayout, widgetPlaceholders);
|
||||
entrylayout, widgetPlaceholders);
|
||||
_settingsLayout->setContentsMargins(0, 0, 0, 0);
|
||||
PlaceWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.action.filter.entry.settings"),
|
||||
_settingsLayout, widgetPlaceholders);
|
||||
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout;
|
||||
auto buttonLayout = new QHBoxLayout;
|
||||
buttonLayout->addWidget(_getSettings);
|
||||
buttonLayout->addStretch();
|
||||
buttonLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(entryLayout);
|
||||
mainLayout->addWidget(_settings);
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(entrylayout);
|
||||
mainLayout->addLayout(_settingsLayout);
|
||||
mainLayout->addWidget(_settingsString);
|
||||
mainLayout->addLayout(buttonLayout);
|
||||
setLayout(mainLayout);
|
||||
|
||||
@@ -169,12 +264,16 @@ void MacroActionFilterEdit::UpdateEntryData()
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
_sources->SetSource(_entryData->_source);
|
||||
_filters->SetFilter(_entryData->_source, _entryData->_filter);
|
||||
_settings->setPlainText(_entryData->_settings);
|
||||
SetWidgetVisibility(_entryData->_action ==
|
||||
MacroActionFilter::Action::SETTINGS);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
_settingsString->setPlainText(_entryData->_settingsString);
|
||||
const auto filters =
|
||||
_entryData->_filter.GetFilters(_entryData->_source);
|
||||
_filterSettings->SetSource(filters.empty() ? nullptr : filters.at(0));
|
||||
_filterSettings->SetSetting(_entryData->_setting);
|
||||
_settingsInputMethods->setCurrentIndex(_settingsInputMethods->findData(
|
||||
static_cast<int>(_entryData->_settingsInputMethod)));
|
||||
_tempVars->SetVariable(_entryData->_tempVar);
|
||||
_manualSettingValue->setPlainText(_entryData->_manualSettingValue);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SourceChanged(const SourceSelection &source)
|
||||
@@ -193,8 +292,13 @@ void MacroActionFilterEdit::FilterChanged(const FilterSelection &filter)
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_filter = filter;
|
||||
{
|
||||
auto lock = LockContext();
|
||||
_entryData->_filter = filter;
|
||||
}
|
||||
const auto filters =
|
||||
_entryData->_filter.GetFilters(_entryData->_source);
|
||||
_filterSettings->SetSource(filters.empty() ? nullptr : filters.at(0));
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
@@ -207,38 +311,130 @@ void MacroActionFilterEdit::ActionChanged(int value)
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<MacroActionFilter::Action>(value);
|
||||
SetWidgetVisibility(_entryData->_action ==
|
||||
MacroActionFilter::Action::SETTINGS);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::GetSettingsClicked()
|
||||
{
|
||||
if (_loading || !_entryData ||
|
||||
!_entryData->_filter.GetFilter(_entryData->_source)) {
|
||||
_entryData->_filter.GetFilters(_entryData->_source).empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
_settings->setPlainText(FormatJsonString(GetSourceSettings(
|
||||
_entryData->_filter.GetFilter(_entryData->_source))));
|
||||
switch (_entryData->_settingsInputMethod) {
|
||||
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL: {
|
||||
const auto filters =
|
||||
_entryData->_filter.GetFilters(_entryData->_source);
|
||||
_manualSettingValue->setPlainText(GetSourceSettingValue(
|
||||
filters.empty() ? nullptr : filters.at(0),
|
||||
_entryData->_setting));
|
||||
break;
|
||||
}
|
||||
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR:
|
||||
break;
|
||||
case MacroActionFilter::SettingsInputMethod::JSON_STRING: {
|
||||
const auto filters =
|
||||
_entryData->_filter.GetFilters(_entryData->_source);
|
||||
_settingsString->setPlainText(
|
||||
FormatJsonString(GetSourceSettings(
|
||||
filters.empty() ? nullptr : filters.at(0))));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SettingsChanged()
|
||||
void MacroActionFilterEdit::SettingsStringChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_settings = _settings->toPlainText().toStdString();
|
||||
_entryData->_settingsString =
|
||||
_settingsString->toPlainText().toStdString();
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SetWidgetVisibility(bool showSettings)
|
||||
void MacroActionFilterEdit::SettingsInputMethodChanged(int idx)
|
||||
{
|
||||
_settings->setVisible(showSettings);
|
||||
_getSettings->setVisible(showSettings);
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_settingsInputMethod =
|
||||
static_cast<MacroActionFilter::SettingsInputMethod>(
|
||||
_settingsInputMethods->itemData(idx).toInt());
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SelectionChanged(const TempVariableRef &var)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_tempVar = var;
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SelectionChanged(const SourceSetting &setting)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_setting = setting;
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::ManualSettingsValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_manualSettingValue =
|
||||
_manualSettingValue->toPlainText().toStdString();
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionFilterEdit::SetWidgetVisibility()
|
||||
{
|
||||
SetLayoutVisible(_settingsLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionFilter::Action::SETTINGS);
|
||||
_filterSettings->setVisible(
|
||||
_entryData->_action == MacroActionFilter::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod !=
|
||||
MacroActionFilter::SettingsInputMethod::JSON_STRING);
|
||||
_settingsString->setVisible(
|
||||
_entryData->_action == MacroActionFilter::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod ==
|
||||
MacroActionFilter::SettingsInputMethod::JSON_STRING);
|
||||
_getSettings->setVisible(_entryData->_action ==
|
||||
MacroActionFilter::Action::SETTINGS);
|
||||
_tempVars->setVisible(_entryData->_action ==
|
||||
MacroActionFilter::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod ==
|
||||
MacroActionFilter::SettingsInputMethod::
|
||||
INDIVIDUAL_TEMPVAR);
|
||||
|
||||
if (_entryData->_action == MacroActionFilter::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod ==
|
||||
MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL) {
|
||||
RemoveStretchIfPresent(_settingsLayout);
|
||||
_manualSettingValue->show();
|
||||
} else {
|
||||
AddStretchIfNecessary(_settingsLayout);
|
||||
_manualSettingValue->hide();
|
||||
}
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "variable-text-edit.hpp"
|
||||
#include "source-selection.hpp"
|
||||
#include "filter-selection.hpp"
|
||||
#include "source-setting.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QSpinBox>
|
||||
@@ -31,10 +32,21 @@ public:
|
||||
SETTINGS,
|
||||
};
|
||||
|
||||
enum class SettingsInputMethod {
|
||||
INDIVIDUAL_MANUAL,
|
||||
INDIVIDUAL_TEMPVAR,
|
||||
JSON_STRING,
|
||||
};
|
||||
SettingsInputMethod _settingsInputMethod =
|
||||
SettingsInputMethod::INDIVIDUAL_MANUAL;
|
||||
|
||||
SourceSelection _source;
|
||||
FilterSelection _filter;
|
||||
Action _action = Action::ENABLE;
|
||||
StringVariable _settings = "";
|
||||
StringVariable _settingsString = "";
|
||||
TempVariableRef _tempVar;
|
||||
StringVariable _manualSettingValue = "";
|
||||
SourceSetting _setting;
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
@@ -62,7 +74,11 @@ private slots:
|
||||
void FilterChanged(const FilterSelection &);
|
||||
void ActionChanged(int value);
|
||||
void GetSettingsClicked();
|
||||
void SettingsChanged();
|
||||
void SettingsStringChanged();
|
||||
void SettingsInputMethodChanged(int);
|
||||
void SelectionChanged(const TempVariableRef &);
|
||||
void SelectionChanged(const SourceSetting &);
|
||||
void ManualSettingsValueChanged();
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
@@ -71,11 +87,17 @@ protected:
|
||||
FilterSelectionWidget *_filters;
|
||||
QComboBox *_actions;
|
||||
QPushButton *_getSettings;
|
||||
VariableTextEdit *_settings;
|
||||
QHBoxLayout *_settingsLayout;
|
||||
QComboBox *_settingsInputMethods;
|
||||
VariableTextEdit *_manualSettingValue;
|
||||
TempVariableSelection *_tempVars;
|
||||
SourceSettingSelection *_filterSettings;
|
||||
VariableTextEdit *_settingsString;
|
||||
|
||||
std::shared_ptr<MacroActionFilter> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility(bool);
|
||||
void SetWidgetVisibility();
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@ bool MacroActionHotkey::_registered = MacroActionFactory::Register(
|
||||
{MacroActionHotkey::Create, MacroActionHotkeyEdit::Create,
|
||||
"AdvSceneSwitcher.action.hotkey"});
|
||||
|
||||
const static std::map<MacroActionHotkey::Action, std::string> actionTypes = {
|
||||
static const std::map<MacroActionHotkey::Action, std::string> actionTypes = {
|
||||
{MacroActionHotkey::Action::OBS_HOTKEY,
|
||||
"AdvSceneSwitcher.action.hotkey.type.obs"},
|
||||
{MacroActionHotkey::Action::CUSTOM,
|
||||
"AdvSceneSwitcher.action.hotkey.type.custom"},
|
||||
};
|
||||
|
||||
const static std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
|
||||
static const std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
|
||||
{OBS_HOTKEY_REGISTERER_FRONTEND,
|
||||
"AdvSceneSwitcher.action.hotkey.type.obs.type.frontend"},
|
||||
{OBS_HOTKEY_REGISTERER_SOURCE,
|
||||
@@ -34,7 +34,7 @@ const static std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
|
||||
"AdvSceneSwitcher.action.hotkey.type.obs.type.service"},
|
||||
};
|
||||
|
||||
static std::unordered_map<HotkeyType, long> keyTable = {
|
||||
static const std::unordered_map<HotkeyType, long> keyTable = {
|
||||
// Chars
|
||||
{HotkeyType::Key_A, OBS_KEY_A},
|
||||
{HotkeyType::Key_B, OBS_KEY_B},
|
||||
@@ -75,6 +75,9 @@ static std::unordered_map<HotkeyType, long> keyTable = {
|
||||
{HotkeyType::Key_8, OBS_KEY_8},
|
||||
{HotkeyType::Key_9, OBS_KEY_9},
|
||||
|
||||
// Other
|
||||
{HotkeyType::Key_Tilde, OBS_KEY_ASCIITILDE},
|
||||
|
||||
{HotkeyType::Key_F1, OBS_KEY_F1},
|
||||
{HotkeyType::Key_F2, OBS_KEY_F2},
|
||||
{HotkeyType::Key_F3, OBS_KEY_F3},
|
||||
@@ -525,6 +528,7 @@ static inline void populateKeySelection(QComboBox *list)
|
||||
list->addItem("NumpadDivide");
|
||||
list->addItem("NumpadDecimal");
|
||||
list->addItem("NumpadEnter");
|
||||
list->addItem("Tilde");
|
||||
}
|
||||
|
||||
static void populateActionSelection(QComboBox *list)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "macro-action-http.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "curl-helper.hpp"
|
||||
|
||||
@@ -36,44 +35,44 @@ void MacroActionHttp::SetupHeaders()
|
||||
}
|
||||
struct curl_slist *headers = nullptr;
|
||||
for (auto &header : _headers) {
|
||||
headers = switcher->curl.SlistAppend(headers, header.c_str());
|
||||
headers = CurlHelper::SlistAppend(headers, header.c_str());
|
||||
}
|
||||
if (!_headers.empty()) {
|
||||
switcher->curl.SetOpt(CURLOPT_HTTPHEADER, headers);
|
||||
CurlHelper::SetOpt(CURLOPT_HTTPHEADER, headers);
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionHttp::Get()
|
||||
{
|
||||
switcher->curl.SetOpt(CURLOPT_URL, _url.c_str());
|
||||
switcher->curl.SetOpt(CURLOPT_HTTPGET, 1L);
|
||||
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
|
||||
CurlHelper::SetOpt(CURLOPT_URL, _url.c_str());
|
||||
CurlHelper::SetOpt(CURLOPT_HTTPGET, 1L);
|
||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
|
||||
SetupHeaders();
|
||||
|
||||
std::string response;
|
||||
if (IsReferencedInVars()) {
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, WriteCB);
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, WriteCB);
|
||||
} else {
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, DropCB);
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, DropCB);
|
||||
}
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &response);
|
||||
switcher->curl.Perform();
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &response);
|
||||
CurlHelper::Perform();
|
||||
|
||||
SetVariableValue(response);
|
||||
}
|
||||
|
||||
void MacroActionHttp::Post()
|
||||
{
|
||||
switcher->curl.SetOpt(CURLOPT_URL, _url.c_str());
|
||||
switcher->curl.SetOpt(CURLOPT_POSTFIELDS, _data.c_str());
|
||||
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
|
||||
CurlHelper::SetOpt(CURLOPT_URL, _url.c_str());
|
||||
CurlHelper::SetOpt(CURLOPT_POSTFIELDS, _data.c_str());
|
||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
|
||||
SetupHeaders();
|
||||
switcher->curl.Perform();
|
||||
CurlHelper::Perform();
|
||||
}
|
||||
|
||||
bool MacroActionHttp::PerformAction()
|
||||
{
|
||||
if (!switcher->curl.Initialized()) {
|
||||
if (!CurlHelper::Initialized()) {
|
||||
blog(LOG_WARNING,
|
||||
"cannot perform http action (curl not found)");
|
||||
return true;
|
||||
|
||||
@@ -10,22 +10,45 @@ bool MacroActionMedia::_registered = MacroActionFactory::Register(
|
||||
{MacroActionMedia::Create, MacroActionMediaEdit::Create,
|
||||
"AdvSceneSwitcher.action.media"});
|
||||
|
||||
const static std::map<MediaAction, std::string> actionTypes = {
|
||||
{MediaAction::PLAY, "AdvSceneSwitcher.action.media.type.play"},
|
||||
{MediaAction::PAUSE, "AdvSceneSwitcher.action.media.type.pause"},
|
||||
{MediaAction::STOP, "AdvSceneSwitcher.action.media.type.stop"},
|
||||
{MediaAction::RESTART, "AdvSceneSwitcher.action.media.type.restart"},
|
||||
{MediaAction::NEXT, "AdvSceneSwitcher.action.media.type.next"},
|
||||
{MediaAction::PREVIOUS, "AdvSceneSwitcher.action.media.type.previous"},
|
||||
{MediaAction::SEEK, "AdvSceneSwitcher.action.media.type.seek"},
|
||||
const static std::map<MacroActionMedia::Action, std::string> actionTypes = {
|
||||
{MacroActionMedia::Action::PLAY,
|
||||
"AdvSceneSwitcher.action.media.type.play"},
|
||||
{MacroActionMedia::Action::PAUSE,
|
||||
"AdvSceneSwitcher.action.media.type.pause"},
|
||||
{MacroActionMedia::Action::STOP,
|
||||
"AdvSceneSwitcher.action.media.type.stop"},
|
||||
{MacroActionMedia::Action::RESTART,
|
||||
"AdvSceneSwitcher.action.media.type.restart"},
|
||||
{MacroActionMedia::Action::NEXT,
|
||||
"AdvSceneSwitcher.action.media.type.next"},
|
||||
{MacroActionMedia::Action::PREVIOUS,
|
||||
"AdvSceneSwitcher.action.media.type.previous"},
|
||||
{MacroActionMedia::Action::SEEK_DURATION,
|
||||
"AdvSceneSwitcher.action.media.type.seek.duration"},
|
||||
{MacroActionMedia::Action::SEEK_PERCENTAGE,
|
||||
"AdvSceneSwitcher.action.media.type.seek.percentage"},
|
||||
};
|
||||
|
||||
std::string MacroActionMedia::GetShortDesc() const
|
||||
{
|
||||
return _mediaSource.ToString();
|
||||
}
|
||||
|
||||
void MacroActionMedia::SeekToPercentage(obs_source_t *source) const
|
||||
{
|
||||
auto totalTimeMs = obs_source_media_get_duration(source);
|
||||
auto percentageTimeMs = round(totalTimeMs * _seekPercentage / 100);
|
||||
|
||||
obs_source_media_set_time(source, percentageTimeMs);
|
||||
}
|
||||
|
||||
bool MacroActionMedia::PerformAction()
|
||||
{
|
||||
auto source = obs_weak_source_get_source(_mediaSource.GetSource());
|
||||
obs_media_state state = obs_source_media_get_state(source);
|
||||
|
||||
switch (_action) {
|
||||
case MediaAction::PLAY:
|
||||
case Action::PLAY:
|
||||
if (state == OBS_MEDIA_STATE_STOPPED ||
|
||||
state == OBS_MEDIA_STATE_ENDED) {
|
||||
obs_source_media_restart(source);
|
||||
@@ -33,27 +56,31 @@ bool MacroActionMedia::PerformAction()
|
||||
obs_source_media_play_pause(source, false);
|
||||
}
|
||||
break;
|
||||
case MediaAction::PAUSE:
|
||||
case Action::PAUSE:
|
||||
obs_source_media_play_pause(source, true);
|
||||
break;
|
||||
case MediaAction::STOP:
|
||||
case Action::STOP:
|
||||
obs_source_media_stop(source);
|
||||
break;
|
||||
case MediaAction::RESTART:
|
||||
case Action::RESTART:
|
||||
obs_source_media_restart(source);
|
||||
break;
|
||||
case MediaAction::NEXT:
|
||||
case Action::NEXT:
|
||||
obs_source_media_next(source);
|
||||
break;
|
||||
case MediaAction::PREVIOUS:
|
||||
case Action::PREVIOUS:
|
||||
obs_source_media_previous(source);
|
||||
break;
|
||||
case MediaAction::SEEK:
|
||||
obs_source_media_set_time(source, _seek.Milliseconds());
|
||||
case Action::SEEK_DURATION:
|
||||
obs_source_media_set_time(source, _seekDuration.Milliseconds());
|
||||
break;
|
||||
case Action::SEEK_PERCENTAGE:
|
||||
SeekToPercentage(source);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
obs_source_release(source);
|
||||
return true;
|
||||
}
|
||||
@@ -73,39 +100,42 @@ void MacroActionMedia::LogAction() const
|
||||
bool MacroActionMedia::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
_mediaSource.Save(obj, "mediaSource");
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
_seek.Save(obj);
|
||||
_seekDuration.Save(obj);
|
||||
_seekPercentage.Save(obj, "seekPercentage");
|
||||
_mediaSource.Save(obj, "mediaSource");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroActionMedia::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
_seekDuration.Load(obj);
|
||||
_seekPercentage.Load(obj, "seekPercentage");
|
||||
_mediaSource.Load(obj, "mediaSource");
|
||||
_action = static_cast<MediaAction>(obs_data_get_int(obj, "action"));
|
||||
_seek.Load(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string MacroActionMedia::GetShortDesc() const
|
||||
{
|
||||
return _mediaSource.ToString();
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void populateActionSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : actionTypes) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
for (const auto &[_, name] : actionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
MacroActionMediaEdit::MacroActionMediaEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionMedia> entryData)
|
||||
: QWidget(parent),
|
||||
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
||||
_actions(new QComboBox()),
|
||||
_seek(new DurationSelection())
|
||||
_seekDuration(new DurationSelection()),
|
||||
_seekPercentage(new SliderSpinBox(
|
||||
0, 100,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.media.seek.percentage.label"))),
|
||||
_sources(new SourceSelectionWidget(this, QStringList(), true))
|
||||
{
|
||||
populateActionSelection(_actions);
|
||||
auto sources = GetMediaSourceNames();
|
||||
@@ -114,39 +144,67 @@ MacroActionMediaEdit::MacroActionMediaEdit(
|
||||
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
QWidget::connect(_seekDuration,
|
||||
SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(SeekDurationChanged(const Duration &)));
|
||||
QWidget::connect(
|
||||
_seekPercentage,
|
||||
SIGNAL(DoubleValueChanged(const NumberVariable<double> &)),
|
||||
this,
|
||||
SLOT(SeekPercentageChanged(const NumberVariable<double> &)));
|
||||
QWidget::connect(_sources,
|
||||
SIGNAL(SourceChanged(const SourceSelection &)), this,
|
||||
SLOT(SourceChanged(const SourceSelection &)));
|
||||
QWidget::connect(_seek, SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(DurationChanged(const Duration &)));
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
auto layout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{mediaSources}}", _sources},
|
||||
{"{{actions}}", _actions},
|
||||
{"{{duration}}", _seek},
|
||||
{"{{seekDuration}}", _seekDuration},
|
||||
{"{{seekPercentage}}", _seekPercentage},
|
||||
{"{{mediaSources}}", _sources},
|
||||
};
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.media.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
layout, widgetPlaceholders);
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::UpdateEntryData()
|
||||
void MacroActionMediaEdit::ActionChanged(int value)
|
||||
{
|
||||
if (!_entryData) {
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_sources->SetSource(_entryData->_mediaSource);
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
_seek->SetDuration(_entryData->_seek);
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<MacroActionMedia::Action>(value);
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::SeekDurationChanged(const Duration &seekDuration)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_seekDuration = seekDuration;
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::SeekPercentageChanged(
|
||||
const NumberVariable<double> &seekPercentage)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_seekPercentage = seekPercentage;
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::SourceChanged(const SourceSelection &source)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
@@ -159,34 +217,32 @@ void MacroActionMediaEdit::SourceChanged(const SourceSelection &source)
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::ActionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_action = static_cast<MediaAction>(value);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::DurationChanged(const Duration &dur)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_seek = dur;
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::SetWidgetVisibility()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
_seek->setVisible(_entryData->_action == MediaAction::SEEK);
|
||||
|
||||
_seekDuration->setVisible(_entryData->_action ==
|
||||
MacroActionMedia::Action::SEEK_DURATION);
|
||||
_seekPercentage->setVisible(_entryData->_action ==
|
||||
MacroActionMedia::Action::SEEK_PERCENTAGE);
|
||||
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
void MacroActionMediaEdit::UpdateEntryData()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
_seekDuration->SetDuration(_entryData->_seekDuration);
|
||||
_seekPercentage->SetDoubleValue(_entryData->_seekPercentage);
|
||||
_sources->SetSource(_entryData->_mediaSource);
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,42 +1,45 @@
|
||||
#pragma once
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "duration-control.hpp"
|
||||
#include "slider-spinbox.hpp"
|
||||
#include "source-selection.hpp"
|
||||
|
||||
#include <QSpinBox>
|
||||
#include <QHBoxLayout>
|
||||
|
||||
namespace advss {
|
||||
|
||||
enum class MediaAction {
|
||||
PLAY,
|
||||
PAUSE,
|
||||
STOP,
|
||||
RESTART,
|
||||
NEXT,
|
||||
PREVIOUS,
|
||||
SEEK,
|
||||
};
|
||||
|
||||
class MacroActionMedia : public MacroAction {
|
||||
public:
|
||||
MacroActionMedia(Macro *m) : MacroAction(m) {}
|
||||
bool PerformAction();
|
||||
void LogAction() const;
|
||||
bool Save(obs_data_t *obj) const;
|
||||
bool Load(obs_data_t *obj);
|
||||
std::string GetShortDesc() const;
|
||||
std::string GetId() const { return id; };
|
||||
static std::shared_ptr<MacroAction> Create(Macro *m)
|
||||
{
|
||||
return std::make_shared<MacroActionMedia>(m);
|
||||
}
|
||||
std::string GetId() const { return id; };
|
||||
std::string GetShortDesc() const;
|
||||
|
||||
bool PerformAction();
|
||||
void LogAction() const;
|
||||
bool Save(obs_data_t *obj) const;
|
||||
bool Load(obs_data_t *obj);
|
||||
|
||||
enum class Action {
|
||||
PLAY,
|
||||
PAUSE,
|
||||
STOP,
|
||||
RESTART,
|
||||
NEXT,
|
||||
PREVIOUS,
|
||||
SEEK_DURATION,
|
||||
SEEK_PERCENTAGE,
|
||||
};
|
||||
|
||||
Action _action = Action::PLAY;
|
||||
Duration _seekDuration;
|
||||
DoubleVariable _seekPercentage = 50;
|
||||
SourceSelection _mediaSource;
|
||||
MediaAction _action = MediaAction::PLAY;
|
||||
Duration _seek;
|
||||
|
||||
private:
|
||||
void SeekToPercentage(obs_source_t *source) const;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
@@ -48,7 +51,6 @@ public:
|
||||
MacroActionMediaEdit(
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroActionMedia> entryData = nullptr);
|
||||
void UpdateEntryData();
|
||||
static QWidget *Create(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
@@ -56,24 +58,27 @@ public:
|
||||
parent,
|
||||
std::dynamic_pointer_cast<MacroActionMedia>(action));
|
||||
}
|
||||
void UpdateEntryData();
|
||||
|
||||
private slots:
|
||||
void SourceChanged(const SourceSelection &);
|
||||
void ActionChanged(int value);
|
||||
void DurationChanged(const Duration &value);
|
||||
void SeekDurationChanged(const Duration &seekDuration);
|
||||
void
|
||||
SeekPercentageChanged(const NumberVariable<double> &seekPercentage);
|
||||
void SourceChanged(const SourceSelection &source);
|
||||
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
SourceSelectionWidget *_sources;
|
||||
QComboBox *_actions;
|
||||
DurationSelection *_seek;
|
||||
std::shared_ptr<MacroActionMedia> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
QHBoxLayout *_mainLayout;
|
||||
QComboBox *_actions;
|
||||
DurationSelection *_seekDuration;
|
||||
SliderSpinBox *_seekPercentage;
|
||||
SourceSelectionWidget *_sources;
|
||||
|
||||
std::shared_ptr<MacroActionMedia> _entryData;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
#include "macro-action-plugin-state.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
#include <QMainWindow>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
@@ -27,40 +28,38 @@ const static std::map<PluginStateAction, std::string> actionTypes = {
|
||||
"AdvSceneSwitcher.action.pluginState.type.terminate"},
|
||||
};
|
||||
|
||||
const static std::map<SwitcherData::NoMatch, std::string> noMatchValues = {
|
||||
{SwitcherData::NoMatch::NO_SWITCH,
|
||||
const static std::map<NoMatchBehavior, std::string> noMatchValues = {
|
||||
{NoMatchBehavior::NO_SWITCH,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch"},
|
||||
{SwitcherData::NoMatch::SWITCH,
|
||||
{NoMatchBehavior::SWITCH,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo"},
|
||||
{SwitcherData::NoMatch::RANDOM_SWITCH,
|
||||
{NoMatchBehavior::RANDOM_SWITCH,
|
||||
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom"},
|
||||
};
|
||||
|
||||
static void stopPlugin()
|
||||
{
|
||||
std::thread t([]() { switcher->Stop(); });
|
||||
std::thread t([]() { StopPlugin(); });
|
||||
t.detach();
|
||||
}
|
||||
|
||||
static void importSettings(const std::string &path)
|
||||
{
|
||||
if (switcher->settingsWindowOpened) {
|
||||
if (SettingsWindowIsOpened()) {
|
||||
return;
|
||||
}
|
||||
obs_data_t *obj = obs_data_create_from_json_file(path.c_str());
|
||||
OBSDataAutoRelease obj = obs_data_create_from_json_file(path.c_str());
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
switcher->LoadSettings(obj);
|
||||
obs_data_release(obj);
|
||||
LoadPluginSettings(obj);
|
||||
}
|
||||
|
||||
static void setNoMatchBehaviour(int value, OBSWeakSource &scene)
|
||||
{
|
||||
switcher->switchIfNotMatching =
|
||||
static_cast<SwitcherData::NoMatch>(value);
|
||||
if (switcher->switchIfNotMatching == SwitcherData::NoMatch::SWITCH) {
|
||||
switcher->nonMatchingScene = scene;
|
||||
SetPluginNoMatchBehavior(static_cast<NoMatchBehavior>(value));
|
||||
if (GetPluginNoMatchBehavior() == NoMatchBehavior::SWITCH) {
|
||||
SetNoMatchScene(scene);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,8 +341,8 @@ void MacroActionPluginStateEdit::SetWidgetVisibility()
|
||||
break;
|
||||
case PluginStateAction::NO_MATCH_BEHAVIOUR:
|
||||
_values->show();
|
||||
if (static_cast<SwitcherData::NoMatch>(_entryData->_value) ==
|
||||
SwitcherData::NoMatch::SWITCH) {
|
||||
if (static_cast<NoMatchBehavior>(_entryData->_value) ==
|
||||
NoMatchBehavior::SWITCH) {
|
||||
_scenes->show();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -14,9 +14,14 @@ bool MacroActionRun::_registered = MacroActionFactory::Register(
|
||||
|
||||
bool MacroActionRun::PerformAction()
|
||||
{
|
||||
bool procStarted = QProcess::startDetached(
|
||||
QString::fromStdString(_procConfig.Path()), _procConfig.Args(),
|
||||
QString::fromStdString(_procConfig.WorkingDir()));
|
||||
if (_wait) {
|
||||
_procConfig.StartProcessAndWait(_timeout.Milliseconds());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool procStarted = _procConfig.StartProcessDetached();
|
||||
|
||||
// Fall back to using default application to open given file
|
||||
if (!procStarted && _procConfig.Args().empty()) {
|
||||
vblog(LOG_INFO, "run \"%s\" using QDesktopServices",
|
||||
_procConfig.Path().c_str());
|
||||
@@ -35,6 +40,9 @@ bool MacroActionRun::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroAction::Save(obj);
|
||||
_procConfig.Save(obj);
|
||||
_timeout.Save(obj);
|
||||
obs_data_set_bool(obj, "wait", _wait);
|
||||
obs_data_set_int(obj, "version", 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -42,6 +50,12 @@ bool MacroActionRun::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroAction::Load(obj);
|
||||
_procConfig.Load(obj);
|
||||
// TODO: Remove this fallback in a future version
|
||||
if (!obs_data_has_user_value(obj, "version")) {
|
||||
return true;
|
||||
}
|
||||
_timeout.Load(obj);
|
||||
_wait = obs_data_get_bool(obj, "wait");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -52,14 +66,30 @@ std::string MacroActionRun::GetShortDesc() const
|
||||
|
||||
MacroActionRunEdit::MacroActionRunEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionRun> entryData)
|
||||
: QWidget(parent), _procConfig(new ProcessConfigEdit(this))
|
||||
: QWidget(parent),
|
||||
_procConfig(new ProcessConfigEdit(this)),
|
||||
_waitLayout(new QHBoxLayout()),
|
||||
_wait(new QCheckBox()),
|
||||
_timeout(new DurationSelection(this, true, 0.1))
|
||||
{
|
||||
QWidget::connect(_procConfig,
|
||||
SIGNAL(ConfigChanged(const ProcessConfig &)), this,
|
||||
SLOT(ProcessConfigChanged(const ProcessConfig &)));
|
||||
QWidget::connect(_procConfig, SIGNAL(AdvancedSettingsEnabled()), this,
|
||||
SLOT(ProcessConfigAdvancedSettingsShown()));
|
||||
QWidget::connect(_wait, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(WaitChanged(int)));
|
||||
QWidget::connect(_timeout, SIGNAL(DurationChanged(const Duration &)),
|
||||
this, SLOT(TimeoutChanged(const Duration &)));
|
||||
|
||||
auto *layout = new QVBoxLayout;
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.run.entry.wait"),
|
||||
_waitLayout,
|
||||
{{"{{wait}}", _wait}, {"{{timeout}}", _timeout}});
|
||||
SetLayoutVisible(_waitLayout, false);
|
||||
|
||||
auto layout = new QVBoxLayout;
|
||||
layout->addWidget(_procConfig);
|
||||
layout->addLayout(_waitLayout);
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
@@ -73,6 +103,31 @@ void MacroActionRunEdit::UpdateEntryData()
|
||||
return;
|
||||
}
|
||||
_procConfig->SetProcessConfig(_entryData->_procConfig);
|
||||
_wait->setChecked(_entryData->_wait);
|
||||
_timeout->SetDuration(_entryData->_timeout);
|
||||
}
|
||||
|
||||
void MacroActionRunEdit::ProcessConfigAdvancedSettingsShown()
|
||||
{
|
||||
SetLayoutVisible(_waitLayout, true);
|
||||
}
|
||||
|
||||
void MacroActionRunEdit::WaitChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
auto lock = LockContext();
|
||||
_entryData->_wait = value;
|
||||
}
|
||||
|
||||
void MacroActionRunEdit::TimeoutChanged(const Duration &timeout)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
auto lock = LockContext();
|
||||
_entryData->_timeout = timeout;
|
||||
}
|
||||
|
||||
void MacroActionRunEdit::ProcessConfigChanged(const ProcessConfig &conf)
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#pragma once
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "process-config.hpp"
|
||||
#include "duration-control.hpp"
|
||||
|
||||
#include <QCheckBox>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -19,6 +22,8 @@ public:
|
||||
}
|
||||
|
||||
ProcessConfig _procConfig;
|
||||
bool _wait = false;
|
||||
Duration _timeout = 1;
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
@@ -42,14 +47,19 @@ public:
|
||||
|
||||
private slots:
|
||||
void ProcessConfigChanged(const ProcessConfig &);
|
||||
void ProcessConfigAdvancedSettingsShown();
|
||||
void WaitChanged(int);
|
||||
void TimeoutChanged(const Duration &);
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<MacroActionRun> _entryData;
|
||||
|
||||
private:
|
||||
ProcessConfigEdit *_procConfig;
|
||||
QHBoxLayout *_waitLayout;
|
||||
QCheckBox *_wait;
|
||||
DurationSelection *_timeout;
|
||||
|
||||
std::shared_ptr<MacroActionRun> _entryData;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "macro-action-scene-collection.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -17,7 +17,7 @@ bool MacroActionSceneCollection::PerformAction()
|
||||
// Changing the scene collection will also reload the settings of the
|
||||
// scene switcher, so to avoid issues of not being able to change
|
||||
// settings ignore this action if the settings dialog is opened.
|
||||
if (switcher->settingsWindowOpened) {
|
||||
if (SettingsWindowIsOpened()) {
|
||||
return false;
|
||||
}
|
||||
obs_frontend_set_current_scene_collection(_sceneCollection.c_str());
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "macro-action-scene-switch.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
@@ -7,7 +9,7 @@ namespace advss {
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
const std::string MacroActionSwitchScene::id = "scene_switch";
|
||||
const std::string MacroActionSwitchScene::id = GetSceneSwitchActionId().data();
|
||||
|
||||
bool MacroActionSwitchScene::_registered = MacroActionFactory::Register(
|
||||
MacroActionSwitchScene::id,
|
||||
@@ -33,9 +35,9 @@ static void waitForTransitionChange(OBSWeakSource &transition,
|
||||
}
|
||||
|
||||
bool stillTransitioning = true;
|
||||
while (stillTransitioning && !switcher->abortMacroWait &&
|
||||
while (stillTransitioning && !MacroWaitShouldAbort() &&
|
||||
!macro->GetStop()) {
|
||||
switcher->macroTransitionCv.wait_for(*lock, time);
|
||||
GetMacroTransitionCV().wait_for(*lock, time);
|
||||
float t = obs_transition_get_time(source);
|
||||
stillTransitioning = t < 1.0f && t > 0.0f;
|
||||
}
|
||||
@@ -49,8 +51,8 @@ static void waitForTransitionChangeFixedDuration(
|
||||
auto time = std::chrono::high_resolution_clock::now() +
|
||||
std::chrono::milliseconds(duration);
|
||||
|
||||
while (!switcher->abortMacroWait && !macro->GetStop()) {
|
||||
if (switcher->macroTransitionCv.wait_until(*lock, time) ==
|
||||
while (!MacroWaitShouldAbort() && !macro->GetStop()) {
|
||||
if (GetMacroTransitionCV().wait_until(*lock, time) ==
|
||||
std::cv_status::timeout) {
|
||||
break;
|
||||
}
|
||||
@@ -91,11 +93,16 @@ static OBSWeakSource getOverrideTransition(OBSWeakSource &scene)
|
||||
return transition;
|
||||
}
|
||||
|
||||
static int getExpectedTransitionDuration(OBSWeakSource &scene, OBSWeakSource &t,
|
||||
static int getExpectedTransitionDuration(OBSWeakSource &scene,
|
||||
OBSWeakSource &transiton_,
|
||||
double duration)
|
||||
{
|
||||
OBSWeakSource transition = t;
|
||||
if (!switcher->transitionOverrideOverride) {
|
||||
OBSWeakSource transition = transiton_;
|
||||
|
||||
// If we are not modifying the transition override, we will have to
|
||||
// check, if a transition override is set by the user and use its
|
||||
// duration instead
|
||||
if (!ShouldModifyTransitionOverrides()) {
|
||||
auto overrideTransition = getOverrideTransition(scene);
|
||||
if (overrideTransition) {
|
||||
transition = overrideTransition;
|
||||
@@ -104,6 +111,7 @@ static int getExpectedTransitionDuration(OBSWeakSource &scene, OBSWeakSource &t,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isUsingFixedLengthTransition(transition)) {
|
||||
return -1; // no API is available to access the fixed duration
|
||||
}
|
||||
@@ -118,9 +126,9 @@ bool MacroActionSwitchScene::WaitForTransition(OBSWeakSource &scene,
|
||||
{
|
||||
const int expectedTransitionDuration = getExpectedTransitionDuration(
|
||||
scene, transition, _duration.Seconds());
|
||||
switcher->abortMacroWait = false;
|
||||
SetMacroAbortWait(false);
|
||||
|
||||
std::unique_lock<std::mutex> lock(switcher->m);
|
||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
||||
if (expectedTransitionDuration < 0) {
|
||||
waitForTransitionChange(transition, &lock, GetMacro());
|
||||
} else {
|
||||
@@ -128,7 +136,7 @@ bool MacroActionSwitchScene::WaitForTransition(OBSWeakSource &scene,
|
||||
&lock, GetMacro());
|
||||
}
|
||||
|
||||
return !switcher->abortMacroWait;
|
||||
return !MacroWaitShouldAbort();
|
||||
}
|
||||
|
||||
bool MacroActionSwitchScene::PerformAction()
|
||||
@@ -145,7 +153,7 @@ bool MacroActionSwitchScene::PerformAction()
|
||||
auto transition = _transition.GetTransition();
|
||||
SwitchScene({scene, transition, (int)(_duration.Milliseconds())},
|
||||
obs_frontend_preview_program_mode_active());
|
||||
if (_blockUntilTransitionDone && scene) {
|
||||
if (_blockUntilTransitionDone && scene && scene != GetCurrentScene()) {
|
||||
return WaitForTransition(scene, transition);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -32,7 +32,7 @@ void MacroActionScreenshot::CustomScreenshot(OBSWeakSource &source)
|
||||
}
|
||||
auto s = obs_weak_source_get_source(source);
|
||||
_screenshot.~ScreenshotHelper();
|
||||
new (&_screenshot) ScreenshotHelper(s, false, 0, true, _path);
|
||||
new (&_screenshot) ScreenshotHelper(s, QRect(), false, 0, true, _path);
|
||||
obs_source_release(s);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,10 @@ const static std::map<MacroActionSource::Action, std::string> actionTypes = {
|
||||
"AdvSceneSwitcher.action.source.type.deinterlaceOrder"},
|
||||
{MacroActionSource::Action::OPEN_INTERACTION_DIALOG,
|
||||
"AdvSceneSwitcher.action.source.type.openInteractionDialog"},
|
||||
{MacroActionSource::Action::OPEN_FILTER_DIALOG,
|
||||
"AdvSceneSwitcher.action.source.type.openFilterDialog"},
|
||||
{MacroActionSource::Action::OPEN_PROPERTIES_DIALOG,
|
||||
"AdvSceneSwitcher.action.source.type.openPropertiesDialog"},
|
||||
};
|
||||
|
||||
const static std::map<obs_deinterlace_mode, std::string> deinterlaceModes = {
|
||||
@@ -60,6 +64,16 @@ const static std::map<obs_deinterlace_field_order, std::string>
|
||||
"AdvSceneSwitcher.action.source.deinterlaceOrder.bottomFieldFirst"},
|
||||
};
|
||||
|
||||
const static std::map<MacroActionSource::SettingsInputMethod, std::string>
|
||||
inputMethods = {
|
||||
{MacroActionSource::SettingsInputMethod::INDIVIDUAL_MANUAL,
|
||||
"AdvSceneSwitcher.action.source.inputMethod.individualManual"},
|
||||
{MacroActionSource::SettingsInputMethod::INDIVIDUAL_TEMPVAR,
|
||||
"AdvSceneSwitcher.action.source.inputMethod.individualTempvar"},
|
||||
{MacroActionSource::SettingsInputMethod::JSON_STRING,
|
||||
"AdvSceneSwitcher.action.source.inputMethod.json"},
|
||||
};
|
||||
|
||||
static std::vector<SourceSettingButton> getSourceButtons(OBSWeakSource source)
|
||||
{
|
||||
auto s = obs_weak_source_get_source(source);
|
||||
@@ -75,6 +89,7 @@ static std::vector<SourceSettingButton> getSourceButtons(OBSWeakSource source)
|
||||
buttons.emplace_back(button);
|
||||
} while (obs_property_next(&it));
|
||||
obs_source_release(s);
|
||||
obs_properties_destroy(sourceProperties);
|
||||
return buttons;
|
||||
}
|
||||
|
||||
@@ -129,7 +144,26 @@ bool MacroActionSource::PerformAction()
|
||||
obs_source_set_enabled(s, false);
|
||||
break;
|
||||
case Action::SETTINGS:
|
||||
SetSourceSettings(s, _settings);
|
||||
switch (_settingsInputMethod) {
|
||||
case SettingsInputMethod::INDIVIDUAL_MANUAL:
|
||||
SetSourceSetting(s, _setting, _manualSettingValue);
|
||||
break;
|
||||
case SettingsInputMethod::INDIVIDUAL_TEMPVAR: {
|
||||
auto var = _tempVar.GetTempVariable(GetMacro());
|
||||
if (!var) {
|
||||
break;
|
||||
}
|
||||
auto value = var->Value();
|
||||
if (!value) {
|
||||
break;
|
||||
}
|
||||
SetSourceSetting(s, _setting, *value);
|
||||
break;
|
||||
}
|
||||
case SettingsInputMethod::JSON_STRING:
|
||||
SetSourceSettings(s, _settingsString);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Action::REFRESH_SETTINGS:
|
||||
refreshSourceSettings(s);
|
||||
@@ -153,6 +187,12 @@ bool MacroActionSource::PerformAction()
|
||||
_source.ToString().c_str());
|
||||
}
|
||||
break;
|
||||
case Action::OPEN_FILTER_DIALOG:
|
||||
obs_frontend_open_source_filters(s);
|
||||
break;
|
||||
case Action::OPEN_PROPERTIES_DIALOG:
|
||||
obs_frontend_open_source_properties(s);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -178,7 +218,12 @@ bool MacroActionSource::Save(obs_data_t *obj) const
|
||||
_source.Save(obj);
|
||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||
_button.Save(obj);
|
||||
_settings.Save(obj, "settings");
|
||||
obs_data_set_int(obj, "inputMethod",
|
||||
static_cast<int>(_settingsInputMethod));
|
||||
_setting.Save(obj);
|
||||
_manualSettingValue.Save(obj, "manualSettingValue");
|
||||
_tempVar.Save(obj);
|
||||
_settingsString.Save(obj, "settings");
|
||||
obs_data_set_int(obj, "deinterlaceMode",
|
||||
static_cast<int>(_deinterlaceMode));
|
||||
obs_data_set_int(obj, "deinterlaceOrder",
|
||||
@@ -192,7 +237,17 @@ bool MacroActionSource::Load(obs_data_t *obj)
|
||||
_source.Load(obj);
|
||||
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
|
||||
_button.Load(obj);
|
||||
_settings.Load(obj, "settings");
|
||||
// TODO: Remove fallback in future version
|
||||
if (obs_data_has_user_value(obj, "inputMethod")) {
|
||||
_settingsInputMethod = static_cast<SettingsInputMethod>(
|
||||
obs_data_get_int(obj, "inputMethod"));
|
||||
} else {
|
||||
_settingsInputMethod = SettingsInputMethod::JSON_STRING;
|
||||
}
|
||||
_setting.Load(obj);
|
||||
_settingsString.Load(obj, "settings");
|
||||
_manualSettingValue.Load(obj, "manualSettingValue");
|
||||
_tempVar.Load(obj, GetMacro());
|
||||
_deinterlaceMode = static_cast<obs_deinterlace_mode>(
|
||||
obs_data_get_int(obj, "deinterlaceMode"));
|
||||
_deinterlaceOrder = static_cast<obs_deinterlace_field_order>(
|
||||
@@ -255,19 +310,34 @@ static inline void populateDeinterlaceFieldOrderSelection(QComboBox *list)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void populateSettingsInputMethods(QComboBox *list)
|
||||
{
|
||||
list->clear();
|
||||
for (const auto &[value, name] : inputMethods) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(value));
|
||||
}
|
||||
}
|
||||
|
||||
MacroActionSourceEdit::MacroActionSourceEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionSource> entryData)
|
||||
: QWidget(parent),
|
||||
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
||||
_actions(new QComboBox()),
|
||||
_settingsButtons(new QComboBox()),
|
||||
_settingsLayout(new QHBoxLayout()),
|
||||
_settingsInputMethods(new QComboBox(this)),
|
||||
_manualSettingValue(new VariableTextEdit(this, 5, 1, 1)),
|
||||
_tempVars(new TempVariableSelection(this)),
|
||||
_sourceSettings(new SourceSettingSelection(this)),
|
||||
_settingsString(new VariableTextEdit(this)),
|
||||
_getSettings(new QPushButton(obs_module_text(
|
||||
"AdvSceneSwitcher.action.source.getSettings"))),
|
||||
_settings(new VariableTextEdit(this)),
|
||||
_deinterlaceMode(new QComboBox()),
|
||||
_deinterlaceOrder(new QComboBox()),
|
||||
_warning(new QLabel(
|
||||
obs_module_text("AdvSceneSwitcher.action.source.warning")))
|
||||
|
||||
{
|
||||
populateActionSelection(_actions);
|
||||
auto sources = GetSourceNames();
|
||||
@@ -275,6 +345,7 @@ MacroActionSourceEdit::MacroActionSourceEdit(
|
||||
_sources->SetSourceNameList(sources);
|
||||
populateDeinterlaceModeSelection(_deinterlaceMode);
|
||||
populateDeinterlaceFieldOrderSelection(_deinterlaceOrder);
|
||||
populateSettingsInputMethods(_settingsInputMethods);
|
||||
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
@@ -285,20 +356,33 @@ MacroActionSourceEdit::MacroActionSourceEdit(
|
||||
SLOT(SourceChanged(const SourceSelection &)));
|
||||
QWidget::connect(_getSettings, SIGNAL(clicked()), this,
|
||||
SLOT(GetSettingsClicked()));
|
||||
QWidget::connect(_settings, SIGNAL(textChanged()), this,
|
||||
SLOT(SettingsChanged()));
|
||||
QWidget::connect(_settingsString, SIGNAL(textChanged()), this,
|
||||
SLOT(SettingsStringChanged()));
|
||||
QWidget::connect(_deinterlaceMode, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(DeinterlaceModeChanged(int)));
|
||||
QWidget::connect(_deinterlaceOrder, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(DeinterlaceOrderChanged(int)));
|
||||
QWidget::connect(_tempVars,
|
||||
SIGNAL(SelectionChanged(const TempVariableRef &)),
|
||||
this, SLOT(SelectionChanged(const TempVariableRef &)));
|
||||
QWidget::connect(_settingsInputMethods,
|
||||
SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(SettingsInputMethodChanged(int)));
|
||||
QWidget::connect(_manualSettingValue, SIGNAL(textChanged()), this,
|
||||
SLOT(ManualSettingsValueChanged()));
|
||||
QWidget::connect(_sourceSettings,
|
||||
SIGNAL(SelectionChanged(const SourceSetting &)), this,
|
||||
SLOT(SelectionChanged(const SourceSetting &)));
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
QHBoxLayout *entryLayout = new QHBoxLayout;
|
||||
QHBoxLayout *buttonLayout = new QHBoxLayout;
|
||||
auto entryLayout = new QHBoxLayout;
|
||||
entryLayout->setContentsMargins(0, 0, 0, 0);
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{sources}}", _sources},
|
||||
{"{{actions}}", _actions},
|
||||
{"{{settings}}", _settings},
|
||||
{"{{settings}}", _sourceSettings},
|
||||
{"{{settingsInputMethod}}", _settingsInputMethods},
|
||||
{"{{settingValue}}", _manualSettingValue},
|
||||
{"{{tempVar}}", _tempVars},
|
||||
{"{{getSettings}}", _getSettings},
|
||||
{"{{settingsButtons}}", _settingsButtons},
|
||||
{"{{deinterlaceMode}}", _deinterlaceMode},
|
||||
@@ -306,9 +390,17 @@ MacroActionSourceEdit::MacroActionSourceEdit(
|
||||
};
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.source.entry"),
|
||||
entryLayout, widgetPlaceholders);
|
||||
_settingsLayout->setContentsMargins(0, 0, 0, 0);
|
||||
PlaceWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.action.source.entry.settings"),
|
||||
_settingsLayout, widgetPlaceholders);
|
||||
auto mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(entryLayout);
|
||||
mainLayout->addLayout(_settingsLayout);
|
||||
mainLayout->addWidget(_warning);
|
||||
mainLayout->addWidget(_settings);
|
||||
mainLayout->addWidget(_settingsString);
|
||||
auto buttonLayout = new QHBoxLayout;
|
||||
buttonLayout->setContentsMargins(0, 0, 0, 0);
|
||||
buttonLayout->addWidget(_getSettings);
|
||||
buttonLayout->addStretch();
|
||||
mainLayout->addLayout(buttonLayout);
|
||||
@@ -329,13 +421,20 @@ void MacroActionSourceEdit::UpdateEntryData()
|
||||
_entryData->_source.GetSource());
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||
_sources->SetSource(_entryData->_source);
|
||||
_sourceSettings->SetSource(_entryData->_source.GetSource());
|
||||
_sourceSettings->SetSetting(_entryData->_setting);
|
||||
_settingsButtons->setCurrentText(
|
||||
QString::fromStdString(_entryData->_button.ToString()));
|
||||
_settings->setPlainText(_entryData->_settings);
|
||||
_settingsString->setPlainText(_entryData->_settingsString);
|
||||
_deinterlaceMode->setCurrentIndex(_deinterlaceMode->findData(
|
||||
static_cast<int>(_entryData->_deinterlaceMode)));
|
||||
_deinterlaceOrder->setCurrentIndex(_deinterlaceOrder->findData(
|
||||
static_cast<int>(_entryData->_deinterlaceOrder)));
|
||||
_settingsInputMethods->setCurrentIndex(_settingsInputMethods->findData(
|
||||
static_cast<int>(_entryData->_settingsInputMethod)));
|
||||
_tempVars->SetVariable(_entryData->_tempVar);
|
||||
_manualSettingValue->setPlainText(_entryData->_manualSettingValue);
|
||||
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -351,6 +450,7 @@ void MacroActionSourceEdit::SourceChanged(const SourceSelection &source)
|
||||
}
|
||||
populateSourceButtonSelection(_settingsButtons,
|
||||
_entryData->_source.GetSource());
|
||||
_sourceSettings->SetSource(_entryData->_source.GetSource());
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
@@ -383,18 +483,29 @@ void MacroActionSourceEdit::GetSettingsClicked()
|
||||
return;
|
||||
}
|
||||
|
||||
_settings->setPlainText(FormatJsonString(
|
||||
GetSourceSettings(_entryData->_source.GetSource())));
|
||||
switch (_entryData->_settingsInputMethod) {
|
||||
case MacroActionSource::SettingsInputMethod::INDIVIDUAL_MANUAL:
|
||||
_manualSettingValue->setPlainText(GetSourceSettingValue(
|
||||
_entryData->_source.GetSource(), _entryData->_setting));
|
||||
break;
|
||||
case MacroActionSource::SettingsInputMethod::INDIVIDUAL_TEMPVAR:
|
||||
break;
|
||||
case MacroActionSource::SettingsInputMethod::JSON_STRING:
|
||||
_settingsString->setPlainText(FormatJsonString(
|
||||
GetSourceSettings(_entryData->_source.GetSource())));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::SettingsChanged()
|
||||
void MacroActionSourceEdit::SettingsStringChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_settings = _settings->toPlainText().toStdString();
|
||||
_entryData->_settingsString =
|
||||
_settingsString->toPlainText().toStdString();
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -423,15 +534,87 @@ void MacroActionSourceEdit::DeinterlaceOrderChanged(int idx)
|
||||
_deinterlaceOrder->itemData(idx).toInt());
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::SelectionChanged(const TempVariableRef &var)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_tempVar = var;
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::SettingsInputMethodChanged(int idx)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_settingsInputMethod =
|
||||
static_cast<MacroActionSource::SettingsInputMethod>(
|
||||
_settingsInputMethods->itemData(idx).toInt());
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::SelectionChanged(const SourceSetting &setting)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_setting = setting;
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::ManualSettingsValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_manualSettingValue =
|
||||
_manualSettingValue->toPlainText().toStdString();
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionSourceEdit::SetWidgetVisibility()
|
||||
{
|
||||
const bool showSettings = _entryData->_action ==
|
||||
MacroActionSource::Action::SETTINGS;
|
||||
SetLayoutVisible(_settingsLayout,
|
||||
_entryData->_action ==
|
||||
MacroActionSource::Action::SETTINGS);
|
||||
_sourceSettings->setVisible(
|
||||
_entryData->_action == MacroActionSource::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod !=
|
||||
MacroActionSource::SettingsInputMethod::JSON_STRING);
|
||||
_settingsString->setVisible(
|
||||
_entryData->_action == MacroActionSource::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod ==
|
||||
MacroActionSource::SettingsInputMethod::JSON_STRING);
|
||||
_getSettings->setVisible(_entryData->_action ==
|
||||
MacroActionSource::Action::SETTINGS);
|
||||
_tempVars->setVisible(_entryData->_action ==
|
||||
MacroActionSource::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod ==
|
||||
MacroActionSource::SettingsInputMethod::
|
||||
INDIVIDUAL_TEMPVAR);
|
||||
|
||||
if (_entryData->_action == MacroActionSource::Action::SETTINGS &&
|
||||
_entryData->_settingsInputMethod ==
|
||||
MacroActionSource::SettingsInputMethod::INDIVIDUAL_MANUAL) {
|
||||
RemoveStretchIfPresent(_settingsLayout);
|
||||
_manualSettingValue->show();
|
||||
} else {
|
||||
AddStretchIfNecessary(_settingsLayout);
|
||||
_manualSettingValue->hide();
|
||||
}
|
||||
|
||||
const bool showWarning =
|
||||
_entryData->_action == MacroActionSource::Action::ENABLE ||
|
||||
_entryData->_action == MacroActionSource::Action::DISABLE;
|
||||
_settings->setVisible(showSettings);
|
||||
_getSettings->setVisible(showSettings);
|
||||
_warning->setVisible(showWarning);
|
||||
_settingsButtons->setVisible(
|
||||
_entryData->_action ==
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "macro-action-edit.hpp"
|
||||
#include "variable-text-edit.hpp"
|
||||
#include "source-selection.hpp"
|
||||
#include "source-setting.hpp"
|
||||
|
||||
#include <QSpinBox>
|
||||
#include <QLabel>
|
||||
@@ -35,10 +36,13 @@ public:
|
||||
|
||||
SourceSelection _source;
|
||||
SourceSettingButton _button;
|
||||
StringVariable _settings = "";
|
||||
StringVariable _settingsString = "";
|
||||
StringVariable _manualSettingValue = "";
|
||||
obs_deinterlace_mode _deinterlaceMode = OBS_DEINTERLACE_MODE_DISABLE;
|
||||
obs_deinterlace_field_order _deinterlaceOrder =
|
||||
OBS_DEINTERLACE_FIELD_ORDER_TOP;
|
||||
TempVariableRef _tempVar;
|
||||
SourceSetting _setting;
|
||||
|
||||
enum class Action {
|
||||
ENABLE,
|
||||
@@ -49,8 +53,18 @@ public:
|
||||
DEINTERLACE_MODE,
|
||||
DEINTERLACE_FIELD_ORDER,
|
||||
OPEN_INTERACTION_DIALOG,
|
||||
OPEN_FILTER_DIALOG,
|
||||
OPEN_PROPERTIES_DIALOG,
|
||||
};
|
||||
Action _action = Action::ENABLE;
|
||||
Action _action = Action::SETTINGS;
|
||||
|
||||
enum class SettingsInputMethod {
|
||||
INDIVIDUAL_MANUAL,
|
||||
INDIVIDUAL_TEMPVAR,
|
||||
JSON_STRING,
|
||||
};
|
||||
SettingsInputMethod _settingsInputMethod =
|
||||
SettingsInputMethod::INDIVIDUAL_MANUAL;
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
@@ -78,9 +92,13 @@ private slots:
|
||||
void ActionChanged(int value);
|
||||
void ButtonChanged(int idx);
|
||||
void GetSettingsClicked();
|
||||
void SettingsChanged();
|
||||
void SettingsStringChanged();
|
||||
void DeinterlaceModeChanged(int);
|
||||
void DeinterlaceOrderChanged(int);
|
||||
void SelectionChanged(const TempVariableRef &);
|
||||
void SettingsInputMethodChanged(int);
|
||||
void SelectionChanged(const SourceSetting &);
|
||||
void ManualSettingsValueChanged();
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
@@ -88,11 +106,17 @@ protected:
|
||||
SourceSelectionWidget *_sources;
|
||||
QComboBox *_actions;
|
||||
QComboBox *_settingsButtons;
|
||||
QHBoxLayout *_settingsLayout;
|
||||
QComboBox *_settingsInputMethods;
|
||||
VariableTextEdit *_manualSettingValue;
|
||||
TempVariableSelection *_tempVars;
|
||||
SourceSettingSelection *_sourceSettings;
|
||||
VariableTextEdit *_settingsString;
|
||||
QPushButton *_getSettings;
|
||||
VariableTextEdit *_settings;
|
||||
QComboBox *_deinterlaceMode;
|
||||
QComboBox *_deinterlaceOrder;
|
||||
QLabel *_warning;
|
||||
|
||||
std::shared_ptr<MacroActionSource> _entryData;
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "macro-action-variable.hpp"
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
@@ -45,6 +44,14 @@ const static std::map<MacroActionVariable::Type, std::string> actionTypes = {
|
||||
"AdvSceneSwitcher.action.variable.type.environmentVariable"},
|
||||
{MacroActionVariable::Type::SCENE_ITEM_COUNT,
|
||||
"AdvSceneSwitcher.action.variable.type.sceneItemCount"},
|
||||
{MacroActionVariable::Type::STRING_LENGTH,
|
||||
"AdvSceneSwitcher.action.variable.type.stringLength"},
|
||||
{MacroActionVariable::Type::EXTRACT_JSON,
|
||||
"AdvSceneSwitcher.action.variable.type.extractJson"},
|
||||
{MacroActionVariable::Type::SET_TO_TEMPVAR,
|
||||
"AdvSceneSwitcher.action.variable.type.setToTempvar"},
|
||||
{MacroActionVariable::Type::SCENE_ITEM_NAME,
|
||||
"AdvSceneSwitcher.action.variable.type.sceneItemName"},
|
||||
};
|
||||
|
||||
static void apppend(Variable &var, const std::string &value)
|
||||
@@ -128,6 +135,49 @@ void MacroActionVariable::HandleMathExpression(Variable *var)
|
||||
var->SetValue(std::get<double>(result));
|
||||
}
|
||||
|
||||
struct GetSceneItemNameHelper {
|
||||
int curIdx = 0;
|
||||
int targetIdx = 0;
|
||||
std::string name = "";
|
||||
};
|
||||
|
||||
static bool getSceneItemAtIdx(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
|
||||
{
|
||||
auto data = reinterpret_cast<GetSceneItemNameHelper *>(ptr);
|
||||
if (obs_sceneitem_is_group(item)) {
|
||||
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
|
||||
obs_scene_enum_items(scene, getSceneItemAtIdx, ptr);
|
||||
}
|
||||
if (data->curIdx == data->targetIdx) {
|
||||
data->name =
|
||||
obs_source_get_name(obs_sceneitem_get_source(item));
|
||||
data->curIdx--;
|
||||
return false;
|
||||
}
|
||||
data->curIdx--;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroActionVariable::SetToSceneItemName(Variable *var)
|
||||
{
|
||||
auto weakSource = _scene.GetScene();
|
||||
if (!weakSource) {
|
||||
var->SetValue("");
|
||||
return;
|
||||
}
|
||||
auto index = _sceneItemIndex.GetValue();
|
||||
if (index < 1) {
|
||||
var->SetValue("");
|
||||
return;
|
||||
}
|
||||
auto sceneItemCount = GetSceneItemCount(weakSource);
|
||||
OBSSourceAutoRelease source = obs_weak_source_get_source(weakSource);
|
||||
auto scene = obs_scene_from_source(source);
|
||||
GetSceneItemNameHelper data{sceneItemCount, index};
|
||||
obs_scene_enum_items(scene, getSceneItemAtIdx, &data);
|
||||
var->SetValue(data.name);
|
||||
}
|
||||
|
||||
struct AskForInputParams {
|
||||
QString prompt;
|
||||
QString placeholder;
|
||||
@@ -238,6 +288,33 @@ bool MacroActionVariable::PerformAction()
|
||||
var->SetValue(GetSceneItemCount(_scene.GetScene(false)));
|
||||
return true;
|
||||
}
|
||||
case Type::STRING_LENGTH: {
|
||||
var->SetValue(std::string(_strValue).length());
|
||||
return true;
|
||||
}
|
||||
case Type::EXTRACT_JSON: {
|
||||
auto value = GetJsonField(var->Value(), _strValue);
|
||||
if (!value.has_value()) {
|
||||
return true;
|
||||
}
|
||||
var->SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
case Type::SET_TO_TEMPVAR: {
|
||||
auto tempVar = _tempVar.GetTempVariable(GetMacro());
|
||||
if (!tempVar) {
|
||||
return true;
|
||||
}
|
||||
auto value = tempVar->Value();
|
||||
if (!value) {
|
||||
return true;
|
||||
}
|
||||
var->SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
case Type::SCENE_ITEM_NAME:
|
||||
SetToSceneItemName(var.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -250,7 +327,7 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
GetWeakVariableName(_variable).c_str());
|
||||
obs_data_set_string(obj, "variable2Name",
|
||||
GetWeakVariableName(_variable2).c_str());
|
||||
obs_data_set_string(obj, "strValue", _strValue.c_str());
|
||||
_strValue.Save(obj, "strValue");
|
||||
obs_data_set_double(obj, "numValue", _numValue);
|
||||
obs_data_set_int(obj, "condition", static_cast<int>(_type));
|
||||
obs_data_set_int(obj, "segmentIdx", GetSegmentIndexValue());
|
||||
@@ -258,8 +335,8 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
obs_data_set_int(obj, "subStringSize", _subStringSize);
|
||||
obs_data_set_string(obj, "regexPattern", _regexPattern.c_str());
|
||||
obs_data_set_int(obj, "regexMatchIdx", _regexMatchIdx);
|
||||
obs_data_set_string(obj, "findStr", _findStr.c_str());
|
||||
obs_data_set_string(obj, "replaceStr", _replaceStr.c_str());
|
||||
_findStr.Save(obj, "findStr");
|
||||
_replaceStr.Save(obj, "replaceStr");
|
||||
_regex.Save(obj);
|
||||
_mathExpression.Save(obj, "mathExpression");
|
||||
obs_data_set_bool(obj, "useCustomPrompt", _useCustomPrompt);
|
||||
@@ -268,6 +345,8 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
||||
_inputPlaceholder.Save(obj, "inputPlaceholder");
|
||||
_envVariableName.Save(obj, "environmentVariableName");
|
||||
_scene.Save(obj);
|
||||
_tempVar.Save(obj);
|
||||
_sceneItemIndex.Save(obj, "sceneItemIndex");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -278,7 +357,7 @@ bool MacroActionVariable::Load(obs_data_t *obj)
|
||||
GetWeakVariableByName(obs_data_get_string(obj, "variableName"));
|
||||
_variable2 = GetWeakVariableByName(
|
||||
obs_data_get_string(obj, "variable2Name"));
|
||||
_strValue = obs_data_get_string(obj, "strValue");
|
||||
_strValue.Load(obj, "strValue");
|
||||
_numValue = obs_data_get_double(obj, "numValue");
|
||||
_type = static_cast<Type>(obs_data_get_int(obj, "condition"));
|
||||
_segmentIdxLoadValue = obs_data_get_int(obj, "segmentIdx");
|
||||
@@ -287,8 +366,8 @@ bool MacroActionVariable::Load(obs_data_t *obj)
|
||||
_regex.Load(obj);
|
||||
_regexPattern = obs_data_get_string(obj, "regexPattern");
|
||||
_regexMatchIdx = obs_data_get_int(obj, "regexMatchIdx");
|
||||
_findStr = obs_data_get_string(obj, "findStr");
|
||||
_replaceStr = obs_data_get_string(obj, "replaceStr");
|
||||
_findStr.Load(obj, "findStr");
|
||||
_replaceStr.Load(obj, "replaceStr");
|
||||
_mathExpression.Load(obj, "mathExpression");
|
||||
_useCustomPrompt = obs_data_get_bool(obj, "useCustomPrompt");
|
||||
_inputPrompt.Load(obj, "inputPrompt");
|
||||
@@ -296,6 +375,8 @@ bool MacroActionVariable::Load(obs_data_t *obj)
|
||||
_inputPlaceholder.Load(obj, "inputPlaceholder");
|
||||
_envVariableName.Load(obj, "environmentVariableName");
|
||||
_scene.Load(obj);
|
||||
_tempVar.Load(obj, GetMacro());
|
||||
_sceneItemIndex.Load(obj, "sceneItemIndex");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -338,7 +419,7 @@ void MacroActionVariable::SetSegmentIndexValue(int value)
|
||||
|
||||
_macroSegment = segment;
|
||||
if (segment) {
|
||||
segment->IncrementVariableRef();
|
||||
IncrementVariableRef(segment.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,13 +461,14 @@ void MacroActionVariable::DecrementCurrentSegmentVariableRef()
|
||||
return;
|
||||
}
|
||||
|
||||
segment->DecrementVariableRef();
|
||||
DecrementVariableRef(segment.get());
|
||||
}
|
||||
|
||||
static inline void populateTypeSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : actionTypes) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
for (const auto &[action, name] : actionTypes) {
|
||||
list->addItem(obs_module_text(name.c_str()),
|
||||
static_cast<int>(action));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,8 +477,8 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
: QWidget(parent),
|
||||
_variables(new VariableSelection(this)),
|
||||
_variables2(new VariableSelection(this)),
|
||||
_actions(new QComboBox()),
|
||||
_strValue(new ResizingPlainTextEdit(this, 5, 1, 1)),
|
||||
_actions(new FilterComboBox(this)),
|
||||
_strValue(new VariableTextEdit(this, 5, 1, 1)),
|
||||
_numValue(new QDoubleSpinBox()),
|
||||
_segmentIdx(new MacroSegmentSelection(
|
||||
this, MacroSegmentSelection::Type::CONDITION, false)),
|
||||
@@ -411,8 +493,8 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_regexPattern(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
||||
_regexMatchIdx(new QSpinBox()),
|
||||
_findReplaceLayout(new QHBoxLayout()),
|
||||
_findStr(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
||||
_replaceStr(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
||||
_findStr(new VariableTextEdit(this, 10, 1, 1)),
|
||||
_replaceStr(new VariableTextEdit(this, 10, 1, 1)),
|
||||
_mathExpression(new VariableLineEdit(this)),
|
||||
_mathExpressionResult(new QLabel()),
|
||||
_promptLayout(new QHBoxLayout()),
|
||||
@@ -422,7 +504,10 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_useInputPlaceholder(new QCheckBox()),
|
||||
_inputPlaceholder(new VariableLineEdit(this)),
|
||||
_envVariable(new VariableLineEdit(this)),
|
||||
_scenes(new SceneSelectionWidget(this, true, false, true, true, true))
|
||||
_scenes(new SceneSelectionWidget(this, true, false, true, true,
|
||||
true)),
|
||||
_tempVars(new TempVariableSelection(this)),
|
||||
_sceneItemIndex(new VariableSpinBox())
|
||||
{
|
||||
_numValue->setMinimum(-9999999999);
|
||||
_numValue->setMaximum(9999999999);
|
||||
@@ -440,6 +525,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
_regexMatchIdx->setSuffix(".");
|
||||
_inputPrompt->setSizePolicy(QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::Preferred);
|
||||
_sceneItemIndex->setMinimum(1);
|
||||
populateTypeSelection(_actions);
|
||||
|
||||
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
||||
@@ -485,6 +571,13 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
SLOT(EnvVariableChanged()));
|
||||
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
|
||||
this, SLOT(SceneChanged(const SceneSelection &)));
|
||||
QWidget::connect(_tempVars,
|
||||
SIGNAL(SelectionChanged(const TempVariableRef &)),
|
||||
this, SLOT(SelectionChanged(const TempVariableRef &)));
|
||||
QWidget::connect(
|
||||
_sceneItemIndex,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(SceneItemIndexChanged(const NumberVariable<int> &)));
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{variables}}", _variables},
|
||||
@@ -505,6 +598,8 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
||||
{"{{inputPlaceholder}}", _inputPlaceholder},
|
||||
{"{{envVariableName}}", _envVariable},
|
||||
{"{{scenes}}", _scenes},
|
||||
{"{{tempVars}}", _tempVars},
|
||||
{"{{sceneItemIndex}}", _sceneItemIndex},
|
||||
};
|
||||
auto entryLayout = new QHBoxLayout;
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.variable.entry"),
|
||||
@@ -572,8 +667,9 @@ void MacroActionVariableEdit::UpdateEntryData()
|
||||
|
||||
_variables->SetVariable(_entryData->_variable);
|
||||
_variables2->SetVariable(_entryData->_variable2);
|
||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_type));
|
||||
_strValue->setPlainText(QString::fromStdString(_entryData->_strValue));
|
||||
_actions->setCurrentIndex(
|
||||
_actions->findData(static_cast<int>(_entryData->_type)));
|
||||
_strValue->setPlainText(_entryData->_strValue);
|
||||
_numValue->setValue(_entryData->_numValue);
|
||||
_segmentIdx->SetValue(_entryData->GetSegmentIndexValue() + 1);
|
||||
_segmentIdx->SetMacro(_entryData->GetMacro());
|
||||
@@ -588,9 +684,8 @@ void MacroActionVariableEdit::UpdateEntryData()
|
||||
_regexPattern->setPlainText(
|
||||
QString::fromStdString(_entryData->_regexPattern));
|
||||
_regexMatchIdx->setValue(_entryData->_regexMatchIdx + 1);
|
||||
_findStr->setPlainText(QString::fromStdString(_entryData->_findStr));
|
||||
_replaceStr->setPlainText(
|
||||
QString::fromStdString(_entryData->_replaceStr));
|
||||
_findStr->setPlainText(_entryData->_findStr);
|
||||
_replaceStr->setPlainText(_entryData->_replaceStr);
|
||||
_mathExpression->setText(_entryData->_mathExpression);
|
||||
_useCustomPrompt->setChecked(_entryData->_useCustomPrompt);
|
||||
_inputPrompt->setText(_entryData->_inputPrompt);
|
||||
@@ -598,6 +693,8 @@ void MacroActionVariableEdit::UpdateEntryData()
|
||||
_inputPlaceholder->setText(_entryData->_inputPlaceholder);
|
||||
_envVariable->setText(_entryData->_envVariableName);
|
||||
_scenes->SetScene(_entryData->_scene);
|
||||
_tempVars->SetVariable(_entryData->_tempVar);
|
||||
_sceneItemIndex->SetValue(_entryData->_sceneItemIndex);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -621,14 +718,15 @@ void MacroActionVariableEdit::Variable2Changed(const QString &text)
|
||||
_entryData->_variable2 = GetWeakVariableByQString(text);
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::ActionChanged(int value)
|
||||
void MacroActionVariableEdit::ActionChanged(int idx)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
if (_loading || !_entryData || idx == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_type = static_cast<MacroActionVariable::Type>(value);
|
||||
_entryData->_type = static_cast<MacroActionVariable::Type>(
|
||||
_actions->itemData(idx).toInt());
|
||||
|
||||
if (_entryData->_type == MacroActionVariable::Type::SET_ACTION_VALUE) {
|
||||
_segmentIdx->SetType(MacroSegmentSelection::Type::ACTION);
|
||||
@@ -725,7 +823,7 @@ void MacroActionVariableEdit::UpdateSegmentVariableValue()
|
||||
return;
|
||||
}
|
||||
|
||||
if (!segment->SupportsVariableValue()) {
|
||||
if (!SupportsVariableValue(segment.get())) {
|
||||
std::string type;
|
||||
QString fmt;
|
||||
|
||||
@@ -750,8 +848,14 @@ void MacroActionVariableEdit::UpdateSegmentVariableValue()
|
||||
_segmentValueStatus->setText(obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.currentSegmentValue"));
|
||||
_segmentValue->show();
|
||||
_segmentValue->setPlainText(
|
||||
QString::fromStdString(segment->GetVariableValue()));
|
||||
|
||||
// Only update the text if the value changed to prevent possible text
|
||||
// selections being lost
|
||||
auto previousText = _segmentValue->toPlainText();
|
||||
auto newText = QString::fromStdString(segment->GetVariableValue());
|
||||
if (newText != previousText) {
|
||||
_segmentValue->setPlainText(newText);
|
||||
}
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
@@ -925,6 +1029,27 @@ void MacroActionVariableEdit::SceneChanged(const SceneSelection &scene)
|
||||
_entryData->_scene = scene;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SelectionChanged(const TempVariableRef &var)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_tempVar = var;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SceneItemIndexChanged(
|
||||
const NumberVariable<int> &value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_sceneItemIndex = value;
|
||||
}
|
||||
|
||||
void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
{
|
||||
if (!_entryData) {
|
||||
@@ -936,7 +1061,9 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
_strValue->setVisible(
|
||||
_entryData->_type ==
|
||||
MacroActionVariable::Type::SET_FIXED_VALUE ||
|
||||
_entryData->_type == MacroActionVariable::Type::APPEND);
|
||||
_entryData->_type == MacroActionVariable::Type::APPEND ||
|
||||
_entryData->_type == MacroActionVariable::Type::STRING_LENGTH ||
|
||||
_entryData->_type == MacroActionVariable::Type::EXTRACT_JSON);
|
||||
_numValue->setVisible(
|
||||
_entryData->_type == MacroActionVariable::Type::INCREMENT ||
|
||||
_entryData->_type == MacroActionVariable::Type::DECREMENT);
|
||||
@@ -999,8 +1126,15 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
||||
}
|
||||
_envVariable->setVisible(_entryData->_type ==
|
||||
MacroActionVariable::Type::ENV_VARIABLE);
|
||||
_scenes->setVisible(_entryData->_type ==
|
||||
MacroActionVariable::Type::SCENE_ITEM_COUNT);
|
||||
_scenes->setVisible(
|
||||
_entryData->_type ==
|
||||
MacroActionVariable::Type::SCENE_ITEM_COUNT ||
|
||||
_entryData->_type ==
|
||||
MacroActionVariable::Type::SCENE_ITEM_NAME);
|
||||
_tempVars->setVisible(_entryData->_type ==
|
||||
MacroActionVariable::Type::SET_TO_TEMPVAR);
|
||||
_sceneItemIndex->setVisible(_entryData->_type ==
|
||||
MacroActionVariable::Type::SCENE_ITEM_NAME);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "resizing-text-edit.hpp"
|
||||
#include "scene-selection.hpp"
|
||||
#include "variable-line-edit.hpp"
|
||||
#include "variable-text-edit.hpp"
|
||||
#include "variable-spinbox.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -40,21 +42,25 @@ public:
|
||||
USER_INPUT,
|
||||
ENV_VARIABLE,
|
||||
SCENE_ITEM_COUNT,
|
||||
STRING_LENGTH,
|
||||
EXTRACT_JSON,
|
||||
SET_TO_TEMPVAR,
|
||||
SCENE_ITEM_NAME,
|
||||
};
|
||||
|
||||
Type _type = Type::SET_FIXED_VALUE;
|
||||
std::weak_ptr<Variable> _variable;
|
||||
std::weak_ptr<Variable> _variable2;
|
||||
std::string _strValue = "";
|
||||
StringVariable _strValue = "";
|
||||
double _numValue = 0;
|
||||
int _subStringStart = 0;
|
||||
int _subStringSize = 0;
|
||||
RegexConfig _regex = RegexConfig::PartialMatchRegexConfig();
|
||||
std::string _regexPattern = ".*";
|
||||
int _regexMatchIdx = 0;
|
||||
std::string _findStr = obs_module_text(
|
||||
StringVariable _findStr = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.findAndReplace.find");
|
||||
std::string _replaceStr = obs_module_text(
|
||||
StringVariable _replaceStr = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.findAndReplace.replace");
|
||||
StringVariable _mathExpression = obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.mathExpression.example");
|
||||
@@ -70,6 +76,8 @@ public:
|
||||
StringVariable _envVariableName = "HOME";
|
||||
#endif
|
||||
SceneSelection _scene;
|
||||
TempVariableRef _tempVar;
|
||||
IntVariable _sceneItemIndex = 1;
|
||||
|
||||
private:
|
||||
void DecrementCurrentSegmentVariableRef();
|
||||
@@ -77,6 +85,7 @@ private:
|
||||
void HandleRegexSubString(Variable *);
|
||||
void HandleFindAndReplace(Variable *);
|
||||
void HandleMathExpression(Variable *);
|
||||
void SetToSceneItemName(Variable *);
|
||||
|
||||
std::weak_ptr<MacroSegment> _macroSegment;
|
||||
int _segmentIdxLoadValue = -1;
|
||||
@@ -123,6 +132,8 @@ private slots:
|
||||
void InputPlaceholderChanged();
|
||||
void EnvVariableChanged();
|
||||
void SceneChanged(const SceneSelection &);
|
||||
void SelectionChanged(const TempVariableRef &var);
|
||||
void SceneItemIndexChanged(const NumberVariable<int> &);
|
||||
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
@@ -133,8 +144,8 @@ private:
|
||||
|
||||
VariableSelection *_variables;
|
||||
VariableSelection *_variables2;
|
||||
QComboBox *_actions;
|
||||
ResizingPlainTextEdit *_strValue;
|
||||
FilterComboBox *_actions;
|
||||
VariableTextEdit *_strValue;
|
||||
QDoubleSpinBox *_numValue;
|
||||
MacroSegmentSelection *_segmentIdx;
|
||||
QLabel *_segmentValueStatus;
|
||||
@@ -148,8 +159,8 @@ private:
|
||||
ResizingPlainTextEdit *_regexPattern;
|
||||
QSpinBox *_regexMatchIdx;
|
||||
QHBoxLayout *_findReplaceLayout;
|
||||
ResizingPlainTextEdit *_findStr;
|
||||
ResizingPlainTextEdit *_replaceStr;
|
||||
VariableTextEdit *_findStr;
|
||||
VariableTextEdit *_replaceStr;
|
||||
VariableLineEdit *_mathExpression;
|
||||
QLabel *_mathExpressionResult;
|
||||
QHBoxLayout *_promptLayout;
|
||||
@@ -160,6 +171,8 @@ private:
|
||||
VariableLineEdit *_inputPlaceholder;
|
||||
VariableLineEdit *_envVariable;
|
||||
SceneSelectionWidget *_scenes;
|
||||
TempVariableSelection *_tempVars;
|
||||
VariableSpinBox *_sceneItemIndex;
|
||||
|
||||
std::shared_ptr<MacroActionVariable> _entryData;
|
||||
QTimer _timer;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "macro-action-wait.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "sync-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <random>
|
||||
@@ -24,8 +26,8 @@ static std::default_random_engine re(rd());
|
||||
static void waitHelper(std::unique_lock<std::mutex> *lock, Macro *macro,
|
||||
std::chrono::high_resolution_clock::time_point &time)
|
||||
{
|
||||
while (!switcher->abortMacroWait && !macro->GetStop()) {
|
||||
if (switcher->macroWaitCv.wait_until(*lock, time) ==
|
||||
while (!MacroWaitShouldAbort() && !macro->GetStop()) {
|
||||
if (GetMacroWaitCV().wait_until(*lock, time) ==
|
||||
std::cv_status::timeout) {
|
||||
break;
|
||||
}
|
||||
@@ -53,11 +55,11 @@ bool MacroActionWait::PerformAction()
|
||||
auto time = std::chrono::high_resolution_clock::now() +
|
||||
std::chrono::milliseconds((int)(sleepDuration * 1000));
|
||||
|
||||
switcher->abortMacroWait = false;
|
||||
std::unique_lock<std::mutex> lock(switcher->m);
|
||||
SetMacroAbortWait(false);
|
||||
std::unique_lock<std::mutex> lock(*GetMutex());
|
||||
waitHelper(&lock, GetMacro(), time);
|
||||
|
||||
return !switcher->abortMacroWait;
|
||||
return !MacroWaitShouldAbort();
|
||||
}
|
||||
|
||||
bool MacroActionWait::Save(obs_data_t *obj) const
|
||||
|
||||
@@ -192,7 +192,7 @@ void MacroActionWebsocketEdit::CheckForSettingsConflict()
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroActionWebsocketEdit::SetupWidgetVisibility()
|
||||
void MacroActionWebsocketEdit::SetWidgetVisibility()
|
||||
{
|
||||
_messageType->setVisible(_entryData->_api ==
|
||||
MacroActionWebsocket::API::SCENE_SWITCHER);
|
||||
@@ -283,7 +283,7 @@ void MacroActionWebsocketEdit::UpdateEntryData()
|
||||
_message->setPlainText(_entryData->_message);
|
||||
_connection->SetConnection(_entryData->_connection);
|
||||
|
||||
SetupWidgetVisibility();
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionWebsocketEdit::APITypeChanged(int index)
|
||||
@@ -294,7 +294,7 @@ void MacroActionWebsocketEdit::APITypeChanged(int index)
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_api = static_cast<MacroActionWebsocket::API>(index);
|
||||
SetupWidgetVisibility();
|
||||
SetWidgetVisibility();
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
@@ -308,7 +308,7 @@ void MacroActionWebsocketEdit::MessageTypeChanged(int index)
|
||||
auto lock = LockContext();
|
||||
_entryData->_type =
|
||||
static_cast<MacroActionWebsocket::MessageType>(index);
|
||||
SetupWidgetVisibility();
|
||||
SetWidgetVisibility();
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ protected:
|
||||
|
||||
private:
|
||||
void CheckForSettingsConflict();
|
||||
void SetupWidgetVisibility();
|
||||
void SetWidgetVisibility();
|
||||
void SetupRequestEdit();
|
||||
void SetupEventEdit();
|
||||
void SetupGenericEdit();
|
||||
|
||||
@@ -47,6 +47,12 @@ const static std::map<MacroConditionAudio::VolumeCondition, std::string>
|
||||
"AdvSceneSwitcher.condition.audio.state.unmute"},
|
||||
};
|
||||
|
||||
void MacroConditionAudio::SetType(const Type &type)
|
||||
{
|
||||
_checkType = type;
|
||||
SetupTempVars();
|
||||
}
|
||||
|
||||
MacroConditionAudio::~MacroConditionAudio()
|
||||
{
|
||||
obs_volmeter_remove_callback(_volmeter, SetVolumeLevel, this);
|
||||
@@ -56,17 +62,17 @@ MacroConditionAudio::~MacroConditionAudio()
|
||||
bool MacroConditionAudio::CheckOutputCondition()
|
||||
{
|
||||
bool ret = false;
|
||||
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||
OBSSourceAutoRelease source =
|
||||
obs_weak_source_get_source(_audioSource.GetSource());
|
||||
|
||||
// peak will have a value from -60 db to 0 db so we need to scale it
|
||||
double curVolume = ((double)_peak + 60) * 1.7;
|
||||
|
||||
switch (_outputCondition) {
|
||||
case OutputCondition::ABOVE:
|
||||
// peak will have a value from -60 db to 0 db
|
||||
ret = curVolume > _volume;
|
||||
break;
|
||||
case OutputCondition::BELOW:
|
||||
// peak will have a value from -60 db to 0 db
|
||||
ret = curVolume < _volume;
|
||||
break;
|
||||
default:
|
||||
@@ -74,24 +80,25 @@ bool MacroConditionAudio::CheckOutputCondition()
|
||||
}
|
||||
|
||||
SetVariableValue(std::to_string(curVolume));
|
||||
SetTempVarValue("output_volume", std::to_string(curVolume));
|
||||
|
||||
// Reset for next check
|
||||
_peak = -std::numeric_limits<float>::infinity();
|
||||
obs_source_release(s);
|
||||
if (_audioSource.GetType() == SourceSelection::Type::VARIABLE) {
|
||||
ResetVolmeter();
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret && source;
|
||||
}
|
||||
|
||||
bool MacroConditionAudio::CheckVolumeCondition()
|
||||
{
|
||||
bool ret = false;
|
||||
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||
OBSSourceAutoRelease source =
|
||||
obs_weak_source_get_source(_audioSource.GetSource());
|
||||
|
||||
float curVolume = obs_source_get_volume(s);
|
||||
bool muted = obs_source_muted(s);
|
||||
float curVolume = obs_source_get_volume(source);
|
||||
bool muted = obs_source_muted(source);
|
||||
|
||||
switch (_volumeCondition) {
|
||||
case VolumeCondition::ABOVE:
|
||||
@@ -118,8 +125,10 @@ bool MacroConditionAudio::CheckVolumeCondition()
|
||||
break;
|
||||
}
|
||||
|
||||
obs_source_release(s);
|
||||
return ret;
|
||||
SetTempVarValue("configured_volume", std::to_string(curVolume));
|
||||
SetTempVarValue("muted", (source && muted) ? "true" : "false");
|
||||
|
||||
return ret && source;
|
||||
}
|
||||
|
||||
bool MacroConditionAudio::CheckSyncOffset()
|
||||
@@ -129,16 +138,17 @@ bool MacroConditionAudio::CheckSyncOffset()
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||
auto curOffset = obs_source_get_sync_offset(s) / nsPerMs;
|
||||
OBSSourceAutoRelease source =
|
||||
obs_weak_source_get_source(_audioSource.GetSource());
|
||||
auto curOffset = obs_source_get_sync_offset(source) / nsPerMs;
|
||||
if (_outputCondition == OutputCondition::ABOVE) {
|
||||
ret = curOffset > _syncOffset;
|
||||
} else {
|
||||
ret = curOffset < _syncOffset;
|
||||
}
|
||||
SetVariableValue(std::to_string(curOffset));
|
||||
obs_source_release(s);
|
||||
return ret;
|
||||
SetTempVarValue("sync_offset", std::to_string(curOffset));
|
||||
return ret && source;
|
||||
}
|
||||
|
||||
bool MacroConditionAudio::CheckMonitor()
|
||||
@@ -148,11 +158,13 @@ bool MacroConditionAudio::CheckMonitor()
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||
ret = obs_source_get_monitoring_type(s) == _monitorType;
|
||||
OBSSourceAutoRelease source =
|
||||
obs_weak_source_get_source(_audioSource.GetSource());
|
||||
ret = obs_source_get_monitoring_type(source) == _monitorType;
|
||||
SetVariableValue("");
|
||||
obs_source_release(s);
|
||||
return ret;
|
||||
SetTempVarValue("monitor",
|
||||
std::to_string(obs_source_get_monitoring_type(source)));
|
||||
return ret && source;
|
||||
}
|
||||
|
||||
bool MacroConditionAudio::CheckBalance()
|
||||
@@ -162,16 +174,17 @@ bool MacroConditionAudio::CheckBalance()
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
auto s = obs_weak_source_get_source(_audioSource.GetSource());
|
||||
auto curBalance = obs_source_get_balance_value(s);
|
||||
OBSSourceAutoRelease source =
|
||||
obs_weak_source_get_source(_audioSource.GetSource());
|
||||
auto curBalance = obs_source_get_balance_value(source);
|
||||
if (_outputCondition == OutputCondition::ABOVE) {
|
||||
ret = curBalance > _balance;
|
||||
} else {
|
||||
ret = curBalance < _balance;
|
||||
}
|
||||
SetVariableValue(std::to_string(curBalance));
|
||||
obs_source_release(s);
|
||||
return ret;
|
||||
SetTempVarValue("balance", std::to_string(curBalance));
|
||||
return ret && source;
|
||||
}
|
||||
|
||||
bool MacroConditionAudio::CheckCondition()
|
||||
@@ -225,13 +238,12 @@ obs_volmeter_t *AddVolmeterToSource(MacroConditionAudio *entry,
|
||||
obs_volmeter_t *volmeter = obs_volmeter_create(OBS_FADER_LOG);
|
||||
obs_volmeter_add_callback(volmeter, MacroConditionAudio::SetVolumeLevel,
|
||||
entry);
|
||||
obs_source_t *as = obs_weak_source_get_source(source);
|
||||
if (!obs_volmeter_attach_source(volmeter, as)) {
|
||||
const char *name = obs_source_get_name(as);
|
||||
OBSSourceAutoRelease audioSource = obs_weak_source_get_source(source);
|
||||
if (!obs_volmeter_attach_source(volmeter, audioSource)) {
|
||||
const char *name = obs_source_get_name(audioSource);
|
||||
blog(LOG_WARNING, "failed to attach volmeter to source %s",
|
||||
name);
|
||||
}
|
||||
obs_source_release(as);
|
||||
|
||||
return volmeter;
|
||||
}
|
||||
@@ -290,6 +302,50 @@ void MacroConditionAudio::ResetVolmeter()
|
||||
_volmeter = AddVolmeterToSource(this, _audioSource.GetSource());
|
||||
}
|
||||
|
||||
void MacroConditionAudio::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
switch (_checkType) {
|
||||
case Type::OUTPUT_VOLUME:
|
||||
AddTempvar(
|
||||
"output_volume",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.output_volume"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.output_volume.description"));
|
||||
break;
|
||||
case Type::CONFIGURED_VOLUME:
|
||||
AddTempvar(
|
||||
"configured_volume",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.configured_volume"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.configured_volume.description"));
|
||||
AddTempvar("muted",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.muted"));
|
||||
break;
|
||||
case Type::SYNC_OFFSET:
|
||||
AddTempvar(
|
||||
"sync_offset",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.sync_offset"));
|
||||
break;
|
||||
case Type::MONITOR:
|
||||
AddTempvar("monitor",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.monitor"));
|
||||
break;
|
||||
case Type::BALANCE:
|
||||
AddTempvar("balance",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.audio.balance"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void populateCheckTypes(QComboBox *list)
|
||||
{
|
||||
list->clear();
|
||||
@@ -397,10 +453,9 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
||||
void MacroConditionAudioEdit::UpdateVolmeterSource()
|
||||
{
|
||||
delete _volMeter;
|
||||
obs_source_t *soruce = obs_weak_source_get_source(
|
||||
OBSSourceAutoRelease soruce = obs_weak_source_get_source(
|
||||
_entryData->_audioSource.GetSource());
|
||||
_volMeter = new VolControl(soruce);
|
||||
obs_source_release(soruce);
|
||||
_volMeter = new VolControl(soruce.Get());
|
||||
|
||||
QLayout *layout = this->layout();
|
||||
layout->addWidget(_volMeter);
|
||||
@@ -479,10 +534,9 @@ void MacroConditionAudioEdit::ConditionChanged(int cond)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
if (_entryData->_checkType ==
|
||||
MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::SYNC_OFFSET) {
|
||||
if (_entryData->GetType() == MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->GetType() == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->GetType() == MacroConditionAudio::Type::SYNC_OFFSET) {
|
||||
_entryData->_outputCondition =
|
||||
static_cast<MacroConditionAudio::OutputCondition>(cond);
|
||||
} else {
|
||||
@@ -499,16 +553,15 @@ void MacroConditionAudioEdit::CheckTypeChanged(int idx)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_checkType = static_cast<MacroConditionAudio::Type>(
|
||||
_checkTypes->itemData(idx).toInt());
|
||||
_entryData->SetType(static_cast<MacroConditionAudio::Type>(
|
||||
_checkTypes->itemData(idx).toInt()));
|
||||
|
||||
const QSignalBlocker b(_condition);
|
||||
if (_entryData->_checkType ==
|
||||
MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::SYNC_OFFSET) {
|
||||
if (_entryData->GetType() == MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->GetType() == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->GetType() == MacroConditionAudio::Type::SYNC_OFFSET) {
|
||||
populateOutputConditionSelection(_condition);
|
||||
} else if (_entryData->_checkType ==
|
||||
} else if (_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::CONFIGURED_VOLUME) {
|
||||
populateVolumeConditionSelection(_condition);
|
||||
}
|
||||
@@ -526,17 +579,16 @@ void MacroConditionAudioEdit::UpdateEntryData()
|
||||
_syncOffset->SetValue(_entryData->_syncOffset);
|
||||
_monitorTypes->setCurrentIndex(_entryData->_monitorType);
|
||||
_balance->SetDoubleValue(_entryData->_balance);
|
||||
_checkTypes->setCurrentIndex(_checkTypes->findData(
|
||||
static_cast<int>(_entryData->_checkType)));
|
||||
_checkTypes->setCurrentIndex(
|
||||
_checkTypes->findData(static_cast<int>(_entryData->GetType())));
|
||||
|
||||
if (_entryData->_checkType ==
|
||||
MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::SYNC_OFFSET) {
|
||||
if (_entryData->GetType() == MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->GetType() == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->GetType() == MacroConditionAudio::Type::SYNC_OFFSET) {
|
||||
populateOutputConditionSelection(_condition);
|
||||
_condition->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_outputCondition));
|
||||
} else if (_entryData->_checkType ==
|
||||
} else if (_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::CONFIGURED_VOLUME) {
|
||||
populateVolumeConditionSelection(_condition);
|
||||
_condition->setCurrentIndex(
|
||||
@@ -554,9 +606,9 @@ void MacroConditionAudioEdit::SetWidgetVisibility()
|
||||
}
|
||||
|
||||
_volume->setVisible(
|
||||
_entryData->_checkType ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
(_entryData->_checkType ==
|
||||
(_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::CONFIGURED_VOLUME &&
|
||||
(_entryData->_volumeCondition ==
|
||||
MacroConditionAudio::VolumeCondition::ABOVE ||
|
||||
@@ -565,20 +617,20 @@ void MacroConditionAudioEdit::SetWidgetVisibility()
|
||||
_entryData->_volumeCondition ==
|
||||
MacroConditionAudio::VolumeCondition::BELOW)));
|
||||
_condition->setVisible(
|
||||
_entryData->_checkType ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::OUTPUT_VOLUME ||
|
||||
_entryData->_checkType ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::CONFIGURED_VOLUME ||
|
||||
_entryData->_checkType == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->_checkType ==
|
||||
_entryData->GetType() == MacroConditionAudio::Type::BALANCE ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::SYNC_OFFSET);
|
||||
_syncOffset->setVisible(_entryData->_checkType ==
|
||||
_syncOffset->setVisible(_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::SYNC_OFFSET);
|
||||
_monitorTypes->setVisible(_entryData->_checkType ==
|
||||
_monitorTypes->setVisible(_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::MONITOR);
|
||||
_balance->setVisible(_entryData->_checkType ==
|
||||
_balance->setVisible(_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::BALANCE);
|
||||
_volMeter->setVisible(_entryData->_checkType ==
|
||||
_volMeter->setVisible(_entryData->GetType() ==
|
||||
MacroConditionAudio::Type::OUTPUT_VOLUME);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ public:
|
||||
MONITOR,
|
||||
BALANCE,
|
||||
};
|
||||
void SetType(const Type &);
|
||||
Type GetType() const { return _checkType; }
|
||||
|
||||
enum class OutputCondition {
|
||||
ABOVE,
|
||||
@@ -56,7 +58,6 @@ public:
|
||||
NumberVariable<int> _syncOffset = 0;
|
||||
obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE;
|
||||
NumberVariable<double> _balance = 0.5;
|
||||
Type _checkType = Type::OUTPUT_VOLUME;
|
||||
OutputCondition _outputCondition = OutputCondition::ABOVE;
|
||||
VolumeCondition _volumeCondition = VolumeCondition::ABOVE;
|
||||
obs_volmeter_t *_volmeter = nullptr;
|
||||
@@ -67,7 +68,9 @@ private:
|
||||
bool CheckSyncOffset();
|
||||
bool CheckMonitor();
|
||||
bool CheckBalance();
|
||||
void SetupTempVars();
|
||||
|
||||
Type _checkType = Type::OUTPUT_VOLUME;
|
||||
float _peak = -std::numeric_limits<float>::infinity();
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "macro-condition-cursor.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "platform-funcs.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
@@ -61,13 +60,15 @@ bool MacroConditionCursor::CheckCondition()
|
||||
std::to_string(cursorPos.second));
|
||||
break;
|
||||
case Condition::MOVING:
|
||||
ret = switcher->cursorPosChanged;
|
||||
ret = cursorPos.first != _lastCursorPosition.first ||
|
||||
cursorPos.second != _lastCursorPosition.second;
|
||||
break;
|
||||
case Condition::CLICK:
|
||||
ret = CheckClick();
|
||||
break;
|
||||
}
|
||||
_lastCheckTime = std::chrono::high_resolution_clock::now();
|
||||
_lastCursorPosition = cursorPos;
|
||||
|
||||
if (GetVariableValue().empty()) {
|
||||
SetVariableValue(ret ? "true" : "false");
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
private:
|
||||
bool CheckClick();
|
||||
std::chrono::high_resolution_clock::time_point _lastCheckTime{};
|
||||
std::pair<int, int> _lastCursorPosition;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
|
||||
@@ -60,7 +60,8 @@ const static std::map<MacroConditionDate::Day, std::string> dayOfWeekNames = {
|
||||
bool MacroConditionDate::CheckDayOfWeek(int64_t msSinceLastCheck)
|
||||
{
|
||||
QDateTime cur = QDateTime::currentDateTime();
|
||||
SetVariableValue(cur.toString().toStdString());
|
||||
SetVariables(cur);
|
||||
|
||||
if (_dayOfWeek != Day::ANY &&
|
||||
cur.date().dayOfWeek() != static_cast<int>(_dayOfWeek)) {
|
||||
return false;
|
||||
@@ -133,7 +134,7 @@ bool MacroConditionDate::CheckRegularDate(int64_t msSinceLastCheck)
|
||||
{
|
||||
bool match = false;
|
||||
QDateTime cur = QDateTime::currentDateTime();
|
||||
SetVariableValue(cur.toString().toStdString());
|
||||
SetVariables(cur);
|
||||
|
||||
if (_ignoreDate) {
|
||||
_dateTime.setDate(cur.date());
|
||||
@@ -304,6 +305,37 @@ QDateTime MacroConditionDate::GetNextMatchDateTime() const
|
||||
return _dateTime;
|
||||
}
|
||||
|
||||
void MacroConditionDate::SetVariables(const QDateTime &date)
|
||||
{
|
||||
SetVariableValue(date.toString().toStdString());
|
||||
|
||||
SetTempVarValue("year", std::to_string(date.date().year()));
|
||||
SetTempVarValue("month", std::to_string(date.date().month()));
|
||||
SetTempVarValue("day", std::to_string(date.date().day()));
|
||||
SetTempVarValue("hour", std::to_string(date.time().hour()));
|
||||
SetTempVarValue("minute", std::to_string(date.time().minute()));
|
||||
SetTempVarValue("second", std::to_string(date.time().second()));
|
||||
SetTempVarValue("dayOfWeek", std::to_string(date.date().dayOfWeek()));
|
||||
}
|
||||
|
||||
void MacroConditionDate::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
AddTempvar("year",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.date.year"));
|
||||
AddTempvar("month",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.date.month"));
|
||||
AddTempvar("day", obs_module_text("AdvSceneSwitcher.tempVar.date.day"));
|
||||
AddTempvar("hour",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.date.hour"));
|
||||
AddTempvar("minute",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.date.minute"));
|
||||
AddTempvar("second",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.date.second"));
|
||||
AddTempvar("dayOfWeek",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.date.dayOfWeek"));
|
||||
}
|
||||
|
||||
static inline void populateDaySelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : dayOfWeekNames) {
|
||||
@@ -606,10 +638,24 @@ void MacroConditionDateEdit::AdvancedSettingsToggleClicked()
|
||||
{
|
||||
auto lock = LockContext();
|
||||
_entryData->_dayOfWeekCheck = !_entryData->_dayOfWeekCheck;
|
||||
_entryData->_condition = MacroConditionDate::Condition::AT;
|
||||
}
|
||||
_condition->setCurrentIndex(0);
|
||||
_weekCondition->setCurrentIndex(0);
|
||||
|
||||
switch (_entryData->_condition) {
|
||||
case MacroConditionDate::Condition::BETWEEN:
|
||||
case MacroConditionDate::Condition::PATTERN:
|
||||
_condition->setCurrentIndex(0);
|
||||
_weekCondition->setCurrentIndex(0);
|
||||
break;
|
||||
case MacroConditionDate::Condition::AT:
|
||||
case MacroConditionDate::Condition::AFTER:
|
||||
case MacroConditionDate::Condition::BEFORE:
|
||||
_weekCondition->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_condition));
|
||||
_condition->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_condition));
|
||||
break;
|
||||
}
|
||||
|
||||
SetWidgetStatus();
|
||||
emit HeaderInfoChanged(
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
|
||||
@@ -64,6 +64,8 @@ private:
|
||||
bool CheckRegularDate(int64_t);
|
||||
bool CheckBetween(const QDateTime &now);
|
||||
bool CheckPattern(QDateTime now, int64_t secondsSinceLastCheck);
|
||||
void SetVariables(const QDateTime &date);
|
||||
void SetupTempVars();
|
||||
|
||||
QDateTime _dateTime = QDateTime::currentDateTime();
|
||||
QDateTime _dateTime2 = QDateTime::currentDateTime();
|
||||
|
||||
@@ -1,84 +1,24 @@
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-properties.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "macro-condition-scene.hpp"
|
||||
#include "section.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::map<std::string, MacroConditionInfo> &MacroConditionFactory::GetMap()
|
||||
{
|
||||
static std::map<std::string, MacroConditionInfo> _methods;
|
||||
return _methods;
|
||||
}
|
||||
|
||||
bool MacroConditionFactory::Register(const std::string &id,
|
||||
MacroConditionInfo info)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it == GetMap().end()) {
|
||||
GetMap()[id] = info;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroCondition>
|
||||
MacroConditionFactory::Create(const std::string &id, Macro *m)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._createFunc(m);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QWidget *
|
||||
MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroCondition> cond)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._createWidgetFunc(parent, cond);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string MacroConditionFactory::GetConditionName(const std::string &id)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._name;
|
||||
}
|
||||
return "unknown condition";
|
||||
}
|
||||
|
||||
std::string MacroConditionFactory::GetIdByName(const QString &name)
|
||||
{
|
||||
for (auto it : GetMap()) {
|
||||
if (name == obs_module_text(it.second._name.c_str())) {
|
||||
return it.first;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool MacroConditionFactory::UsesDurationModifier(const std::string &id)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._useDurationModifier;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void populateLogicSelection(QComboBox *list, bool root = false)
|
||||
{
|
||||
if (root) {
|
||||
for (auto entry : MacroCondition::logicTypes) {
|
||||
for (const auto &entry : MacroCondition::logicTypes) {
|
||||
if (static_cast<int>(entry.first) < logic_root_offset) {
|
||||
list->addItem(obs_module_text(
|
||||
entry.second._name.c_str()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto entry : MacroCondition::logicTypes) {
|
||||
for (const auto &entry : MacroCondition::logicTypes) {
|
||||
if (static_cast<int>(entry.first) >=
|
||||
logic_root_offset) {
|
||||
list->addItem(obs_module_text(
|
||||
@@ -90,7 +30,7 @@ static inline void populateLogicSelection(QComboBox *list, bool root = false)
|
||||
|
||||
static inline void populateConditionSelection(QComboBox *list)
|
||||
{
|
||||
for (auto &[_, condition] :
|
||||
for (const auto &[_, condition] :
|
||||
MacroConditionFactory::GetConditionTypes()) {
|
||||
QString entry(obs_module_text(condition._name.c_str()));
|
||||
if (list->findText(entry) == -1) {
|
||||
@@ -179,7 +119,7 @@ void DurationModifierEdit::Collapse(bool collapse)
|
||||
MacroConditionEdit::MacroConditionEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
||||
const std::string &id, bool root)
|
||||
: MacroSegmentEdit(switcher->macroProperties._highlightConditions,
|
||||
: MacroSegmentEdit(GetGlobalMacroProperties()._highlightConditions,
|
||||
parent),
|
||||
_logicSelection(new QComboBox()),
|
||||
_conditionSelection(new FilterComboBox()),
|
||||
@@ -312,6 +252,7 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
||||
*_entryData = MacroConditionFactory::Create(id, macro);
|
||||
(*_entryData)->SetIndex(idx);
|
||||
(*_entryData)->SetLogicType(logic);
|
||||
(*_entryData)->PostLoad();
|
||||
}
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
@@ -342,7 +283,7 @@ void MacroConditionEdit::DurationModifierChanged(DurationModifier::Type m)
|
||||
(*_entryData)->SetDurationModifier(m);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroSegment> MacroConditionEdit::Data()
|
||||
std::shared_ptr<MacroSegment> MacroConditionEdit::Data() const
|
||||
{
|
||||
return *_entryData;
|
||||
}
|
||||
@@ -383,6 +324,7 @@ void AdvSceneSwitcher::AddMacroCondition(int idx)
|
||||
macro->Conditions().at(idx)->Load(data);
|
||||
obs_data_release(data);
|
||||
}
|
||||
macro->Conditions().at(idx)->PostLoad();
|
||||
(*cond)->SetLogicType(logic);
|
||||
macro->UpdateConditionIndices();
|
||||
ui->conditionsList->Insert(
|
||||
|
||||
@@ -1,38 +1,12 @@
|
||||
#pragma once
|
||||
#include "macro-condition.hpp"
|
||||
#include "macro-condition-factory.hpp"
|
||||
#include "filter-combo-box.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct MacroConditionInfo {
|
||||
using TCreateMethod = std::shared_ptr<MacroCondition> (*)(Macro *m);
|
||||
using TCreateWidgetMethod =
|
||||
QWidget *(*)(QWidget *parent, std::shared_ptr<MacroCondition>);
|
||||
TCreateMethod _createFunc = nullptr;
|
||||
TCreateWidgetMethod _createWidgetFunc = nullptr;
|
||||
std::string _name;
|
||||
bool _useDurationModifier = true;
|
||||
};
|
||||
|
||||
class MacroConditionFactory {
|
||||
public:
|
||||
MacroConditionFactory() = delete;
|
||||
static bool Register(const std::string &, MacroConditionInfo);
|
||||
static std::shared_ptr<MacroCondition> Create(const std::string &,
|
||||
Macro *m);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroCondition>);
|
||||
static auto GetConditionTypes() { return GetMap(); }
|
||||
static std::string GetConditionName(const std::string &);
|
||||
static std::string GetIdByName(const QString &name);
|
||||
static bool UsesDurationModifier(const std::string &id);
|
||||
|
||||
private:
|
||||
static std::map<std::string, MacroConditionInfo> &GetMap();
|
||||
};
|
||||
|
||||
class DurationModifierEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -75,7 +49,7 @@ private slots:
|
||||
|
||||
private:
|
||||
void SetLogicSelection();
|
||||
std::shared_ptr<MacroSegment> Data();
|
||||
std::shared_ptr<MacroSegment> Data() const;
|
||||
|
||||
QComboBox *_logicSelection;
|
||||
FilterComboBox *_conditionSelection;
|
||||
|
||||
66
src/macro-core/macro-condition-factory.cpp
Normal file
66
src/macro-core/macro-condition-factory.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#include "macro-condition-factory.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
std::map<std::string, MacroConditionInfo> &MacroConditionFactory::GetMap()
|
||||
{
|
||||
static std::map<std::string, MacroConditionInfo> _methods;
|
||||
return _methods;
|
||||
}
|
||||
|
||||
bool MacroConditionFactory::Register(const std::string &id,
|
||||
MacroConditionInfo info)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it == GetMap().end()) {
|
||||
GetMap()[id] = info;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroCondition>
|
||||
MacroConditionFactory::Create(const std::string &id, Macro *m)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._create(m);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QWidget *
|
||||
MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroCondition> cond)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._createWidget(parent, cond);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string MacroConditionFactory::GetConditionName(const std::string &id)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._name;
|
||||
}
|
||||
return "unknown condition";
|
||||
}
|
||||
|
||||
std::string MacroConditionFactory::GetIdByName(const QString &name)
|
||||
{
|
||||
for (auto it : GetMap()) {
|
||||
if (name == obs_module_text(it.second._name.c_str())) {
|
||||
return it.first;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool MacroConditionFactory::UsesDurationModifier(const std::string &id)
|
||||
{
|
||||
if (auto it = GetMap().find(id); it != GetMap().end()) {
|
||||
return it->second._useDurationModifier;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
35
src/macro-core/macro-condition-factory.hpp
Normal file
35
src/macro-core/macro-condition-factory.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include "macro-condition.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace advss {
|
||||
|
||||
struct MacroConditionInfo {
|
||||
using CreateCondition = std::shared_ptr<MacroCondition> (*)(Macro *m);
|
||||
using CreateConditionWidget =
|
||||
QWidget *(*)(QWidget *parent, std::shared_ptr<MacroCondition>);
|
||||
CreateCondition _create = nullptr;
|
||||
CreateConditionWidget _createWidget = nullptr;
|
||||
std::string _name;
|
||||
bool _useDurationModifier = true;
|
||||
};
|
||||
|
||||
class MacroConditionFactory {
|
||||
public:
|
||||
MacroConditionFactory() = delete;
|
||||
static bool Register(const std::string &, MacroConditionInfo);
|
||||
static std::shared_ptr<MacroCondition> Create(const std::string &,
|
||||
Macro *m);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroCondition>);
|
||||
static auto GetConditionTypes() { return GetMap(); }
|
||||
static std::string GetConditionName(const std::string &);
|
||||
static std::string GetIdByName(const QString &name);
|
||||
static bool UsesDurationModifier(const std::string &id);
|
||||
|
||||
private:
|
||||
static std::map<std::string, MacroConditionInfo> &GetMap();
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "macro-condition-file.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "curl-helper.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
|
||||
#include <QTextStream>
|
||||
#include <QFileDialog>
|
||||
@@ -28,16 +28,16 @@ static size_t WriteCallback(void *contents, size_t size, size_t nmemb,
|
||||
static std::string getRemoteData(std::string &url)
|
||||
{
|
||||
std::string readBuffer;
|
||||
switcher->curl.SetOpt(CURLOPT_URL, url.c_str());
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
switcher->curl.SetOpt(CURLOPT_WRITEDATA, &readBuffer);
|
||||
CurlHelper::SetOpt(CURLOPT_URL, url.c_str());
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
CurlHelper::SetOpt(CURLOPT_WRITEDATA, &readBuffer);
|
||||
// Set timeout to at least one second
|
||||
int timeout = switcher->interval / 1000;
|
||||
int timeout = GetIntervalValue() / 1000;
|
||||
if (timeout == 0) {
|
||||
timeout = 1;
|
||||
}
|
||||
switcher->curl.SetOpt(CURLOPT_TIMEOUT, 1);
|
||||
switcher->curl.Perform();
|
||||
CurlHelper::SetOpt(CURLOPT_TIMEOUT, 1);
|
||||
CurlHelper::Perform();
|
||||
return readBuffer;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,15 +24,14 @@ const static std::map<MacroConditionFilter::Condition, std::string>
|
||||
"AdvSceneSwitcher.condition.filter.type.settingsChanged"},
|
||||
};
|
||||
|
||||
bool MacroConditionFilter::CheckCondition()
|
||||
bool MacroConditionFilter::CheckConditionHelper(const OBSWeakSource &filter)
|
||||
{
|
||||
auto filterWeakSource = _filter.GetFilter(_source);
|
||||
if (!filterWeakSource) {
|
||||
bool ret = false;
|
||||
OBSSourceAutoRelease filterSource = obs_weak_source_get_source(filter);
|
||||
if (!filterSource.Get()) {
|
||||
return false;
|
||||
}
|
||||
auto filterSource = obs_weak_source_get_source(filterWeakSource);
|
||||
|
||||
bool ret = false;
|
||||
switch (_condition) {
|
||||
case Condition::ENABLED:
|
||||
ret = obs_source_enabled(filterSource);
|
||||
@@ -41,10 +40,9 @@ bool MacroConditionFilter::CheckCondition()
|
||||
ret = !obs_source_enabled(filterSource);
|
||||
break;
|
||||
case Condition::SETTINGS_MATCH:
|
||||
ret = CompareSourceSettings(filterWeakSource, _settings,
|
||||
_regex);
|
||||
ret = CompareSourceSettings(filter, _settings, _regex);
|
||||
if (IsReferencedInVars()) {
|
||||
SetVariableValue(GetSourceSettings(filterWeakSource));
|
||||
SetVariableValue(GetSourceSettings(filter));
|
||||
}
|
||||
break;
|
||||
case Condition::SETTINGS_CHANGED: {
|
||||
@@ -57,8 +55,20 @@ bool MacroConditionFilter::CheckCondition()
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
obs_source_release(filterSource);
|
||||
bool MacroConditionFilter::CheckCondition()
|
||||
{
|
||||
auto filters = _filter.GetFilters(_source);
|
||||
if (filters.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ret = true;
|
||||
for (const auto &filter : filters) {
|
||||
ret = ret && CheckConditionHelper(filter);
|
||||
}
|
||||
|
||||
if (GetVariableValue().empty()) {
|
||||
SetVariableValue(ret ? "true" : "false");
|
||||
@@ -211,12 +221,12 @@ void MacroConditionFilterEdit::ConditionChanged(int index)
|
||||
void MacroConditionFilterEdit::GetSettingsClicked()
|
||||
{
|
||||
if (_loading || !_entryData ||
|
||||
!_entryData->_filter.GetFilter(_entryData->_source)) {
|
||||
_entryData->_filter.GetFilters(_entryData->_source).empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString json = FormatJsonString(GetSourceSettings(
|
||||
_entryData->_filter.GetFilter(_entryData->_source)));
|
||||
_entryData->_filter.GetFilters(_entryData->_source).at(0)));
|
||||
if (_entryData->_regex.Enabled()) {
|
||||
json = EscapeForRegex(json);
|
||||
}
|
||||
|
||||
@@ -38,8 +38,9 @@ public:
|
||||
RegexConfig _regex;
|
||||
|
||||
private:
|
||||
std::string _currentSettings;
|
||||
bool CheckConditionHelper(const OBSWeakSource &);
|
||||
|
||||
std::string _currentSettings;
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
@@ -24,6 +24,8 @@ const static std::map<MacroConditionMacro::Type, std::string>
|
||||
"AdvSceneSwitcher.condition.macro.type.actionDisabled"},
|
||||
{MacroConditionMacro::Type::ACTION_ENABLED,
|
||||
"AdvSceneSwitcher.condition.macro.type.actionEnabled"},
|
||||
{MacroConditionMacro::Type::PAUSED,
|
||||
"AdvSceneSwitcher.condition.macro.type.paused"},
|
||||
};
|
||||
|
||||
const static std::map<MacroConditionMacro::CounterCondition, std::string>
|
||||
@@ -75,6 +77,8 @@ bool MacroConditionMacro::CheckMultiStateCondition()
|
||||
}
|
||||
}
|
||||
|
||||
SetTempVarValue("matchedCount", std::to_string(matchedCount));
|
||||
|
||||
switch (_multiSateCondition) {
|
||||
case MacroConditionMacro::MultiStateCondition::BELOW:
|
||||
return matchedCount < _multiSateCount;
|
||||
@@ -107,6 +111,16 @@ bool MacroConditionMacro::CheckActionStateCondition()
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacroConditionMacro::CheckPauseState()
|
||||
{
|
||||
auto macro = _macro.GetMacro();
|
||||
if (!macro) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return macro->Paused();
|
||||
}
|
||||
|
||||
bool MacroConditionMacro::CheckCountCondition()
|
||||
{
|
||||
auto macro = _macro.GetMacro();
|
||||
@@ -114,6 +128,8 @@ bool MacroConditionMacro::CheckCountCondition()
|
||||
return false;
|
||||
}
|
||||
|
||||
SetTempVarValue("runCount", std::to_string(macro->RunCount()));
|
||||
|
||||
switch (_counterCondition) {
|
||||
case CounterCondition::BELOW:
|
||||
return macro->RunCount() < _count;
|
||||
@@ -140,6 +156,8 @@ bool MacroConditionMacro::CheckCondition()
|
||||
case Type::ACTION_DISABLED:
|
||||
case Type::ACTION_ENABLED:
|
||||
return CheckActionStateCondition();
|
||||
case Type::PAUSED:
|
||||
return CheckPauseState();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -193,7 +211,7 @@ bool MacroConditionMacro::Load(obs_data_t *obj)
|
||||
|
||||
bool MacroConditionMacro::PostLoad()
|
||||
{
|
||||
return MacroRefCondition::PostLoad() &&
|
||||
return MacroCondition::PostLoad() && MacroRefCondition::PostLoad() &&
|
||||
MultiMacroRefCondtition::PostLoad();
|
||||
}
|
||||
|
||||
@@ -202,6 +220,45 @@ std::string MacroConditionMacro::GetShortDesc() const
|
||||
return _macro.Name();
|
||||
}
|
||||
|
||||
void MacroConditionMacro::SetType(Type type)
|
||||
{
|
||||
_type = type;
|
||||
SetupTempVars();
|
||||
}
|
||||
|
||||
void MacroConditionMacro::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
switch (_type) {
|
||||
case Type::COUNT:
|
||||
AddTempvar(
|
||||
"runCount",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.runCount"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.runCount.description"));
|
||||
break;
|
||||
case Type::STATE:
|
||||
break;
|
||||
case Type::MULTI_STATE:
|
||||
AddTempvar(
|
||||
"matchedCount",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.matchedCount"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.macro.matchedCount.description"));
|
||||
break;
|
||||
case Type::ACTION_DISABLED:
|
||||
break;
|
||||
case Type::ACTION_ENABLED:
|
||||
break;
|
||||
case Type::PAUSED:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void populateTypeSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : macroConditionTypes) {
|
||||
@@ -335,7 +392,10 @@ void MacroConditionMacroEdit::ClearLayouts()
|
||||
|
||||
void MacroConditionMacroEdit::SetupWidgets()
|
||||
{
|
||||
switch (_entryData->_type) {
|
||||
SetWidgetVisibility();
|
||||
ClearLayouts();
|
||||
|
||||
switch (_entryData->GetType()) {
|
||||
case MacroConditionMacro::Type::COUNT:
|
||||
SetupCountWidgets();
|
||||
break;
|
||||
@@ -351,6 +411,9 @@ void MacroConditionMacroEdit::SetupWidgets()
|
||||
case MacroConditionMacro::Type::ACTION_ENABLED:
|
||||
SetupActionStateWidgets(true);
|
||||
break;
|
||||
case MacroConditionMacro::Type::PAUSED:
|
||||
SetupPauseWidgets();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -358,38 +421,24 @@ void MacroConditionMacroEdit::SetupWidgets()
|
||||
|
||||
void MacroConditionMacroEdit::SetupStateWidgets()
|
||||
{
|
||||
SetWidgetVisibility();
|
||||
ClearLayouts();
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{macros}}", _macros},
|
||||
};
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.condition.macro.state.entry"),
|
||||
_settingsLine1, widgetPlaceholders);
|
||||
_settingsLine1, {{"{{macros}}", _macros}});
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::SetupMultiStateWidgets()
|
||||
{
|
||||
SetWidgetVisibility();
|
||||
ClearLayouts();
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{multiStateConditions}}", _multiStateConditions},
|
||||
{"{{multiStateCount}}", _multiStateCount},
|
||||
};
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.macro.multistate.entry"),
|
||||
_settingsLine1, widgetPlaceholders);
|
||||
_settingsLine1,
|
||||
{{"{{multiStateConditions}}", _multiStateConditions},
|
||||
{"{{multiStateCount}}", _multiStateCount}});
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::SetupCountWidgets()
|
||||
{
|
||||
SetWidgetVisibility();
|
||||
ClearLayouts();
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{macros}}", _macros},
|
||||
{"{{conditions}}", _counterConditions},
|
||||
{"{{count}}", _count},
|
||||
@@ -408,9 +457,6 @@ void MacroConditionMacroEdit::SetupCountWidgets()
|
||||
|
||||
void MacroConditionMacroEdit::SetupActionStateWidgets(bool enable)
|
||||
{
|
||||
SetWidgetVisibility();
|
||||
ClearLayouts();
|
||||
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
enable ? "AdvSceneSwitcher.condition.macro.actionState.enabled.entry"
|
||||
@@ -419,35 +465,49 @@ void MacroConditionMacroEdit::SetupActionStateWidgets(bool enable)
|
||||
{{"{{macros}}", _macros}, {"{{actionIndex}}", _actionIndex}});
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::SetupPauseWidgets()
|
||||
{
|
||||
PlaceWidgets(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.macro.paused.entry"),
|
||||
_settingsLine1, {{"{{macros}}", _macros}});
|
||||
}
|
||||
|
||||
void MacroConditionMacroEdit::SetWidgetVisibility()
|
||||
{
|
||||
_macros->setVisible(
|
||||
_entryData->_type == MacroConditionMacro::Type::COUNT ||
|
||||
_entryData->_type == MacroConditionMacro::Type::STATE ||
|
||||
_entryData->_type ==
|
||||
_entryData->GetType() == MacroConditionMacro::Type::COUNT ||
|
||||
_entryData->GetType() == MacroConditionMacro::Type::STATE ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||
_entryData->_type == MacroConditionMacro::Type::ACTION_ENABLED);
|
||||
_counterConditions->setVisible(_entryData->_type ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_ENABLED ||
|
||||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED);
|
||||
_counterConditions->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::COUNT);
|
||||
_count->setVisible(_entryData->_type ==
|
||||
_count->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::COUNT);
|
||||
_currentCount->setVisible(_entryData->_type ==
|
||||
_currentCount->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::COUNT);
|
||||
_resetCount->setVisible(_entryData->_type ==
|
||||
_resetCount->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::COUNT);
|
||||
_macroList->setVisible(_entryData->_type ==
|
||||
_macroList->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::MULTI_STATE);
|
||||
_multiStateConditions->setVisible(
|
||||
_entryData->_type == MacroConditionMacro::Type::MULTI_STATE);
|
||||
_multiStateCount->setVisible(_entryData->_type ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::MULTI_STATE);
|
||||
_multiStateCount->setVisible(_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::MULTI_STATE);
|
||||
_actionIndex->setVisible(
|
||||
_entryData->_type ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||
_entryData->_type == MacroConditionMacro::Type::ACTION_ENABLED);
|
||||
if (_entryData->_type == MacroConditionMacro::Type::MULTI_STATE ||
|
||||
_entryData->_type == MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||
_entryData->_type == MacroConditionMacro::Type::ACTION_ENABLED) {
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_ENABLED);
|
||||
if (_entryData->GetType() == MacroConditionMacro::Type::MULTI_STATE ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_DISABLED ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionMacro::Type::ACTION_ENABLED ||
|
||||
_entryData->GetType() == MacroConditionMacro::Type::PAUSED) {
|
||||
_pausedWarning->hide();
|
||||
}
|
||||
|
||||
@@ -463,7 +523,7 @@ void MacroConditionMacroEdit::UpdateEntryData()
|
||||
|
||||
SetupWidgets();
|
||||
_macros->SetCurrentMacro(_entryData->_macro);
|
||||
_types->setCurrentIndex(static_cast<int>(_entryData->_type));
|
||||
_types->setCurrentIndex(static_cast<int>(_entryData->GetType()));
|
||||
_counterConditions->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_counterCondition));
|
||||
_count->SetValue(_entryData->_count);
|
||||
@@ -535,7 +595,7 @@ void MacroConditionMacroEdit::TypeChanged(int type)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_type = static_cast<MacroConditionMacro::Type>(type);
|
||||
_entryData->SetType(static_cast<MacroConditionMacro::Type>(type));
|
||||
SetupWidgets();
|
||||
}
|
||||
|
||||
@@ -571,7 +631,8 @@ void MacroConditionMacroEdit::UpdatePaused()
|
||||
auto macro = _entryData->_macro.GetMacro();
|
||||
_pausedWarning->setVisible(
|
||||
_entryData &&
|
||||
_entryData->_type != MacroConditionMacro::Type::MULTI_STATE &&
|
||||
_entryData->GetType() !=
|
||||
MacroConditionMacro::Type::MULTI_STATE &&
|
||||
macro && macro->Paused());
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
@@ -39,8 +39,10 @@ public:
|
||||
MULTI_STATE,
|
||||
ACTION_DISABLED,
|
||||
ACTION_ENABLED,
|
||||
PAUSED,
|
||||
};
|
||||
Type _type = Type::STATE;
|
||||
void SetType(Type);
|
||||
Type GetType() const { return _type; }
|
||||
|
||||
enum class CounterCondition {
|
||||
BELOW,
|
||||
@@ -64,7 +66,11 @@ private:
|
||||
bool CheckStateCondition();
|
||||
bool CheckMultiStateCondition();
|
||||
bool CheckActionStateCondition();
|
||||
bool CheckPauseState();
|
||||
|
||||
void SetupTempVars();
|
||||
|
||||
Type _type = Type::STATE;
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
@@ -128,6 +134,7 @@ private:
|
||||
void SetupMultiStateWidgets();
|
||||
void SetupCountWidgets();
|
||||
void SetupActionStateWidgets(bool enable);
|
||||
void SetupPauseWidgets();
|
||||
void SetWidgetVisibility();
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "macro-condition-media.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -148,26 +150,20 @@ bool MacroConditionMedia::CheckMediaMatch()
|
||||
if (!_source.GetSource()) {
|
||||
return false;
|
||||
}
|
||||
bool match = false;
|
||||
bool matched = CheckState() && CheckTime();
|
||||
|
||||
if (matched && !(_onlyMatchOnChagne && _alreadyMatched)) {
|
||||
match = true;
|
||||
}
|
||||
_alreadyMatched = matched;
|
||||
|
||||
// reset for next check
|
||||
_stopped = false;
|
||||
_ended = false;
|
||||
_next = false;
|
||||
|
||||
return match;
|
||||
return matched;
|
||||
}
|
||||
|
||||
void MacroConditionMedia::HandleSceneChange()
|
||||
{
|
||||
UpdateMediaSourcesOfSceneList();
|
||||
_lastConfigureScene = switcher->currentScene;
|
||||
_lastConfigureScene = GetCurrentScene();
|
||||
}
|
||||
|
||||
bool MacroConditionMedia::CheckCondition()
|
||||
@@ -194,7 +190,7 @@ bool MacroConditionMedia::CheckCondition()
|
||||
break;
|
||||
}
|
||||
|
||||
if (_lastConfigureScene != switcher->currentScene) {
|
||||
if (_lastConfigureScene != GetCurrentScene()) {
|
||||
HandleSceneChange();
|
||||
}
|
||||
|
||||
@@ -210,7 +206,6 @@ bool MacroConditionMedia::Save(obs_data_t *obj) const
|
||||
obs_data_set_int(obj, "state", static_cast<int>(_state));
|
||||
obs_data_set_int(obj, "restriction", static_cast<int>(_restriction));
|
||||
_time.Save(obj);
|
||||
obs_data_set_bool(obj, "matchOnChagne", _onlyMatchOnChagne);
|
||||
obs_data_set_int(obj, "version", 0);
|
||||
return true;
|
||||
}
|
||||
@@ -268,7 +263,6 @@ bool MacroConditionMedia::Load(obs_data_t *obj)
|
||||
_restriction = static_cast<MacroConditionMedia::Time>(
|
||||
obs_data_get_int(obj, "restriction"));
|
||||
_time.Load(obj);
|
||||
_onlyMatchOnChagne = obs_data_get_bool(obj, "matchOnChagne");
|
||||
|
||||
if (_sourceType == Type::SOURCE) {
|
||||
obs_source_t *mediasource =
|
||||
@@ -408,9 +402,7 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
|
||||
_sources(new SourceSelectionWidget(this, QStringList(), true)),
|
||||
_states(new QComboBox()),
|
||||
_timeRestrictions(new QComboBox()),
|
||||
_time(new DurationSelection()),
|
||||
_onChange(new QCheckBox(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.media.matchOnChange")))
|
||||
_time(new DurationSelection())
|
||||
{
|
||||
_states->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.media.inconsistencyInfo"));
|
||||
@@ -432,14 +424,12 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
|
||||
this, SLOT(TimeRestrictionChanged(int)));
|
||||
QWidget::connect(_time, SIGNAL(DurationChanged(const Duration &)), this,
|
||||
SLOT(TimeChanged(const Duration &)));
|
||||
QWidget::connect(_onChange, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(OnChangeChanged(int)));
|
||||
|
||||
populateSourceTypes(_sourceTypes);
|
||||
populateMediaStates(_states);
|
||||
populateMediaTimes(_timeRestrictions);
|
||||
|
||||
QHBoxLayout *entryLayout = new QHBoxLayout;
|
||||
auto layout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{sourceTypes}}", _sourceTypes},
|
||||
{"{{mediaSources}}", _sources},
|
||||
@@ -449,11 +439,8 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
|
||||
{"{{time}}", _time},
|
||||
};
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.media.entry"),
|
||||
entryLayout, widgetPlaceholders);
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(entryLayout);
|
||||
mainLayout->addWidget(_onChange);
|
||||
setLayout(mainLayout);
|
||||
layout, widgetPlaceholders);
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
@@ -572,28 +559,12 @@ void MacroConditionMediaEdit::TimeChanged(const Duration &dur)
|
||||
}
|
||||
}
|
||||
|
||||
void MacroConditionMediaEdit::OnChangeChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_onlyMatchOnChagne = value;
|
||||
if (_entryData->_sourceType != MacroConditionMedia::Type::SOURCE) {
|
||||
_entryData->UpdateMediaSourcesOfSceneList();
|
||||
}
|
||||
}
|
||||
|
||||
void MacroConditionMediaEdit::SetWidgetVisibility()
|
||||
{
|
||||
_sources->setVisible(_entryData->_sourceType ==
|
||||
MacroConditionMedia::Type::SOURCE);
|
||||
_scenes->setVisible(_entryData->_sourceType !=
|
||||
MacroConditionMedia::Type::SOURCE);
|
||||
if (!_onChange->isChecked()) {
|
||||
_onChange->hide();
|
||||
}
|
||||
}
|
||||
|
||||
static int getIdxFromMediaState(MacroConditionMedia::State state)
|
||||
@@ -625,7 +596,6 @@ void MacroConditionMediaEdit::UpdateEntryData()
|
||||
MacroConditionMedia::Time::TIME_RESTRICTION_NONE) {
|
||||
_time->setDisabled(true);
|
||||
}
|
||||
_onChange->setChecked(_entryData->_onlyMatchOnChagne);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ public:
|
||||
OBSWeakSource _rawSource = nullptr;
|
||||
std::vector<MacroConditionMedia> _sourceGroup;
|
||||
Duration _time;
|
||||
bool _onlyMatchOnChagne = false;
|
||||
|
||||
private:
|
||||
bool CheckTime();
|
||||
@@ -84,9 +83,7 @@ private:
|
||||
bool _stopped = false;
|
||||
bool _ended = false;
|
||||
bool _next = false;
|
||||
// TODO: Remove _alreadyMatched as it does not make much sense when
|
||||
// time restrictions for macro conditions are available.
|
||||
bool _alreadyMatched = false;
|
||||
|
||||
// Workaround to enable use of "ended" to specify end of VLC playlist
|
||||
bool _previousStateEnded = false;
|
||||
// Used to keep track of scene changes
|
||||
@@ -119,7 +116,6 @@ private slots:
|
||||
void StateChanged(int index);
|
||||
void TimeRestrictionChanged(int index);
|
||||
void TimeChanged(const Duration &seconds);
|
||||
void OnChangeChanged(int);
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
@@ -130,7 +126,6 @@ protected:
|
||||
QComboBox *_states;
|
||||
QComboBox *_timeRestrictions;
|
||||
DurationSelection *_time;
|
||||
QCheckBox *_onChange;
|
||||
std::shared_ptr<MacroConditionMedia> _entryData;
|
||||
|
||||
private:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "macro-condition-plugin-state.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "macro-helpers.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -33,7 +34,7 @@ const static std::map<MacroConditionPluginState::Condition, std::string>
|
||||
MacroConditionPluginState::~MacroConditionPluginState()
|
||||
{
|
||||
if (_condition == Condition::OBS_SHUTDOWN) {
|
||||
switcher->shutdownConditionCount--;
|
||||
GetShutdownConditionCount()--;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,15 +42,15 @@ bool MacroConditionPluginState::CheckCondition()
|
||||
{
|
||||
switch (_condition) {
|
||||
case Condition::PLUGIN_SCENE_CHANGE:
|
||||
return switcher->macroSceneSwitched;
|
||||
return MacroSwitchedScene();
|
||||
case Condition::PLUGIN_RUNNING:
|
||||
return true;
|
||||
case Condition::OBS_SHUTDOWN:
|
||||
return switcher->obsIsShuttingDown;
|
||||
return OBSIsShuttingDown();
|
||||
case Condition::PLUGIN_START:
|
||||
return switcher->firstInterval;
|
||||
return IsFirstInterval();
|
||||
case Condition::PLUGIN_RESTART:
|
||||
return switcher->firstIntervalAfterStop;
|
||||
return IsFirstIntervalAfterStop();
|
||||
case Condition::SCENE_COLLECTION_CHANGE:
|
||||
if (_firstCheckAfterSceneCollectionChange) {
|
||||
_firstCheckAfterSceneCollectionChange = false;
|
||||
@@ -83,25 +84,33 @@ bool MacroConditionPluginState::Load(obs_data_t *obj)
|
||||
obs_data_get_int(obj, "condition"));
|
||||
switch (oldValue) {
|
||||
case PluginStateCondition::SCENE_SWITCHED:
|
||||
_condition = Condition::PLUGIN_SCENE_CHANGE;
|
||||
SetCondition(Condition::PLUGIN_SCENE_CHANGE);
|
||||
break;
|
||||
case PluginStateCondition::RUNNING:
|
||||
_condition = Condition::PLUGIN_RUNNING;
|
||||
SetCondition(Condition::PLUGIN_RUNNING);
|
||||
break;
|
||||
case PluginStateCondition::SHUTDOWN:
|
||||
_condition = Condition::OBS_SHUTDOWN;
|
||||
SetCondition(Condition::OBS_SHUTDOWN);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
_condition = static_cast<Condition>(
|
||||
obs_data_get_int(obj, "condition"));
|
||||
}
|
||||
if (_condition == Condition::OBS_SHUTDOWN) {
|
||||
switcher->shutdownConditionCount++;
|
||||
SetCondition(static_cast<Condition>(
|
||||
obs_data_get_int(obj, "condition")));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroConditionPluginState::SetCondition(Condition newValue)
|
||||
{
|
||||
if (_condition == Condition::OBS_SHUTDOWN) {
|
||||
GetShutdownConditionCount()--;
|
||||
}
|
||||
if (newValue == Condition::OBS_SHUTDOWN) {
|
||||
GetShutdownConditionCount()++;
|
||||
}
|
||||
_condition = newValue;
|
||||
}
|
||||
|
||||
static inline void populateConditionSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[action, name] : pluginStateConditionTypes) {
|
||||
@@ -148,17 +157,9 @@ void MacroConditionPluginStateEdit::ConditionChanged(int idx)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
if (_entryData->_condition ==
|
||||
MacroConditionPluginState::Condition::OBS_SHUTDOWN) {
|
||||
switcher->shutdownConditionCount--;
|
||||
}
|
||||
_entryData->_condition =
|
||||
_entryData->SetCondition(
|
||||
static_cast<MacroConditionPluginState::Condition>(
|
||||
_condition->itemData(idx).toInt());
|
||||
if (_entryData->_condition ==
|
||||
MacroConditionPluginState::Condition::OBS_SHUTDOWN) {
|
||||
switcher->shutdownConditionCount++;
|
||||
}
|
||||
_condition->itemData(idx).toInt()));
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -168,15 +169,15 @@ void MacroConditionPluginStateEdit::UpdateEntryData()
|
||||
return;
|
||||
}
|
||||
|
||||
_condition->setCurrentIndex(
|
||||
_condition->findData(static_cast<int>(_entryData->_condition)));
|
||||
_condition->setCurrentIndex(_condition->findData(
|
||||
static_cast<int>(_entryData->GetCondition())));
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionPluginStateEdit::SetWidgetVisibility()
|
||||
{
|
||||
_shutdownLimitation->setVisible(
|
||||
_entryData->_condition ==
|
||||
_entryData->GetCondition() ==
|
||||
MacroConditionPluginState::Condition::OBS_SHUTDOWN);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
@@ -26,10 +26,11 @@ public:
|
||||
SCENE_COLLECTION_CHANGE,
|
||||
PLUGIN_SCENE_CHANGE,
|
||||
};
|
||||
|
||||
Condition _condition = Condition::PLUGIN_SCENE_CHANGE;
|
||||
void SetCondition(Condition);
|
||||
Condition GetCondition() const { return _condition; }
|
||||
|
||||
private:
|
||||
Condition _condition = Condition::PLUGIN_SCENE_CHANGE;
|
||||
bool _firstCheckAfterSceneCollectionChange = true;
|
||||
|
||||
const static uint32_t _version;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "macro-condition-process.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "platform-funcs.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
@@ -19,25 +18,43 @@ bool MacroConditionProcess::CheckCondition()
|
||||
QStringList runningProcesses;
|
||||
QString proc = QString::fromStdString(_process);
|
||||
GetProcessList(runningProcesses);
|
||||
std::string foregroundProcessName;
|
||||
GetForegroundProcessName(foregroundProcessName);
|
||||
|
||||
bool equals = runningProcesses.contains(proc);
|
||||
bool matches = runningProcesses.indexOf(QRegularExpression(proc)) != -1;
|
||||
bool focus = !_focus || IsInFocus(proc);
|
||||
SetVariableValue(foregroundProcessName);
|
||||
|
||||
if (IsReferencedInVars()) {
|
||||
std::string name;
|
||||
GetForegroundProcessName(name);
|
||||
SetVariableValue(name);
|
||||
if (!_regex.Enabled()) {
|
||||
if (runningProcesses.contains(proc) &&
|
||||
(!_checkFocus || IsInFocus(proc))) {
|
||||
SetTempVarValue("name", proc.toStdString());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return (equals || matches) && focus;
|
||||
auto matchIndex = runningProcesses.indexOf(QRegularExpression(proc));
|
||||
if (matchIndex == -1) {
|
||||
return false;
|
||||
}
|
||||
if (!_checkFocus) {
|
||||
SetTempVarValue("name",
|
||||
runningProcesses.at(matchIndex).toStdString());
|
||||
return true;
|
||||
}
|
||||
if (!IsInFocus(proc)) {
|
||||
return false;
|
||||
}
|
||||
SetTempVarValue("name", foregroundProcessName);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroConditionProcess::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
obs_data_set_string(obj, "process", _process.c_str());
|
||||
obs_data_set_bool(obj, "focus", _focus);
|
||||
obs_data_set_bool(obj, "focus", _checkFocus);
|
||||
_regex.Save(obj);
|
||||
obs_data_set_int(obj, "version", 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -45,7 +62,13 @@ bool MacroConditionProcess::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Load(obj);
|
||||
_process = obs_data_get_string(obj, "process");
|
||||
_focus = obs_data_get_bool(obj, "focus");
|
||||
_checkFocus = obs_data_get_bool(obj, "focus");
|
||||
// Fall back to partial match regex as default for old version
|
||||
if (!obs_data_has_user_value(obj, "version")) {
|
||||
_regex.SetEnabled(true);
|
||||
} else {
|
||||
_regex.Load(obj);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -54,10 +77,18 @@ std::string MacroConditionProcess::GetShortDesc() const
|
||||
return _process;
|
||||
}
|
||||
|
||||
void MacroConditionProcess::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
AddTempvar("name",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.process.name"));
|
||||
}
|
||||
|
||||
MacroConditionProcessEdit::MacroConditionProcessEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionProcess> entryData)
|
||||
: QWidget(parent),
|
||||
_processSelection(new QComboBox()),
|
||||
_regex(new RegexConfigWidget(this)),
|
||||
_focused(new QCheckBox()),
|
||||
_focusProcess(new QLabel()),
|
||||
_focusLayout(new QHBoxLayout())
|
||||
@@ -68,6 +99,8 @@ MacroConditionProcessEdit::MacroConditionProcessEdit(
|
||||
QWidget::connect(_processSelection,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(ProcessChanged(const QString &)));
|
||||
QWidget::connect(_regex, SIGNAL(RegexConfigChanged(RegexConfig)), this,
|
||||
SLOT(RegexChanged(RegexConfig)));
|
||||
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(FocusChanged(int)));
|
||||
QWidget::connect(&_timer, SIGNAL(timeout()), this,
|
||||
@@ -77,6 +110,7 @@ MacroConditionProcessEdit::MacroConditionProcessEdit(
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{processes}}", _processSelection},
|
||||
{"{{regex}}", _regex},
|
||||
{"{{focused}}", _focused},
|
||||
{"{{focusProcess}}", _focusProcess},
|
||||
};
|
||||
@@ -112,6 +146,18 @@ void MacroConditionProcessEdit::ProcessChanged(const QString &text)
|
||||
QString::fromStdString(_entryData->GetShortDesc()));
|
||||
}
|
||||
|
||||
void MacroConditionProcessEdit::RegexChanged(RegexConfig conf)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_regex = conf;
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroConditionProcessEdit::FocusChanged(int state)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
@@ -119,14 +165,15 @@ void MacroConditionProcessEdit::FocusChanged(int state)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_focus = state;
|
||||
_entryData->_checkFocus = state;
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionProcessEdit::UpdateFocusProcess()
|
||||
{
|
||||
_focusProcess->setText(
|
||||
QString::fromStdString(switcher->currentForegroundProcess));
|
||||
std::string name;
|
||||
GetForegroundProcessName(name);
|
||||
_focusProcess->setText(QString::fromStdString(name));
|
||||
}
|
||||
|
||||
void MacroConditionProcessEdit::SetWidgetVisibility()
|
||||
@@ -134,7 +181,7 @@ void MacroConditionProcessEdit::SetWidgetVisibility()
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
SetLayoutVisible(_focusLayout, _entryData->_focus);
|
||||
SetLayoutVisible(_focusLayout, _entryData->_checkFocus);
|
||||
adjustSize();
|
||||
}
|
||||
|
||||
@@ -145,7 +192,8 @@ void MacroConditionProcessEdit::UpdateEntryData()
|
||||
}
|
||||
|
||||
_processSelection->setCurrentText(_entryData->_process.c_str());
|
||||
_focused->setChecked(_entryData->_focus);
|
||||
_regex->SetRegexConfig(_entryData->_regex);
|
||||
_focused->setChecked(_entryData->_checkFocus);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "regex-config.hpp"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
@@ -20,9 +21,12 @@ public:
|
||||
}
|
||||
|
||||
std::string _process;
|
||||
bool _focus = true;
|
||||
bool _checkFocus = true;
|
||||
RegexConfig _regex = RegexConfig::PartialMatchRegexConfig();
|
||||
|
||||
private:
|
||||
void SetupTempVars();
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
@@ -45,22 +49,22 @@ public:
|
||||
|
||||
private slots:
|
||||
void ProcessChanged(const QString &text);
|
||||
void RegexChanged(RegexConfig);
|
||||
void FocusChanged(int state);
|
||||
void UpdateFocusProcess();
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
QComboBox *_processSelection;
|
||||
RegexConfigWidget *_regex;
|
||||
QCheckBox *_focused;
|
||||
QLabel *_focusProcess;
|
||||
QHBoxLayout *_focusLayout;
|
||||
QTimer _timer;
|
||||
std::shared_ptr<MacroConditionProcess> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "macro-condition-recording.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace advss {
|
||||
|
||||
const std::string MacroConditionRecord::id = "recording";
|
||||
@@ -10,45 +12,81 @@ bool MacroConditionRecord::_registered = MacroConditionFactory::Register(
|
||||
{MacroConditionRecord::Create, MacroConditionRecordEdit::Create,
|
||||
"AdvSceneSwitcher.condition.record"});
|
||||
|
||||
const static std::map<RecordState, std::string> recordStates = {
|
||||
{RecordState::STOP, "AdvSceneSwitcher.condition.record.state.stop"},
|
||||
{RecordState::PAUSE, "AdvSceneSwitcher.condition.record.state.pause"},
|
||||
{RecordState::START, "AdvSceneSwitcher.condition.record.state.start"},
|
||||
const static std::map<MacroConditionRecord::Condition, std::string>
|
||||
recordStates = {
|
||||
{MacroConditionRecord::Condition::STOP,
|
||||
"AdvSceneSwitcher.condition.record.state.stop"},
|
||||
{MacroConditionRecord::Condition::PAUSE,
|
||||
"AdvSceneSwitcher.condition.record.state.pause"},
|
||||
{MacroConditionRecord::Condition::START,
|
||||
"AdvSceneSwitcher.condition.record.state.start"},
|
||||
{MacroConditionRecord::Condition::DURATION,
|
||||
"AdvSceneSwitcher.condition.record.state.duration"},
|
||||
};
|
||||
|
||||
static bool SetupRecordingTimer();
|
||||
static bool recordingTimerIsSetup = SetupRecordingTimer();
|
||||
static int currentRecordingDurationInSeconds = 0;
|
||||
|
||||
bool MacroConditionRecord::CheckCondition()
|
||||
{
|
||||
bool stateMatch = false;
|
||||
switch (_recordState) {
|
||||
case RecordState::STOP:
|
||||
stateMatch = !obs_frontend_recording_active();
|
||||
break;
|
||||
case RecordState::PAUSE:
|
||||
stateMatch = obs_frontend_recording_paused();
|
||||
break;
|
||||
case RecordState::START:
|
||||
stateMatch = obs_frontend_recording_active();
|
||||
break;
|
||||
switch (_condition) {
|
||||
case Condition::STOP:
|
||||
return !obs_frontend_recording_active();
|
||||
case Condition::PAUSE:
|
||||
return obs_frontend_recording_paused();
|
||||
case Condition::START:
|
||||
return obs_frontend_recording_active();
|
||||
case Condition::DURATION:
|
||||
SetTempVarValue(
|
||||
"durationSeconds",
|
||||
std::to_string(currentRecordingDurationInSeconds));
|
||||
return currentRecordingDurationInSeconds > _duration.Seconds();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return stateMatch;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacroConditionRecord::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
obs_data_set_int(obj, "state", static_cast<int>(_recordState));
|
||||
obs_data_set_int(obj, "state", static_cast<int>(_condition));
|
||||
_duration.Save(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroConditionRecord::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Load(obj);
|
||||
_recordState = static_cast<RecordState>(obs_data_get_int(obj, "state"));
|
||||
_condition = static_cast<Condition>(obs_data_get_int(obj, "state"));
|
||||
_duration.Load(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MacroConditionRecord::SetCondition(Condition condition)
|
||||
{
|
||||
_condition = condition;
|
||||
SetupTempVars();
|
||||
}
|
||||
|
||||
void MacroConditionRecord::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
switch (_condition) {
|
||||
case Condition::DURATION:
|
||||
AddTempvar(
|
||||
"durationSeconds",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.recording.durationSeconds"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.recording.durationSeconds.description"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void populateStateSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : recordStates) {
|
||||
@@ -58,38 +96,39 @@ static inline void populateStateSelection(QComboBox *list)
|
||||
|
||||
MacroConditionRecordEdit::MacroConditionRecordEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionRecord> entryData)
|
||||
: QWidget(parent)
|
||||
: QWidget(parent),
|
||||
_condition(new QComboBox(this)),
|
||||
_duration(new DurationSelection(this))
|
||||
{
|
||||
_recordState = new QComboBox();
|
||||
populateStateSelection(_condition);
|
||||
|
||||
QWidget::connect(_recordState, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(StateChanged(int)));
|
||||
|
||||
populateStateSelection(_recordState);
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{recordState}}", _recordState},
|
||||
};
|
||||
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ConditionChanged(int)));
|
||||
QWidget::connect(_duration, SIGNAL(DurationChanged(const Duration &)),
|
||||
this, SLOT(DurationChanged(const Duration &)));
|
||||
|
||||
auto layout = new QHBoxLayout;
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.record.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
layout,
|
||||
{{"{{condition}}", _condition},
|
||||
{"{{duration}}", _duration}});
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroConditionRecordEdit::StateChanged(int value)
|
||||
void MacroConditionRecordEdit::ConditionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_recordState = static_cast<RecordState>(value);
|
||||
_entryData->SetCondition(
|
||||
static_cast<MacroConditionRecord::Condition>(value));
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionRecordEdit::UpdateEntryData()
|
||||
@@ -98,8 +137,67 @@ void MacroConditionRecordEdit::UpdateEntryData()
|
||||
return;
|
||||
}
|
||||
|
||||
_recordState->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_recordState));
|
||||
_condition->setCurrentIndex(
|
||||
static_cast<int>(_entryData->GetCondition()));
|
||||
_duration->SetDuration(_entryData->_duration);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionRecordEdit::DurationChanged(const Duration &duration)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_duration = duration;
|
||||
}
|
||||
|
||||
void MacroConditionRecordEdit::SetWidgetVisibility()
|
||||
{
|
||||
_duration->setVisible(_entryData->GetCondition() ==
|
||||
MacroConditionRecord::Condition::DURATION);
|
||||
}
|
||||
|
||||
bool SetupRecordingTimer()
|
||||
{
|
||||
static std::atomic_bool recordingStopped = {true};
|
||||
static std::atomic_bool recordingPaused = {false};
|
||||
static auto handleRecordingEvents = [](enum obs_frontend_event event,
|
||||
void *) {
|
||||
switch (event) {
|
||||
case OBS_FRONTEND_EVENT_RECORDING_STOPPED:
|
||||
recordingStopped = true;
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
|
||||
recordingStopped = false;
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_RECORDING_PAUSED:
|
||||
recordingPaused = true;
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_RECORDING_UNPAUSED:
|
||||
recordingPaused = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
};
|
||||
obs_frontend_add_event_callback(handleRecordingEvents, nullptr);
|
||||
std::thread thread([]() {
|
||||
while (true) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
if (recordingStopped) {
|
||||
currentRecordingDurationInSeconds = 0;
|
||||
continue;
|
||||
}
|
||||
if (recordingPaused) {
|
||||
continue;
|
||||
}
|
||||
++currentRecordingDurationInSeconds;
|
||||
}
|
||||
});
|
||||
thread.detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -6,12 +6,6 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
enum class RecordState {
|
||||
STOP,
|
||||
PAUSE,
|
||||
START,
|
||||
};
|
||||
|
||||
class MacroConditionRecord : public MacroCondition {
|
||||
public:
|
||||
MacroConditionRecord(Macro *m) : MacroCondition(m) {}
|
||||
@@ -24,9 +18,21 @@ public:
|
||||
return std::make_shared<MacroConditionRecord>(m);
|
||||
}
|
||||
|
||||
RecordState _recordState = RecordState::STOP;
|
||||
enum class Condition {
|
||||
STOP,
|
||||
PAUSE,
|
||||
START,
|
||||
DURATION,
|
||||
};
|
||||
|
||||
void SetCondition(Condition);
|
||||
Condition GetCondition() const { return _condition; }
|
||||
Duration _duration;
|
||||
|
||||
private:
|
||||
void SetupTempVars();
|
||||
|
||||
Condition _condition = Condition::STOP;
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
@@ -48,13 +54,15 @@ public:
|
||||
}
|
||||
|
||||
private slots:
|
||||
void StateChanged(int value);
|
||||
|
||||
protected:
|
||||
QComboBox *_recordState;
|
||||
std::shared_ptr<MacroConditionRecord> _entryData;
|
||||
void ConditionChanged(int value);
|
||||
void DurationChanged(const Duration &);
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
QComboBox *_condition;
|
||||
DurationSelection *_duration;
|
||||
std::shared_ptr<MacroConditionRecord> _entryData;
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "macro-condition-replay-buffer.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -11,35 +10,63 @@ bool MacroConditionReplayBuffer::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionReplayBufferEdit::Create,
|
||||
"AdvSceneSwitcher.condition.replay"});
|
||||
|
||||
const static std::map<ReplayBufferState, std::string> ReplayBufferStates = {
|
||||
{ReplayBufferState::STOP,
|
||||
"AdvSceneSwitcher.condition.replay.state.stopped"},
|
||||
{ReplayBufferState::START,
|
||||
"AdvSceneSwitcher.condition.replay.state.started"},
|
||||
{ReplayBufferState::SAVE,
|
||||
"AdvSceneSwitcher.condition.replay.state.saved"},
|
||||
const static std::map<MacroConditionReplayBuffer::Condition, std::string>
|
||||
conditions = {
|
||||
{MacroConditionReplayBuffer::Condition::STOP,
|
||||
"AdvSceneSwitcher.condition.replay.state.stopped"},
|
||||
{MacroConditionReplayBuffer::Condition::START,
|
||||
"AdvSceneSwitcher.condition.replay.state.started"},
|
||||
{MacroConditionReplayBuffer::Condition::SAVE,
|
||||
"AdvSceneSwitcher.condition.replay.state.saved"},
|
||||
};
|
||||
|
||||
static bool replayBufferSaved = false;
|
||||
|
||||
static std::chrono::high_resolution_clock::time_point replayBufferSaveTime{};
|
||||
static bool setupReplayBufferEventHandler();
|
||||
static bool replayBufferEventHandlerIsSetup = setupReplayBufferEventHandler();
|
||||
|
||||
static bool setupReplayBufferEventHandler()
|
||||
{
|
||||
static auto handleReplayBufferEvent = [](enum obs_frontend_event event,
|
||||
void *) {
|
||||
switch (event) {
|
||||
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED:
|
||||
replayBufferSaveTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
};
|
||||
obs_frontend_add_event_callback(handleReplayBufferEvent, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroConditionReplayBuffer::ReplayBufferWasSaved()
|
||||
{
|
||||
bool timersAreInitialized =
|
||||
_saveTime.time_since_epoch().count() != 0 &&
|
||||
replayBufferSaveTime.time_since_epoch().count() != 0;
|
||||
bool newSaveOccurred = timersAreInitialized &&
|
||||
_saveTime != replayBufferSaveTime;
|
||||
_saveTime = replayBufferSaveTime;
|
||||
return newSaveOccurred;
|
||||
}
|
||||
|
||||
bool MacroConditionReplayBuffer::CheckCondition()
|
||||
{
|
||||
bool stateMatch = false;
|
||||
switch (_state) {
|
||||
case ReplayBufferState::STOP:
|
||||
stateMatch = !obs_frontend_replay_buffer_active();
|
||||
break;
|
||||
case ReplayBufferState::START:
|
||||
stateMatch = obs_frontend_replay_buffer_active();
|
||||
break;
|
||||
case ReplayBufferState::SAVE:
|
||||
if (switcher->replayBufferSaved) {
|
||||
stateMatch = true;
|
||||
switcher->replayBufferSaved = false;
|
||||
}
|
||||
break;
|
||||
case Condition::STOP:
|
||||
return !obs_frontend_replay_buffer_active();
|
||||
case Condition::START:
|
||||
return obs_frontend_replay_buffer_active();
|
||||
case Condition::SAVE:
|
||||
return ReplayBufferWasSaved();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return stateMatch;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacroConditionReplayBuffer::Save(obs_data_t *obj) const
|
||||
@@ -52,37 +79,30 @@ bool MacroConditionReplayBuffer::Save(obs_data_t *obj) const
|
||||
bool MacroConditionReplayBuffer::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Load(obj);
|
||||
_state = static_cast<ReplayBufferState>(obs_data_get_int(obj, "state"));
|
||||
_state = static_cast<Condition>(obs_data_get_int(obj, "state"));
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void populateStateSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : ReplayBufferStates) {
|
||||
for (const auto &entry : conditions) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
MacroConditionReplayBufferEdit::MacroConditionReplayBufferEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionReplayBuffer> entryData)
|
||||
: QWidget(parent)
|
||||
: QWidget(parent), _state(new QComboBox())
|
||||
{
|
||||
_state = new QComboBox();
|
||||
|
||||
QWidget::connect(_state, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(StateChanged(int)));
|
||||
|
||||
populateStateSelection(_state);
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{state}}", _state},
|
||||
};
|
||||
|
||||
auto layout = new QHBoxLayout;
|
||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.condition.replay.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
setLayout(mainLayout);
|
||||
layout, {{"{{state}}", _state}});
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
@@ -96,7 +116,8 @@ void MacroConditionReplayBufferEdit::StateChanged(int value)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_state = static_cast<ReplayBufferState>(value);
|
||||
_entryData->_state =
|
||||
static_cast<MacroConditionReplayBuffer::Condition>(value);
|
||||
}
|
||||
|
||||
void MacroConditionReplayBufferEdit::UpdateEntryData()
|
||||
|
||||
@@ -6,12 +6,6 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
enum class ReplayBufferState {
|
||||
STOP,
|
||||
START,
|
||||
SAVE,
|
||||
};
|
||||
|
||||
class MacroConditionReplayBuffer : public MacroCondition {
|
||||
public:
|
||||
MacroConditionReplayBuffer(Macro *m) : MacroCondition(m) {}
|
||||
@@ -24,9 +18,18 @@ public:
|
||||
return std::make_shared<MacroConditionReplayBuffer>(m);
|
||||
}
|
||||
|
||||
ReplayBufferState _state = ReplayBufferState::STOP;
|
||||
enum class Condition {
|
||||
STOP,
|
||||
START,
|
||||
SAVE,
|
||||
};
|
||||
|
||||
Condition _state = Condition::STOP;
|
||||
|
||||
private:
|
||||
bool ReplayBufferWasSaved();
|
||||
|
||||
std::chrono::high_resolution_clock::time_point _saveTime = {};
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QDesktopServices>
|
||||
|
||||
namespace advss {
|
||||
|
||||
@@ -28,17 +27,18 @@ bool MacroConditionRun::CheckCondition()
|
||||
|
||||
bool ret = false;
|
||||
|
||||
switch (_procStatus) {
|
||||
case MacroConditionRun::Status::FAILED_TO_START:
|
||||
switch (_error) {
|
||||
case ProcessConfig::ProcStartError::FAILED_TO_START:
|
||||
SetVariableValue("Failed to start process");
|
||||
ret = false;
|
||||
break;
|
||||
case MacroConditionRun::Status::TIMEOUT:
|
||||
case ProcessConfig::ProcStartError::TIMEOUT:
|
||||
SetVariableValue("Timeout while running process");
|
||||
ret = false;
|
||||
break;
|
||||
case MacroConditionRun::Status::OK:
|
||||
ret = _checkExitCode ? _exitCode == _procExitCode : true;
|
||||
case ProcessConfig::ProcStartError::CRASH:
|
||||
SetVariableValue("Timeout while running process");
|
||||
break;
|
||||
case ProcessConfig::ProcStartError::NONE:
|
||||
ret = _checkExitCode ? _exitCodeToCheck == _procExitCode : true;
|
||||
SetVariableValue(std::to_string(_procExitCode));
|
||||
break;
|
||||
default:
|
||||
@@ -56,42 +56,14 @@ bool MacroConditionRun::CheckCondition()
|
||||
|
||||
void MacroConditionRun::RunProcess()
|
||||
{
|
||||
QProcess process;
|
||||
process.setWorkingDirectory(
|
||||
QString::fromStdString(_procConfig.WorkingDir()));
|
||||
process.start(QString::fromStdString(_procConfig.Path()),
|
||||
_procConfig.Args());
|
||||
int timeout = _timeout.Milliseconds();
|
||||
auto result = _procConfig.StartProcessAndWait(_timeout.Milliseconds());
|
||||
|
||||
vblog(LOG_INFO, "run \"%s\" with a timeout of %d ms",
|
||||
_procConfig.Path().c_str(), timeout);
|
||||
|
||||
bool procFinishedInTime = process.waitForFinished(timeout);
|
||||
|
||||
if (!procFinishedInTime) {
|
||||
if (process.error() == QProcess::FailedToStart) {
|
||||
vblog(LOG_INFO, "failed to start \"%s\"!",
|
||||
_procConfig.Path().c_str());
|
||||
_procStatus = Status::FAILED_TO_START;
|
||||
} else {
|
||||
vblog(LOG_INFO,
|
||||
"timeout while running \"%s\"\nAttempting to kill process!",
|
||||
_procConfig.Path().c_str());
|
||||
process.kill();
|
||||
process.waitForFinished();
|
||||
_procStatus = Status::TIMEOUT;
|
||||
}
|
||||
if (std::holds_alternative<ProcessConfig::ProcStartError>(result)) {
|
||||
_error = std::get<ProcessConfig::ProcStartError>(result);
|
||||
} else {
|
||||
_error = ProcessConfig::ProcStartError::NONE;
|
||||
_procExitCode = std::get<int>(result);
|
||||
}
|
||||
|
||||
bool validExitCode = process.exitStatus() == QProcess::NormalExit;
|
||||
|
||||
if ((_checkExitCode && !validExitCode) || !procFinishedInTime) {
|
||||
_threadDone = true;
|
||||
return;
|
||||
}
|
||||
|
||||
_procExitCode = process.exitCode();
|
||||
_procStatus = Status::OK;
|
||||
_threadDone = true;
|
||||
}
|
||||
|
||||
@@ -100,7 +72,7 @@ bool MacroConditionRun::Save(obs_data_t *obj) const
|
||||
MacroCondition::Save(obj);
|
||||
_procConfig.Save(obj);
|
||||
obs_data_set_bool(obj, "checkExitCode", _checkExitCode);
|
||||
obs_data_set_int(obj, "exitCode", _exitCode);
|
||||
obs_data_set_int(obj, "exitCode", _exitCodeToCheck);
|
||||
_timeout.Save(obj, "timeout");
|
||||
return true;
|
||||
}
|
||||
@@ -110,7 +82,7 @@ bool MacroConditionRun::Load(obs_data_t *obj)
|
||||
MacroCondition::Load(obj);
|
||||
_procConfig.Load(obj);
|
||||
_checkExitCode = obs_data_get_bool(obj, "checkExitCode");
|
||||
_exitCode = obs_data_get_int(obj, "exitCode");
|
||||
_exitCodeToCheck = obs_data_get_int(obj, "exitCode");
|
||||
_timeout.Load(obj, "timeout");
|
||||
return true;
|
||||
}
|
||||
@@ -174,7 +146,7 @@ void MacroConditionRunEdit::UpdateEntryData()
|
||||
_procConfig->SetProcessConfig(_entryData->_procConfig);
|
||||
_timeout->SetDuration(_entryData->_timeout);
|
||||
_checkExitCode->setChecked(_entryData->_checkExitCode);
|
||||
_exitCode->setValue(_entryData->_exitCode);
|
||||
_exitCode->setValue(_entryData->_exitCodeToCheck);
|
||||
}
|
||||
|
||||
void MacroConditionRunEdit::TimeoutChanged(const Duration &dur)
|
||||
@@ -204,7 +176,7 @@ void MacroConditionRunEdit::ExitCodeChanged(int exitCode)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_exitCode = exitCode;
|
||||
_entryData->_exitCodeToCheck = exitCode;
|
||||
}
|
||||
|
||||
void MacroConditionRunEdit::ProcessConfigChanged(const ProcessConfig &conf)
|
||||
|
||||
@@ -25,22 +25,15 @@ public:
|
||||
|
||||
ProcessConfig _procConfig;
|
||||
bool _checkExitCode = true;
|
||||
int _exitCode = 0;
|
||||
int _exitCodeToCheck = 0;
|
||||
Duration _timeout = Duration(0.1);
|
||||
|
||||
private:
|
||||
enum class Status {
|
||||
NONE,
|
||||
FAILED_TO_START,
|
||||
TIMEOUT,
|
||||
OK,
|
||||
};
|
||||
|
||||
void RunProcess();
|
||||
|
||||
std::thread _thread;
|
||||
std::atomic_bool _threadDone{true};
|
||||
Status _procStatus = Status::NONE;
|
||||
ProcessConfig::ProcStartError _error =
|
||||
ProcessConfig::ProcStartError::NONE;
|
||||
int _procExitCode = 0;
|
||||
|
||||
static bool _registered;
|
||||
|
||||
@@ -12,19 +12,79 @@ bool MacroConditionSceneTransform::_registered =
|
||||
MacroConditionSceneTransformEdit::Create,
|
||||
"AdvSceneSwitcher.condition.sceneTransform"});
|
||||
|
||||
bool MacroConditionSceneTransform::CheckCondition()
|
||||
const static std::map<MacroConditionSceneTransform::CondType, std::string>
|
||||
conditionTypes = {
|
||||
{MacroConditionSceneTransform::CondType::MATCHES,
|
||||
"AdvSceneSwitcher.condition.sceneTransform.entry.type.matches"},
|
||||
{MacroConditionSceneTransform::CondType::CHANGED,
|
||||
"AdvSceneSwitcher.condition.sceneTransform.entry.type.changed"},
|
||||
};
|
||||
|
||||
static bool doesTransformOfAnySceneItemMatch(
|
||||
const std::vector<OBSSceneItem> &items, const std::string &jsonCompare,
|
||||
const RegexConfig ®ex, std::string &newVariable)
|
||||
{
|
||||
bool ret = false;
|
||||
auto items = _source.GetSceneItems(_scene);
|
||||
|
||||
std::string json;
|
||||
for (const auto &item : items) {
|
||||
json = GetSceneItemTransform(item);
|
||||
if (MatchJson(json, _settings, _regex)) {
|
||||
if (MatchJson(json, jsonCompare, regex)) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
SetVariableValue(json);
|
||||
newVariable = json;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
didTransformOfAnySceneItemChange(const std::vector<OBSSceneItem> &items,
|
||||
std::vector<std::string> &previousTransform,
|
||||
std::string &newVariable)
|
||||
{
|
||||
bool ret = false;
|
||||
std::string json;
|
||||
RegexConfig regex;
|
||||
auto numItems = items.size();
|
||||
if (previousTransform.size() < numItems) {
|
||||
ret = true;
|
||||
previousTransform.resize(numItems);
|
||||
}
|
||||
for (size_t idx = 0; idx < numItems; ++idx) {
|
||||
auto const &item = items[idx];
|
||||
json = GetSceneItemTransform(item);
|
||||
if (!MatchJson(json, previousTransform[idx], regex)) {
|
||||
ret = true;
|
||||
previousTransform[idx] = json;
|
||||
}
|
||||
}
|
||||
newVariable = json;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool MacroConditionSceneTransform::CheckCondition()
|
||||
{
|
||||
auto items = _source.GetSceneItems(_scene);
|
||||
if (items.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string newVariable = "";
|
||||
bool ret = false;
|
||||
switch (_type) {
|
||||
case CondType::MATCHES:
|
||||
ret = doesTransformOfAnySceneItemMatch(items, _settings, _regex,
|
||||
newVariable);
|
||||
break;
|
||||
case CondType::CHANGED:
|
||||
ret = didTransformOfAnySceneItemChange(
|
||||
items, _previousTransform, newVariable);
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
SetVariableValue(newVariable);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -35,6 +95,7 @@ bool MacroConditionSceneTransform::Save(obs_data_t *obj) const
|
||||
_source.Save(obj);
|
||||
_settings.Save(obj, "settings");
|
||||
_regex.Save(obj);
|
||||
obs_data_set_int(obj, "type", static_cast<int>(_type));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -52,6 +113,7 @@ bool MacroConditionSceneTransform::Load(obs_data_t *obj)
|
||||
_source.Load(obj);
|
||||
_settings.Load(obj, "settings");
|
||||
_regex.Load(obj);
|
||||
_type = static_cast<CondType>(obs_data_get_int(obj, "type"));
|
||||
// TOOD: remove in future version
|
||||
if (obs_data_has_user_value(obj, "regex")) {
|
||||
_regex.CreateBackwardsCompatibleRegex(
|
||||
@@ -69,6 +131,13 @@ std::string MacroConditionSceneTransform::GetShortDesc() const
|
||||
return _scene.ToString() + " - " + _source.ToString();
|
||||
}
|
||||
|
||||
static inline void populateTypesSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &entry : conditionTypes) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
MacroConditionSceneTransformEdit::MacroConditionSceneTransformEdit(
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroConditionSceneTransform> entryData)
|
||||
@@ -76,11 +145,14 @@ MacroConditionSceneTransformEdit::MacroConditionSceneTransformEdit(
|
||||
_scenes(new SceneSelectionWidget(window(), true, false, false, true)),
|
||||
_sources(new SceneItemSelectionWidget(
|
||||
parent, true, SceneItemSelectionWidget::Placeholder::ANY)),
|
||||
_types(new QComboBox()),
|
||||
_getSettings(new QPushButton(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.sceneTransform.getTransform"))),
|
||||
_settings(new VariableTextEdit(this)),
|
||||
_regex(new RegexConfigWidget(parent))
|
||||
{
|
||||
populateTypesSelection(_types);
|
||||
|
||||
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
|
||||
this, SLOT(SceneChanged(const SceneSelection &)));
|
||||
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
|
||||
@@ -88,6 +160,8 @@ MacroConditionSceneTransformEdit::MacroConditionSceneTransformEdit(
|
||||
QWidget::connect(_sources,
|
||||
SIGNAL(SceneItemChanged(const SceneItemSelection &)),
|
||||
this, SLOT(SourceChanged(const SceneItemSelection &)));
|
||||
QWidget::connect(_types, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(TypeChanged(int)));
|
||||
QWidget::connect(_getSettings, SIGNAL(clicked()), this,
|
||||
SLOT(GetSettingsClicked()));
|
||||
QWidget::connect(_settings, SIGNAL(textChanged()), this,
|
||||
@@ -96,8 +170,11 @@ MacroConditionSceneTransformEdit::MacroConditionSceneTransformEdit(
|
||||
SLOT(RegexChanged(RegexConfig)));
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{scenes}}", _scenes}, {"{{sources}}", _sources},
|
||||
{"{{settings}}", _settings}, {"{{getSettings}}", _getSettings},
|
||||
{"{{scenes}}", _scenes},
|
||||
{"{{sources}}", _sources},
|
||||
{"{{types}}", _types},
|
||||
{"{{settings}}", _settings},
|
||||
{"{{getSettings}}", _getSettings},
|
||||
{"{{regex}}", _regex},
|
||||
};
|
||||
|
||||
@@ -136,11 +213,10 @@ void MacroConditionSceneTransformEdit::UpdateEntryData()
|
||||
|
||||
_scenes->SetScene(_entryData->_scene);
|
||||
_sources->SetSceneItem(_entryData->_source);
|
||||
_types->setCurrentIndex(static_cast<int>(_entryData->_type));
|
||||
_regex->SetRegexConfig(_entryData->_regex);
|
||||
_settings->setPlainText(_entryData->_settings);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionSceneTransformEdit::SceneChanged(const SceneSelection &s)
|
||||
@@ -168,6 +244,18 @@ void MacroConditionSceneTransformEdit::SourceChanged(
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroConditionSceneTransformEdit::TypeChanged(int index)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_type =
|
||||
static_cast<MacroConditionSceneTransform::CondType>(index);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionSceneTransformEdit::GetSettingsClicked()
|
||||
{
|
||||
|
||||
@@ -213,4 +301,16 @@ void MacroConditionSceneTransformEdit::RegexChanged(RegexConfig conf)
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroConditionSceneTransformEdit::SetWidgetVisibility()
|
||||
{
|
||||
const bool showSettingsAndRegex =
|
||||
_entryData->_type ==
|
||||
MacroConditionSceneTransform::CondType::MATCHES;
|
||||
_settings->setVisible(showSettingsAndRegex);
|
||||
_getSettings->setVisible(showSettingsAndRegex);
|
||||
_regex->setVisible(showSettingsAndRegex);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -23,12 +23,20 @@ public:
|
||||
return std::make_shared<MacroConditionSceneTransform>(m);
|
||||
}
|
||||
|
||||
enum class CondType {
|
||||
MATCHES,
|
||||
CHANGED,
|
||||
};
|
||||
|
||||
SceneSelection _scene;
|
||||
SceneItemSelection _source;
|
||||
CondType _type = CondType::MATCHES;
|
||||
RegexConfig _regex;
|
||||
StringVariable _settings = "";
|
||||
|
||||
private:
|
||||
std::vector<std::string> _previousTransform;
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
@@ -54,6 +62,7 @@ public:
|
||||
private slots:
|
||||
void SceneChanged(const SceneSelection &);
|
||||
void SourceChanged(const SceneItemSelection &);
|
||||
void TypeChanged(int type);
|
||||
void GetSettingsClicked();
|
||||
void SettingsChanged();
|
||||
void RegexChanged(RegexConfig);
|
||||
@@ -63,6 +72,7 @@ signals:
|
||||
protected:
|
||||
SceneSelectionWidget *_scenes;
|
||||
SceneItemSelectionWidget *_sources;
|
||||
QComboBox *_types;
|
||||
QPushButton *_getSettings;
|
||||
VariableTextEdit *_settings;
|
||||
RegexConfigWidget *_regex;
|
||||
@@ -70,6 +80,7 @@ protected:
|
||||
std::shared_ptr<MacroConditionSceneTransform> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "macro-condition-scene.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -53,34 +53,35 @@ static OBSWeakSource getCurrentSceneHelper(bool useTransitionTargetScene)
|
||||
obs_source_release(current);
|
||||
return weak;
|
||||
}
|
||||
return switcher->currentScene;
|
||||
return GetCurrentScene();
|
||||
}
|
||||
|
||||
static OBSWeakSource getPreviousSceneHelper(bool useTransitionTargetScene)
|
||||
{
|
||||
if (switcher->AnySceneTransitionStarted() && useTransitionTargetScene) {
|
||||
return switcher->currentScene;
|
||||
if (AnySceneTransitionStarted() && useTransitionTargetScene) {
|
||||
return GetCurrentScene();
|
||||
}
|
||||
return switcher->previousScene;
|
||||
return GetPreviousScene();
|
||||
}
|
||||
|
||||
bool MacroConditionScene::CheckCondition()
|
||||
{
|
||||
bool sceneChanged = _lastSceneChangeTime !=
|
||||
switcher->lastSceneChangeTime;
|
||||
bool sceneChanged = _lastSceneChangeTime != GetLastSceneChangeTime();
|
||||
if (sceneChanged) {
|
||||
_lastSceneChangeTime = switcher->lastSceneChangeTime;
|
||||
_lastSceneChangeTime = GetLastSceneChangeTime();
|
||||
}
|
||||
|
||||
switch (_type) {
|
||||
case Type::CURRENT: {
|
||||
auto scene = getCurrentSceneHelper(_useTransitionTargetScene);
|
||||
SetVariableValue(GetWeakSourceName(scene));
|
||||
SetTempVarValue("current", GetWeakSourceName(scene));
|
||||
return scene == _scene.GetScene(false);
|
||||
}
|
||||
case Type::PREVIOUS: {
|
||||
auto scene = getPreviousSceneHelper(_useTransitionTargetScene);
|
||||
SetVariableValue(GetWeakSourceName(scene));
|
||||
SetTempVarValue("previous", GetWeakSourceName(scene));
|
||||
return scene == _scene.GetScene(false);
|
||||
}
|
||||
case Type::PREVIEW: {
|
||||
@@ -89,22 +90,29 @@ bool MacroConditionScene::CheckCondition()
|
||||
OBSWeakSourceAutoRelease scene =
|
||||
obs_source_get_weak_source(source);
|
||||
SetVariableValue(GetWeakSourceName(scene));
|
||||
SetTempVarValue("preview", GetWeakSourceName(scene));
|
||||
return scene == _scene.GetScene(false);
|
||||
}
|
||||
case Type::CHANGED:
|
||||
SetVariableValue(GetWeakSourceName(switcher->currentScene));
|
||||
SetVariableValue(GetWeakSourceName(GetCurrentScene()));
|
||||
SetTempVarValue("current",
|
||||
GetWeakSourceName(GetCurrentScene()));
|
||||
return sceneChanged;
|
||||
case Type::NOT_CHANGED:
|
||||
SetVariableValue(GetWeakSourceName(switcher->currentScene));
|
||||
SetVariableValue(GetWeakSourceName(GetCurrentScene()));
|
||||
SetTempVarValue("current",
|
||||
GetWeakSourceName(GetCurrentScene()));
|
||||
return !sceneChanged;
|
||||
case Type::CURRENT_PATTERN: {
|
||||
auto scene = getCurrentSceneHelper(_useTransitionTargetScene);
|
||||
SetVariableValue(GetWeakSourceName(scene));
|
||||
SetTempVarValue("current", GetWeakSourceName(scene));
|
||||
return sceneNameMatchesRegex(scene, _pattern);
|
||||
}
|
||||
case Type::PREVIOUS_PATTERN: {
|
||||
auto scene = getPreviousSceneHelper(_useTransitionTargetScene);
|
||||
SetVariableValue(GetWeakSourceName(scene));
|
||||
SetTempVarValue("previous", GetWeakSourceName(scene));
|
||||
return sceneNameMatchesRegex(scene, _pattern);
|
||||
}
|
||||
case Type::PREVIEW_PATTERN: {
|
||||
@@ -113,6 +121,7 @@ bool MacroConditionScene::CheckCondition()
|
||||
OBSWeakSourceAutoRelease scene =
|
||||
obs_source_get_weak_source(source);
|
||||
SetVariableValue(GetWeakSourceName(scene));
|
||||
SetTempVarValue("preview", GetWeakSourceName(scene));
|
||||
return sceneNameMatchesRegex(scene.Get(), _pattern);
|
||||
}
|
||||
}
|
||||
@@ -179,8 +188,8 @@ bool MacroConditionScene::Load(obs_data_t *obj)
|
||||
break;
|
||||
default:
|
||||
blog(LOG_WARNING,
|
||||
"failed to convert scene condition type (%d) for macro %s",
|
||||
oldType, GetMacro()->Name().c_str());
|
||||
"failed to convert scene condition type (%d)",
|
||||
oldType);
|
||||
_type = Type::CURRENT;
|
||||
break;
|
||||
}
|
||||
@@ -196,6 +205,41 @@ std::string MacroConditionScene::GetShortDesc() const
|
||||
return "";
|
||||
}
|
||||
|
||||
void MacroConditionScene::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
switch (_type) {
|
||||
case Type::CURRENT:
|
||||
case Type::CHANGED:
|
||||
case Type::NOT_CHANGED:
|
||||
case Type::CURRENT_PATTERN:
|
||||
AddTempvar("current",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.scene.current"));
|
||||
break;
|
||||
case Type::PREVIOUS:
|
||||
case Type::PREVIOUS_PATTERN:
|
||||
AddTempvar("previous",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.scene.previous"));
|
||||
break;
|
||||
case Type::PREVIEW:
|
||||
case Type::PREVIEW_PATTERN:
|
||||
AddTempvar("preview",
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.scene.preview"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MacroConditionScene::SetType(const Type &type)
|
||||
{
|
||||
_type = type;
|
||||
SetupTempVars();
|
||||
}
|
||||
|
||||
static inline void populateTypeSelection(QComboBox *list)
|
||||
{
|
||||
for (const auto &[id, name] : sceneTypes) {
|
||||
@@ -268,8 +312,8 @@ void MacroConditionSceneEdit::TypeChanged(int index)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_type = static_cast<MacroConditionScene::Type>(
|
||||
_sceneType->itemData(index).toInt());
|
||||
_entryData->SetType(static_cast<MacroConditionScene::Type>(
|
||||
_sceneType->itemData(index).toInt()));
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -296,31 +340,33 @@ void MacroConditionSceneEdit::UseTransitionTargetSceneChanged(int state)
|
||||
void MacroConditionSceneEdit::SetWidgetVisibility()
|
||||
{
|
||||
_scenes->setVisible(
|
||||
_entryData->_type == MacroConditionScene::Type::CURRENT ||
|
||||
_entryData->_type == MacroConditionScene::Type::PREVIOUS ||
|
||||
_entryData->_type == MacroConditionScene::Type::PREVIEW);
|
||||
_entryData->GetType() == MacroConditionScene::Type::CURRENT ||
|
||||
_entryData->GetType() == MacroConditionScene::Type::PREVIOUS ||
|
||||
_entryData->GetType() == MacroConditionScene::Type::PREVIEW);
|
||||
_useTransitionTargetScene->setVisible(
|
||||
_entryData->_type == MacroConditionScene::Type::CURRENT ||
|
||||
_entryData->_type == MacroConditionScene::Type::PREVIOUS ||
|
||||
_entryData->_type ==
|
||||
_entryData->GetType() == MacroConditionScene::Type::CURRENT ||
|
||||
_entryData->GetType() == MacroConditionScene::Type::PREVIOUS ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionScene::Type::CURRENT_PATTERN ||
|
||||
_entryData->_type ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionScene::Type::PREVIOUS_PATTERN);
|
||||
_pattern->setVisible(
|
||||
_entryData->_type ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionScene::Type::CURRENT_PATTERN ||
|
||||
_entryData->_type ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionScene::Type::PREVIOUS_PATTERN ||
|
||||
_entryData->_type ==
|
||||
_entryData->GetType() ==
|
||||
MacroConditionScene::Type::PREVIEW_PATTERN);
|
||||
|
||||
if (_entryData->_type == MacroConditionScene::Type::PREVIOUS ||
|
||||
_entryData->_type == MacroConditionScene::Type::PREVIOUS_PATTERN) {
|
||||
if (_entryData->GetType() == MacroConditionScene::Type::PREVIOUS ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionScene::Type::PREVIOUS_PATTERN) {
|
||||
_useTransitionTargetScene->setText(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour"));
|
||||
}
|
||||
if (_entryData->_type == MacroConditionScene::Type::CURRENT ||
|
||||
_entryData->_type == MacroConditionScene::Type::CURRENT_PATTERN) {
|
||||
if (_entryData->GetType() == MacroConditionScene::Type::CURRENT ||
|
||||
_entryData->GetType() ==
|
||||
MacroConditionScene::Type::CURRENT_PATTERN) {
|
||||
_useTransitionTargetScene->setText(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour"));
|
||||
}
|
||||
@@ -336,7 +382,7 @@ void MacroConditionSceneEdit::UpdateEntryData()
|
||||
|
||||
_scenes->SetScene(_entryData->_scene);
|
||||
_sceneType->setCurrentIndex(
|
||||
_sceneType->findData(static_cast<int>(_entryData->_type)));
|
||||
_sceneType->findData(static_cast<int>(_entryData->GetType())));
|
||||
_pattern->setText(QString::fromStdString(_entryData->_pattern));
|
||||
_useTransitionTargetScene->setChecked(
|
||||
_entryData->_useTransitionTargetScene);
|
||||
|
||||
@@ -32,9 +32,10 @@ public:
|
||||
PREVIOUS_PATTERN = 70,
|
||||
PREVIEW_PATTERN = 80,
|
||||
};
|
||||
void SetType(const Type &);
|
||||
Type GetType() const { return _type; }
|
||||
|
||||
SceneSelection _scene;
|
||||
Type _type = Type::CURRENT;
|
||||
std::string _pattern = ".*Scene.*";
|
||||
// During a transition "current" scene could either stand for the scene
|
||||
// being transitioned to or the scene still being transitioned away
|
||||
@@ -42,6 +43,9 @@ public:
|
||||
bool _useTransitionTargetScene = false;
|
||||
|
||||
private:
|
||||
void SetupTempVars();
|
||||
|
||||
Type _type = Type::CURRENT;
|
||||
std::chrono::high_resolution_clock::time_point _lastSceneChangeTime{};
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "macro-condition-streaming.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -25,6 +24,32 @@ const static std::map<MacroConditionStream::Condition, std::string>
|
||||
"AdvSceneSwitcher.condition.stream.state.keyFrameInterval"},
|
||||
};
|
||||
|
||||
static bool setupStreamingEventHandler();
|
||||
static bool steamingEventHandlerIsSetup = setupStreamingEventHandler();
|
||||
static std::chrono::high_resolution_clock::time_point streamStartTime{};
|
||||
static std::chrono::high_resolution_clock::time_point streamStopTime{};
|
||||
|
||||
bool setupStreamingEventHandler()
|
||||
{
|
||||
static auto handleStreamingEvents = [](enum obs_frontend_event event,
|
||||
void *) {
|
||||
switch (event) {
|
||||
case OBS_FRONTEND_EVENT_STREAMING_STARTING:
|
||||
streamStartTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_STREAMING_STOPPING:
|
||||
streamStopTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
};
|
||||
obs_frontend_add_event_callback(handleStreamingEvents, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
int MacroConditionStream::GetKeyFrameInterval()
|
||||
{
|
||||
const auto configPath = GetPathInProfileDir("streamEncoder.json");
|
||||
@@ -42,10 +67,8 @@ bool MacroConditionStream::CheckCondition()
|
||||
{
|
||||
bool match = false;
|
||||
|
||||
bool streamStarting = switcher->lastStreamStartingTime !=
|
||||
_lastStreamStartingTime;
|
||||
bool streamStopping = switcher->lastStreamStoppingTime !=
|
||||
_lastStreamStoppingTime;
|
||||
bool streamStarting = streamStartTime != _lastStreamStartingTime;
|
||||
bool streamStopping = streamStopTime != _lastStreamStoppingTime;
|
||||
|
||||
switch (_condition) {
|
||||
case Condition::STOP:
|
||||
@@ -68,10 +91,10 @@ bool MacroConditionStream::CheckCondition()
|
||||
}
|
||||
|
||||
if (streamStarting) {
|
||||
_lastStreamStartingTime = switcher->lastStreamStartingTime;
|
||||
_lastStreamStartingTime = streamStartTime;
|
||||
}
|
||||
if (streamStopping) {
|
||||
_lastStreamStoppingTime = switcher->lastStreamStoppingTime;
|
||||
_lastStreamStoppingTime = streamStopTime;
|
||||
}
|
||||
return match;
|
||||
}
|
||||
|
||||
368
src/macro-core/macro-condition-tempvar.cpp
Normal file
368
src/macro-core/macro-condition-tempvar.cpp
Normal file
@@ -0,0 +1,368 @@
|
||||
#include "macro-condition-tempvar.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
const std::string MacroConditionTempVar::id = "temp_var";
|
||||
|
||||
bool MacroConditionTempVar::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionTempVar::id,
|
||||
{MacroConditionTempVar::Create, MacroConditionTempVarEdit::Create,
|
||||
"AdvSceneSwitcher.condition.temporaryVariable"});
|
||||
|
||||
const static std::map<MacroConditionTempVar::Condition, std::string>
|
||||
conditionTypes = {
|
||||
{MacroConditionTempVar::Condition::EQUALS,
|
||||
"AdvSceneSwitcher.condition.variable.type.compare"},
|
||||
{MacroConditionTempVar::Condition::IS_EMPTY,
|
||||
"AdvSceneSwitcher.condition.variable.type.empty"},
|
||||
{MacroConditionTempVar::Condition::IS_NUMBER,
|
||||
"AdvSceneSwitcher.condition.variable.type.number"},
|
||||
{MacroConditionTempVar::Condition::LESS_THAN,
|
||||
"AdvSceneSwitcher.condition.variable.type.lessThan"},
|
||||
{MacroConditionTempVar::Condition::GREATER_THAN,
|
||||
"AdvSceneSwitcher.condition.variable.type.greaterThan"},
|
||||
{MacroConditionTempVar::Condition::VALUE_CHANGED,
|
||||
"AdvSceneSwitcher.condition.variable.type.valueChanged"},
|
||||
{MacroConditionTempVar::Condition::EQUALS_VARIABLE,
|
||||
"AdvSceneSwitcher.condition.variable.type.equalsVariable"},
|
||||
{MacroConditionTempVar::Condition::LESS_THAN_VARIABLE,
|
||||
"AdvSceneSwitcher.condition.variable.type.lessThanVariable"},
|
||||
{MacroConditionTempVar::Condition::GREATER_THAN_VARIABLE,
|
||||
"AdvSceneSwitcher.condition.variable.type.greaterThanVariable"},
|
||||
};
|
||||
|
||||
static bool isNumber(const TempVariable &var)
|
||||
{
|
||||
auto value = var.Value();
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return GetDouble(*value).has_value();
|
||||
}
|
||||
|
||||
static bool compareNumber(const TempVariable &var, double value, bool less)
|
||||
{
|
||||
auto tempVarValue = var.Value();
|
||||
if (!tempVarValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto doubleValue = GetDouble(*tempVarValue);
|
||||
if (!doubleValue.has_value()) {
|
||||
return false;
|
||||
}
|
||||
if (less) {
|
||||
return doubleValue < value;
|
||||
}
|
||||
return doubleValue > value;
|
||||
}
|
||||
|
||||
bool MacroConditionTempVar::Compare(const TempVariable &var) const
|
||||
{
|
||||
auto value = var.Value();
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_regex.Enabled()) {
|
||||
auto expr = _regex.GetRegularExpression(_strValue);
|
||||
if (!expr.isValid()) {
|
||||
return false;
|
||||
}
|
||||
auto match = expr.match(QString::fromStdString(*value));
|
||||
return match.hasMatch();
|
||||
}
|
||||
|
||||
return std::string(_strValue) == *value;
|
||||
}
|
||||
|
||||
bool MacroConditionTempVar::ValueChanged(const TempVariable &var)
|
||||
{
|
||||
auto value = var.Value();
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
bool changed = *value != _lastValue;
|
||||
if (changed) {
|
||||
_lastValue = *value;
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool MacroConditionTempVar::CompareVariables()
|
||||
{
|
||||
auto var1 = _tempVar.GetTempVariable(GetMacro());
|
||||
auto var2 = _variable2.lock();
|
||||
if (!var1 || !var2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto tempVarValue = var1->Value();
|
||||
if (!tempVarValue) {
|
||||
return false;
|
||||
}
|
||||
auto val1 = GetDouble(*tempVarValue);
|
||||
auto val2 = var2->DoubleValue();
|
||||
bool validNumbers = val1.has_value() && val2.has_value();
|
||||
|
||||
switch (_type) {
|
||||
case MacroConditionTempVar::Condition::EQUALS_VARIABLE:
|
||||
return *tempVarValue == var2->Value() ||
|
||||
(validNumbers && val1 == val2);
|
||||
case MacroConditionTempVar::Condition::LESS_THAN_VARIABLE:
|
||||
return validNumbers && val1 < val2;
|
||||
case MacroConditionTempVar::Condition::GREATER_THAN_VARIABLE:
|
||||
return validNumbers && val1 > val2;
|
||||
default:
|
||||
blog(LOG_WARNING,
|
||||
"Unexpected call of %s with condition type %d", __func__,
|
||||
static_cast<int>(_type));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacroConditionTempVar::CheckCondition()
|
||||
{
|
||||
auto var = _tempVar.GetTempVariable(GetMacro());
|
||||
if (!var) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (_type) {
|
||||
case MacroConditionTempVar::Condition::EQUALS:
|
||||
return Compare(*var);
|
||||
case MacroConditionTempVar::Condition::IS_EMPTY:
|
||||
return var->Value().has_value() && var->Value()->empty();
|
||||
case MacroConditionTempVar::Condition::IS_NUMBER:
|
||||
return isNumber(*var);
|
||||
case MacroConditionTempVar::Condition::LESS_THAN:
|
||||
return compareNumber(*var, _numValue, true);
|
||||
case MacroConditionTempVar::Condition::GREATER_THAN:
|
||||
return compareNumber(*var, _numValue, false);
|
||||
case MacroConditionTempVar::Condition::VALUE_CHANGED:
|
||||
return ValueChanged(*var);
|
||||
case MacroConditionTempVar::Condition::EQUALS_VARIABLE:
|
||||
return CompareVariables();
|
||||
case MacroConditionTempVar::Condition::LESS_THAN_VARIABLE:
|
||||
return CompareVariables();
|
||||
case MacroConditionTempVar::Condition::GREATER_THAN_VARIABLE:
|
||||
return CompareVariables();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacroConditionTempVar::Save(obs_data_t *obj) const
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
_tempVar.Save(obj);
|
||||
obs_data_set_string(obj, "variableName",
|
||||
GetWeakVariableName(_variable2).c_str());
|
||||
_strValue.Save(obj, "strValue");
|
||||
obs_data_set_double(obj, "numValue", _numValue);
|
||||
obs_data_set_int(obj, "condition", static_cast<int>(_type));
|
||||
_regex.Save(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroConditionTempVar::Load(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Load(obj);
|
||||
_tempVar.Load(obj, GetMacro());
|
||||
_variable2 =
|
||||
GetWeakVariableByName(obs_data_get_string(obj, "variableName"));
|
||||
_strValue.Load(obj, "strValue");
|
||||
_numValue = obs_data_get_double(obj, "numValue");
|
||||
_type = static_cast<Condition>(obs_data_get_int(obj, "condition"));
|
||||
_regex.Load(obj);
|
||||
// TODO: remove in future version
|
||||
if (obs_data_has_user_value(obj, "regex")) {
|
||||
_regex.CreateBackwardsCompatibleRegex(
|
||||
obs_data_get_bool(obj, "regex"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string MacroConditionTempVar::GetShortDesc() const
|
||||
{
|
||||
auto var = _tempVar.GetTempVariable(GetMacro());
|
||||
if (!var) {
|
||||
return "";
|
||||
}
|
||||
return var->Name();
|
||||
}
|
||||
|
||||
static inline void populateConditionSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : conditionTypes) {
|
||||
list->addItem(obs_module_text(entry.second.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
MacroConditionTempVarEdit::MacroConditionTempVarEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionTempVar> entryData)
|
||||
: QWidget(parent),
|
||||
_tempVars(new TempVariableSelection(this)),
|
||||
_variables2(new VariableSelection(this)),
|
||||
_conditions(new QComboBox()),
|
||||
_strValue(new VariableTextEdit(this, 5, 1, 1)),
|
||||
_numValue(new QDoubleSpinBox()),
|
||||
_regex(new RegexConfigWidget(parent))
|
||||
{
|
||||
_numValue->setMinimum(-9999999999);
|
||||
_numValue->setMaximum(9999999999);
|
||||
populateConditionSelection(_conditions);
|
||||
|
||||
QWidget::connect(_tempVars,
|
||||
SIGNAL(SelectionChanged(const TempVariableRef &)),
|
||||
this, SLOT(VariableChanged(const TempVariableRef &)));
|
||||
QWidget::connect(_variables2, SIGNAL(SelectionChanged(const QString &)),
|
||||
this, SLOT(Variable2Changed(const QString &)));
|
||||
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ConditionChanged(int)));
|
||||
QWidget::connect(_strValue, SIGNAL(textChanged()), this,
|
||||
SLOT(StrValueChanged()));
|
||||
QWidget::connect(_numValue, SIGNAL(valueChanged(double)), this,
|
||||
SLOT(NumValueChanged(double)));
|
||||
QWidget::connect(_regex, SIGNAL(RegexConfigChanged(RegexConfig)), this,
|
||||
SLOT(RegexChanged(RegexConfig)));
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{variables}}", _tempVars},
|
||||
{"{{variables2}}", _variables2},
|
||||
{"{{conditions}}", _conditions},
|
||||
{"{{strValue}}", _strValue},
|
||||
{"{{numValue}}", _numValue},
|
||||
{"{{regex}}", _regex},
|
||||
};
|
||||
|
||||
auto layout = new QHBoxLayout;
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.condition.variable.entry"),
|
||||
layout, widgetPlaceholders);
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::UpdateEntryData()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_tempVars->SetVariable(_entryData->_tempVar);
|
||||
_variables2->SetVariable(_entryData->_variable2);
|
||||
_conditions->setCurrentIndex(static_cast<int>(_entryData->_type));
|
||||
_strValue->setPlainText(_entryData->_strValue);
|
||||
_numValue->setValue(_entryData->_numValue);
|
||||
_regex->SetRegexConfig(_entryData->_regex);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::VariableChanged(const TempVariableRef &var)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_tempVar = var;
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::Variable2Changed(const QString &text)
|
||||
{
|
||||
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_variable2 = GetWeakVariableByQString(text);
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::ConditionChanged(int value)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_type =
|
||||
static_cast<MacroConditionTempVar::Condition>(value);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::StrValueChanged()
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_strValue = _strValue->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::NumValueChanged(double val)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_numValue = val;
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::RegexChanged(RegexConfig conf)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_regex = conf;
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroConditionTempVarEdit::SetWidgetVisibility()
|
||||
{
|
||||
if (!_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
_regex->setVisible(_entryData->_type ==
|
||||
MacroConditionTempVar::Condition::EQUALS);
|
||||
_strValue->setVisible(_entryData->_type ==
|
||||
MacroConditionTempVar::Condition::EQUALS);
|
||||
_numValue->setVisible(
|
||||
_entryData->_type ==
|
||||
MacroConditionTempVar::Condition::LESS_THAN ||
|
||||
_entryData->_type ==
|
||||
MacroConditionTempVar::Condition::GREATER_THAN);
|
||||
_numValue->setVisible(
|
||||
_entryData->_type ==
|
||||
MacroConditionTempVar::Condition::LESS_THAN ||
|
||||
_entryData->_type ==
|
||||
MacroConditionTempVar::Condition::GREATER_THAN);
|
||||
_variables2->setVisible(
|
||||
_entryData->_type ==
|
||||
MacroConditionTempVar::Condition::EQUALS_VARIABLE ||
|
||||
_entryData->_type ==
|
||||
MacroConditionTempVar::Condition::LESS_THAN_VARIABLE ||
|
||||
_entryData->_type ==
|
||||
MacroConditionTempVar::Condition::GREATER_THAN_VARIABLE);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
100
src/macro-core/macro-condition-tempvar.hpp
Normal file
100
src/macro-core/macro-condition-tempvar.hpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
#include "macro-condition-edit.hpp"
|
||||
#include "resizing-text-edit.hpp"
|
||||
#include "variable.hpp"
|
||||
#include "regex-config.hpp"
|
||||
#include "variable-text-edit.hpp"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
#include <QCheckBox>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class MacroConditionTempVar : public MacroCondition {
|
||||
public:
|
||||
MacroConditionTempVar(Macro *m) : MacroCondition(m) {}
|
||||
bool CheckCondition();
|
||||
bool Save(obs_data_t *obj) const;
|
||||
bool Load(obs_data_t *obj);
|
||||
std::string GetShortDesc() const;
|
||||
std::string GetId() const { return id; };
|
||||
static std::shared_ptr<MacroCondition> Create(Macro *m)
|
||||
{
|
||||
return std::make_shared<MacroConditionTempVar>(m);
|
||||
}
|
||||
|
||||
enum class Condition {
|
||||
EQUALS,
|
||||
IS_EMPTY,
|
||||
IS_NUMBER,
|
||||
LESS_THAN,
|
||||
GREATER_THAN,
|
||||
VALUE_CHANGED,
|
||||
EQUALS_VARIABLE,
|
||||
LESS_THAN_VARIABLE,
|
||||
GREATER_THAN_VARIABLE,
|
||||
};
|
||||
|
||||
Condition _type = Condition::EQUALS;
|
||||
TempVariableRef _tempVar;
|
||||
std::weak_ptr<Variable> _variable2;
|
||||
StringVariable _strValue = "";
|
||||
double _numValue = 0;
|
||||
RegexConfig _regex;
|
||||
|
||||
private:
|
||||
bool Compare(const TempVariable &) const;
|
||||
bool ValueChanged(const TempVariable &);
|
||||
bool CompareVariables();
|
||||
|
||||
std::string _lastValue = "";
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroConditionTempVarEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MacroConditionTempVarEdit(
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroConditionTempVar> cond = nullptr);
|
||||
void UpdateEntryData();
|
||||
static QWidget *Create(QWidget *parent,
|
||||
std::shared_ptr<MacroCondition> cond)
|
||||
{
|
||||
return new MacroConditionTempVarEdit(
|
||||
parent,
|
||||
std::dynamic_pointer_cast<MacroConditionTempVar>(cond));
|
||||
}
|
||||
|
||||
private slots:
|
||||
void VariableChanged(const TempVariableRef &);
|
||||
void Variable2Changed(const QString &);
|
||||
void ConditionChanged(int);
|
||||
void StrValueChanged();
|
||||
void NumValueChanged(double);
|
||||
void RegexChanged(RegexConfig);
|
||||
|
||||
signals:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
||||
protected:
|
||||
TempVariableSelection *_tempVars;
|
||||
VariableSelection *_variables2;
|
||||
QComboBox *_conditions;
|
||||
VariableTextEdit *_strValue;
|
||||
QDoubleSpinBox *_numValue;
|
||||
RegexConfigWidget *_regex;
|
||||
std::shared_ptr<MacroConditionTempVar> _entryData;
|
||||
|
||||
private:
|
||||
void SetWidgetVisibility();
|
||||
|
||||
bool _loading = true;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -10,18 +10,20 @@ bool MacroConditionTimer::_registered = MacroConditionFactory::Register(
|
||||
{MacroConditionTimer::Create, MacroConditionTimerEdit::Create,
|
||||
"AdvSceneSwitcher.condition.timer", false});
|
||||
|
||||
const static std::map<TimerType, std::string> timerTypes = {
|
||||
{TimerType::FIXED, "AdvSceneSwitcher.condition.timer.type.fixed"},
|
||||
{TimerType::RANDOM, "AdvSceneSwitcher.condition.timer.type.random"},
|
||||
const static std::map<MacroConditionTimer::TimerType, std::string> timerTypes = {
|
||||
{MacroConditionTimer::TimerType::FIXED,
|
||||
"AdvSceneSwitcher.condition.timer.type.fixed"},
|
||||
{MacroConditionTimer::TimerType::RANDOM,
|
||||
"AdvSceneSwitcher.condition.timer.type.random"},
|
||||
};
|
||||
|
||||
bool MacroConditionTimer::CheckCondition()
|
||||
{
|
||||
if (_paused) {
|
||||
SetVariableValue(std::to_string(_remaining));
|
||||
SetVariables(_remaining);
|
||||
return _remaining == 0.;
|
||||
}
|
||||
SetVariableValue(std::to_string(_duration.TimeRemaining()));
|
||||
SetVariables(_duration.TimeRemaining());
|
||||
if (_duration.DurationReached()) {
|
||||
if (!_oneshot) {
|
||||
_duration.Reset();
|
||||
@@ -120,6 +122,29 @@ void MacroConditionTimer::Reset()
|
||||
}
|
||||
}
|
||||
|
||||
void MacroConditionTimer::SetVariables(double seconds)
|
||||
{
|
||||
SetVariableValue(std::to_string(seconds));
|
||||
SetTempVarValue("seconds", std::to_string((int)seconds));
|
||||
SetTempVarValue("minutes", std::to_string((int)(seconds / 60)));
|
||||
SetTempVarValue("hours", std::to_string((int)(seconds / (60 * 60))));
|
||||
SetTempVarValue("days",
|
||||
std::to_string((int)(seconds / (60 * 60 * 24))));
|
||||
}
|
||||
|
||||
void MacroConditionTimer::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
AddTempvar("seconds",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.timer.seconds"));
|
||||
AddTempvar("minutes",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.timer.minutes"));
|
||||
AddTempvar("hours",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.timer.hours"));
|
||||
AddTempvar("days",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.timer.days"));
|
||||
}
|
||||
|
||||
static inline void populateTimerTypeSelection(QComboBox *list)
|
||||
{
|
||||
for (auto entry : timerTypes) {
|
||||
@@ -203,7 +228,7 @@ void MacroConditionTimerEdit::TimerTypeChanged(int type)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_type = static_cast<TimerType>(type);
|
||||
_entryData->_type = static_cast<MacroConditionTimer::TimerType>(type);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -337,7 +362,7 @@ void MacroConditionTimerEdit::SetWidgetVisibility()
|
||||
{"{{duration2}}", _duration2},
|
||||
};
|
||||
|
||||
if (_entryData->_type == TimerType::RANDOM) {
|
||||
if (_entryData->_type == MacroConditionTimer::TimerType::RANDOM) {
|
||||
PlaceWidgets(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.condition.timer.entry.line1.random"),
|
||||
|
||||
@@ -12,11 +12,6 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
enum class TimerType {
|
||||
FIXED,
|
||||
RANDOM,
|
||||
};
|
||||
|
||||
class MacroConditionTimer : public MacroCondition {
|
||||
public:
|
||||
MacroConditionTimer(Macro *m) : MacroCondition(m, true) {}
|
||||
@@ -32,6 +27,7 @@ public:
|
||||
void Continue();
|
||||
void Reset();
|
||||
|
||||
enum class TimerType { FIXED, RANDOM };
|
||||
TimerType _type = TimerType::FIXED;
|
||||
Duration _duration;
|
||||
Duration _duration2;
|
||||
@@ -42,6 +38,9 @@ public:
|
||||
|
||||
private:
|
||||
void SetRandomTimeRemaining();
|
||||
void SetVariables(double seconds);
|
||||
void SetupTempVars();
|
||||
|
||||
std::default_random_engine _re;
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "macro-condition-transition.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace advss {
|
||||
@@ -50,8 +50,8 @@ static bool isTargetScene(OBSWeakSource &target)
|
||||
bool MacroConditionTransition::CheckCondition()
|
||||
{
|
||||
bool anyTransitionEnded = _lastTransitionEndTime !=
|
||||
switcher->lastTransitionEndTime;
|
||||
bool anyTransitionStarted = switcher->AnySceneTransitionStarted();
|
||||
GetLastTransitionEndTime();
|
||||
bool anyTransitionStarted = AnySceneTransitionStarted();
|
||||
bool transitionStarted = false;
|
||||
bool transitionEnded = false;
|
||||
|
||||
@@ -82,7 +82,7 @@ bool MacroConditionTransition::CheckCondition()
|
||||
break;
|
||||
case TransitionCondition::TRANSITION_SOURCE:
|
||||
ret = anyTransitionStarted &&
|
||||
_scene.GetScene() == switcher->currentScene;
|
||||
_scene.GetScene() == GetCurrentScene();
|
||||
break;
|
||||
case TransitionCondition::TRANSITION_TARGET: {
|
||||
auto scene = _scene.GetScene();
|
||||
@@ -101,7 +101,7 @@ bool MacroConditionTransition::CheckCondition()
|
||||
_ended = false;
|
||||
}
|
||||
if (anyTransitionEnded) {
|
||||
_lastTransitionEndTime = switcher->lastTransitionEndTime;
|
||||
_lastTransitionEndTime = GetLastTransitionEndTime();
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#include "macro-condition-variable.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <regex>
|
||||
|
||||
namespace advss {
|
||||
|
||||
const std::string MacroConditionVariable::id = "variable";
|
||||
@@ -12,25 +10,25 @@ bool MacroConditionVariable::_registered = MacroConditionFactory::Register(
|
||||
{MacroConditionVariable::Create, MacroConditionVariableEdit::Create,
|
||||
"AdvSceneSwitcher.condition.variable"});
|
||||
|
||||
const static std::map<MacroConditionVariable::Type, std::string>
|
||||
const static std::map<MacroConditionVariable::Condition, std::string>
|
||||
conditionTypes = {
|
||||
{MacroConditionVariable::Type::EQUALS,
|
||||
{MacroConditionVariable::Condition::EQUALS,
|
||||
"AdvSceneSwitcher.condition.variable.type.compare"},
|
||||
{MacroConditionVariable::Type::IS_EMPTY,
|
||||
{MacroConditionVariable::Condition::IS_EMPTY,
|
||||
"AdvSceneSwitcher.condition.variable.type.empty"},
|
||||
{MacroConditionVariable::Type::IS_NUMBER,
|
||||
{MacroConditionVariable::Condition::IS_NUMBER,
|
||||
"AdvSceneSwitcher.condition.variable.type.number"},
|
||||
{MacroConditionVariable::Type::LESS_THAN,
|
||||
{MacroConditionVariable::Condition::LESS_THAN,
|
||||
"AdvSceneSwitcher.condition.variable.type.lessThan"},
|
||||
{MacroConditionVariable::Type::GREATER_THAN,
|
||||
{MacroConditionVariable::Condition::GREATER_THAN,
|
||||
"AdvSceneSwitcher.condition.variable.type.greaterThan"},
|
||||
{MacroConditionVariable::Type::VALUE_CHANGED,
|
||||
{MacroConditionVariable::Condition::VALUE_CHANGED,
|
||||
"AdvSceneSwitcher.condition.variable.type.valueChanged"},
|
||||
{MacroConditionVariable::Type::EQUALS_VARIABLE,
|
||||
{MacroConditionVariable::Condition::EQUALS_VARIABLE,
|
||||
"AdvSceneSwitcher.condition.variable.type.equalsVariable"},
|
||||
{MacroConditionVariable::Type::LESS_THAN_VARIABLE,
|
||||
{MacroConditionVariable::Condition::LESS_THAN_VARIABLE,
|
||||
"AdvSceneSwitcher.condition.variable.type.lessThanVariable"},
|
||||
{MacroConditionVariable::Type::GREATER_THAN_VARIABLE,
|
||||
{MacroConditionVariable::Condition::GREATER_THAN_VARIABLE,
|
||||
"AdvSceneSwitcher.condition.variable.type.greaterThanVariable"},
|
||||
};
|
||||
|
||||
@@ -62,7 +60,7 @@ bool MacroConditionVariable::Compare(const Variable &var) const
|
||||
return match.hasMatch();
|
||||
}
|
||||
|
||||
return _strValue == var.Value();
|
||||
return std::string(_strValue) == var.Value();
|
||||
}
|
||||
|
||||
bool MacroConditionVariable::ValueChanged(const Variable &var)
|
||||
@@ -87,12 +85,12 @@ bool MacroConditionVariable::CompareVariables()
|
||||
bool validNumbers = val1.has_value() && val2.has_value();
|
||||
|
||||
switch (_type) {
|
||||
case MacroConditionVariable::Type::EQUALS_VARIABLE:
|
||||
case MacroConditionVariable::Condition::EQUALS_VARIABLE:
|
||||
return var1->Value() == var2->Value() ||
|
||||
(validNumbers && val1 == val2);
|
||||
case MacroConditionVariable::Type::LESS_THAN_VARIABLE:
|
||||
case MacroConditionVariable::Condition::LESS_THAN_VARIABLE:
|
||||
return validNumbers && val1 < val2;
|
||||
case MacroConditionVariable::Type::GREATER_THAN_VARIABLE:
|
||||
case MacroConditionVariable::Condition::GREATER_THAN_VARIABLE:
|
||||
return validNumbers && val1 > val2;
|
||||
default:
|
||||
blog(LOG_WARNING,
|
||||
@@ -111,23 +109,23 @@ bool MacroConditionVariable::CheckCondition()
|
||||
}
|
||||
|
||||
switch (_type) {
|
||||
case MacroConditionVariable::Type::EQUALS:
|
||||
case MacroConditionVariable::Condition::EQUALS:
|
||||
return Compare(*var);
|
||||
case MacroConditionVariable::Type::IS_EMPTY:
|
||||
case MacroConditionVariable::Condition::IS_EMPTY:
|
||||
return var->Value().empty();
|
||||
case MacroConditionVariable::Type::IS_NUMBER:
|
||||
case MacroConditionVariable::Condition::IS_NUMBER:
|
||||
return isNumber(*var);
|
||||
case MacroConditionVariable::Type::LESS_THAN:
|
||||
case MacroConditionVariable::Condition::LESS_THAN:
|
||||
return compareNumber(*var, _numValue, true);
|
||||
case MacroConditionVariable::Type::GREATER_THAN:
|
||||
case MacroConditionVariable::Condition::GREATER_THAN:
|
||||
return compareNumber(*var, _numValue, false);
|
||||
case MacroConditionVariable::Type::VALUE_CHANGED:
|
||||
case MacroConditionVariable::Condition::VALUE_CHANGED:
|
||||
return ValueChanged(*var);
|
||||
case MacroConditionVariable::Type::EQUALS_VARIABLE:
|
||||
case MacroConditionVariable::Condition::EQUALS_VARIABLE:
|
||||
return CompareVariables();
|
||||
case MacroConditionVariable::Type::LESS_THAN_VARIABLE:
|
||||
case MacroConditionVariable::Condition::LESS_THAN_VARIABLE:
|
||||
return CompareVariables();
|
||||
case MacroConditionVariable::Type::GREATER_THAN_VARIABLE:
|
||||
case MacroConditionVariable::Condition::GREATER_THAN_VARIABLE:
|
||||
return CompareVariables();
|
||||
}
|
||||
|
||||
@@ -141,7 +139,7 @@ bool MacroConditionVariable::Save(obs_data_t *obj) const
|
||||
GetWeakVariableName(_variable).c_str());
|
||||
obs_data_set_string(obj, "variable2Name",
|
||||
GetWeakVariableName(_variable2).c_str());
|
||||
obs_data_set_string(obj, "strValue", _strValue.c_str());
|
||||
_strValue.Save(obj, "strValue");
|
||||
obs_data_set_double(obj, "numValue", _numValue);
|
||||
obs_data_set_int(obj, "condition", static_cast<int>(_type));
|
||||
_regex.Save(obj);
|
||||
@@ -155,9 +153,9 @@ bool MacroConditionVariable::Load(obs_data_t *obj)
|
||||
GetWeakVariableByName(obs_data_get_string(obj, "variableName"));
|
||||
_variable2 = GetWeakVariableByName(
|
||||
obs_data_get_string(obj, "variable2Name"));
|
||||
_strValue = obs_data_get_string(obj, "strValue");
|
||||
_strValue.Load(obj, "strValue");
|
||||
_numValue = obs_data_get_double(obj, "numValue");
|
||||
_type = static_cast<Type>(obs_data_get_int(obj, "condition"));
|
||||
_type = static_cast<Condition>(obs_data_get_int(obj, "condition"));
|
||||
_regex.Load(obj);
|
||||
// TODO: remove in future version
|
||||
if (obs_data_has_user_value(obj, "regex")) {
|
||||
@@ -185,7 +183,7 @@ MacroConditionVariableEdit::MacroConditionVariableEdit(
|
||||
_variables(new VariableSelection(this)),
|
||||
_variables2(new VariableSelection(this)),
|
||||
_conditions(new QComboBox()),
|
||||
_strValue(new ResizingPlainTextEdit(this, 5, 1, 1)),
|
||||
_strValue(new VariableTextEdit(this, 5, 1, 1)),
|
||||
_numValue(new QDoubleSpinBox()),
|
||||
_regex(new RegexConfigWidget(parent))
|
||||
{
|
||||
@@ -215,19 +213,11 @@ MacroConditionVariableEdit::MacroConditionVariableEdit(
|
||||
{"{{regex}}", _regex},
|
||||
};
|
||||
|
||||
QHBoxLayout *layout = new QHBoxLayout;
|
||||
auto layout = new QHBoxLayout;
|
||||
PlaceWidgets(
|
||||
obs_module_text("AdvSceneSwitcher.condition.variable.entry"),
|
||||
layout, widgetPlaceholders);
|
||||
|
||||
auto *regexLayout = new QHBoxLayout;
|
||||
regexLayout->addWidget(_regex);
|
||||
regexLayout->addStretch();
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(layout);
|
||||
mainLayout->addLayout(regexLayout);
|
||||
setLayout(mainLayout);
|
||||
setLayout(layout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData();
|
||||
@@ -243,7 +233,7 @@ void MacroConditionVariableEdit::UpdateEntryData()
|
||||
_variables->SetVariable(_entryData->_variable);
|
||||
_variables2->SetVariable(_entryData->_variable2);
|
||||
_conditions->setCurrentIndex(static_cast<int>(_entryData->_type));
|
||||
_strValue->setPlainText(QString::fromStdString(_entryData->_strValue));
|
||||
_strValue->setPlainText(_entryData->_strValue);
|
||||
_numValue->setValue(_entryData->_numValue);
|
||||
_regex->SetRegexConfig(_entryData->_regex);
|
||||
SetWidgetVisibility();
|
||||
@@ -277,7 +267,8 @@ void MacroConditionVariableEdit::ConditionChanged(int value)
|
||||
}
|
||||
|
||||
auto lock = LockContext();
|
||||
_entryData->_type = static_cast<MacroConditionVariable::Type>(value);
|
||||
_entryData->_type =
|
||||
static_cast<MacroConditionVariable::Condition>(value);
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
@@ -290,6 +281,7 @@ void MacroConditionVariableEdit::StrValueChanged()
|
||||
auto lock = LockContext();
|
||||
_entryData->_strValue = _strValue->toPlainText().toStdString();
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroConditionVariableEdit::NumValueChanged(double val)
|
||||
@@ -321,24 +313,26 @@ void MacroConditionVariableEdit::SetWidgetVisibility()
|
||||
}
|
||||
|
||||
_regex->setVisible(_entryData->_type ==
|
||||
MacroConditionVariable::Type::EQUALS);
|
||||
MacroConditionVariable::Condition::EQUALS);
|
||||
_strValue->setVisible(_entryData->_type ==
|
||||
MacroConditionVariable::Type::EQUALS);
|
||||
MacroConditionVariable::Condition::EQUALS);
|
||||
_numValue->setVisible(
|
||||
_entryData->_type == MacroConditionVariable::Type::LESS_THAN ||
|
||||
_entryData->_type ==
|
||||
MacroConditionVariable::Type::GREATER_THAN);
|
||||
MacroConditionVariable::Condition::LESS_THAN ||
|
||||
_entryData->_type ==
|
||||
MacroConditionVariable::Condition::GREATER_THAN);
|
||||
_numValue->setVisible(
|
||||
_entryData->_type == MacroConditionVariable::Type::LESS_THAN ||
|
||||
_entryData->_type ==
|
||||
MacroConditionVariable::Type::GREATER_THAN);
|
||||
MacroConditionVariable::Condition::LESS_THAN ||
|
||||
_entryData->_type ==
|
||||
MacroConditionVariable::Condition::GREATER_THAN);
|
||||
_variables2->setVisible(
|
||||
_entryData->_type ==
|
||||
MacroConditionVariable::Type::EQUALS_VARIABLE ||
|
||||
MacroConditionVariable::Condition::EQUALS_VARIABLE ||
|
||||
_entryData->_type ==
|
||||
MacroConditionVariable::Type::LESS_THAN_VARIABLE ||
|
||||
MacroConditionVariable::Condition::LESS_THAN_VARIABLE ||
|
||||
_entryData->_type ==
|
||||
MacroConditionVariable::Type::GREATER_THAN_VARIABLE);
|
||||
MacroConditionVariable::Condition::GREATER_THAN_VARIABLE);
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "resizing-text-edit.hpp"
|
||||
#include "variable.hpp"
|
||||
#include "regex-config.hpp"
|
||||
#include "variable-text-edit.hpp"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
@@ -24,7 +25,7 @@ public:
|
||||
return std::make_shared<MacroConditionVariable>(m);
|
||||
}
|
||||
|
||||
enum class Type {
|
||||
enum class Condition {
|
||||
EQUALS,
|
||||
IS_EMPTY,
|
||||
IS_NUMBER,
|
||||
@@ -36,10 +37,10 @@ public:
|
||||
GREATER_THAN_VARIABLE,
|
||||
};
|
||||
|
||||
Type _type = Type::EQUALS;
|
||||
Condition _type = Condition::EQUALS;
|
||||
std::weak_ptr<Variable> _variable;
|
||||
std::weak_ptr<Variable> _variable2;
|
||||
std::string _strValue = "";
|
||||
StringVariable _strValue = "";
|
||||
double _numValue = 0;
|
||||
RegexConfig _regex;
|
||||
|
||||
@@ -86,7 +87,7 @@ protected:
|
||||
VariableSelection *_variables;
|
||||
VariableSelection *_variables2;
|
||||
QComboBox *_conditions;
|
||||
ResizingPlainTextEdit *_strValue;
|
||||
VariableTextEdit *_strValue;
|
||||
QDoubleSpinBox *_numValue;
|
||||
RegexConfigWidget *_regex;
|
||||
std::shared_ptr<MacroConditionVariable> _entryData;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "macro-condition-websocket.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <regex>
|
||||
@@ -34,28 +33,24 @@ static bool matchRegex(const RegexConfig &conf, const std::string &msg,
|
||||
|
||||
bool MacroConditionWebsocket::CheckCondition()
|
||||
{
|
||||
const std::vector<std::string> *messages = nullptr;
|
||||
std::vector<std::string> messages;
|
||||
switch (_type) {
|
||||
case MacroConditionWebsocket::Type::REQUEST:
|
||||
messages = &switcher->websocketMessages;
|
||||
messages = GetWebsocketMessages();
|
||||
break;
|
||||
case MacroConditionWebsocket::Type::EVENT: {
|
||||
auto connection = _connection.lock();
|
||||
if (!connection) {
|
||||
return false;
|
||||
}
|
||||
messages = &connection->Events();
|
||||
messages = connection->Events();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!messages) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &msg : *messages) {
|
||||
for (const auto &msg : messages) {
|
||||
if (_regex.Enabled()) {
|
||||
if (matchRegex(_regex, msg, _message)) {
|
||||
SetVariableValue(msg);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "macro-condition-window.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
#include "platform-funcs.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
@@ -43,7 +43,8 @@ static bool windowContainsText(const std::string &window,
|
||||
bool MacroConditionWindow::WindowMatchesRequirements(
|
||||
const std::string &window) const
|
||||
{
|
||||
const bool focusCheckOK = (!_focus || window == switcher->currentTitle);
|
||||
const bool focusCheckOK =
|
||||
(!_focus || window == ForegroundWindowTitle());
|
||||
if (!focusCheckOK) {
|
||||
return false;
|
||||
}
|
||||
@@ -96,6 +97,7 @@ bool MacroConditionWindow::WindowRegexMatches(
|
||||
void MacroConditionWindow::SetVariableValueBasedOnMatch(
|
||||
const std::string &matchWindow)
|
||||
{
|
||||
SetTempVarValue("window", matchWindow);
|
||||
if (!IsReferencedInVars()) {
|
||||
return;
|
||||
}
|
||||
@@ -103,13 +105,13 @@ void MacroConditionWindow::SetVariableValueBasedOnMatch(
|
||||
auto text = GetTextInWindow(matchWindow);
|
||||
SetVariableValue(text.value_or(""));
|
||||
} else {
|
||||
SetVariableValue(switcher->currentTitle);
|
||||
SetVariableValue(ForegroundWindowTitle());
|
||||
}
|
||||
}
|
||||
|
||||
static bool foregroundWindowChanged()
|
||||
{
|
||||
return switcher->currentTitle != switcher->lastTitle;
|
||||
return ForegroundWindowTitle() != PreviousForegroundWindowTitle();
|
||||
}
|
||||
|
||||
bool MacroConditionWindow::CheckCondition()
|
||||
@@ -173,6 +175,16 @@ std::string MacroConditionWindow::GetShortDesc() const
|
||||
return _window;
|
||||
}
|
||||
|
||||
void MacroConditionWindow::SetupTempVars()
|
||||
{
|
||||
MacroCondition::SetupTempVars();
|
||||
AddTempvar(
|
||||
"window",
|
||||
obs_module_text("AdvSceneSwitcher.tempVar.window.window"),
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.window.window.description"));
|
||||
}
|
||||
|
||||
MacroConditionWindowEdit::MacroConditionWindowEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroConditionWindow> entryData)
|
||||
: QWidget(parent),
|
||||
@@ -421,7 +433,7 @@ void MacroConditionWindowEdit::WindowFocusChanged(int state)
|
||||
|
||||
void MacroConditionWindowEdit::UpdateFocusWindow()
|
||||
{
|
||||
_focusWindow->setText(QString::fromStdString(switcher->currentTitle));
|
||||
_focusWindow->setText(QString::fromStdString(ForegroundWindowTitle()));
|
||||
}
|
||||
|
||||
void MacroConditionWindowEdit::SetWidgetVisibility()
|
||||
|
||||
@@ -21,7 +21,6 @@ public:
|
||||
return std::make_shared<MacroConditionWindow>(m);
|
||||
}
|
||||
|
||||
public:
|
||||
StringVariable _window;
|
||||
RegexConfig _windowRegex;
|
||||
bool _checkTitle = true;
|
||||
@@ -40,6 +39,7 @@ private:
|
||||
bool WindowMatches(const std::vector<std::string> &windowList);
|
||||
bool WindowRegexMatches(const std::vector<std::string> &windowList);
|
||||
void SetVariableValueBasedOnMatch(const std::string &matchWindow);
|
||||
void SetupTempVars();
|
||||
|
||||
static bool _registered;
|
||||
static const std::string id;
|
||||
|
||||
@@ -22,7 +22,7 @@ void DurationModifier::Save(obs_data_t *obj, const char *condName,
|
||||
void DurationModifier::Load(obs_data_t *obj, const char *condName,
|
||||
const char *duration)
|
||||
{
|
||||
// For backwards compatability check if duration value exist without
|
||||
// For backwards compatibility check if duration value exist without
|
||||
// time constraint condition - if so assume DurationCondition::MORE
|
||||
if (!obs_data_has_user_value(obj, condName) &&
|
||||
obs_data_has_user_value(obj, duration)) {
|
||||
@@ -105,7 +105,7 @@ bool MacroCondition::Load(obs_data_t *obj)
|
||||
_duration.Load(durObj);
|
||||
obs_data_release(durObj);
|
||||
} else {
|
||||
// For backwards compatability
|
||||
// For backwards compatibility
|
||||
_duration.Load(obj);
|
||||
}
|
||||
return true;
|
||||
|
||||
59
src/macro-core/macro-helpers.cpp
Normal file
59
src/macro-core/macro-helpers.cpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "macro-helpers.hpp"
|
||||
#include "plugin-state-helpers.hpp"
|
||||
|
||||
namespace advss {
|
||||
|
||||
static std::atomic_bool abortMacroWait = {false};
|
||||
static std::atomic_bool macroSceneSwitched = {false};
|
||||
static std::atomic_int shutdownConditionCount = {0};
|
||||
|
||||
std::condition_variable &GetMacroWaitCV()
|
||||
{
|
||||
static std::condition_variable cv;
|
||||
return cv;
|
||||
}
|
||||
|
||||
std::condition_variable &GetMacroTransitionCV()
|
||||
{
|
||||
static std::condition_variable cv;
|
||||
return cv;
|
||||
}
|
||||
|
||||
std::atomic_bool &MacroWaitShouldAbort()
|
||||
{
|
||||
return abortMacroWait;
|
||||
}
|
||||
|
||||
void SetMacroAbortWait(bool value)
|
||||
{
|
||||
abortMacroWait = value;
|
||||
}
|
||||
|
||||
bool ShutdownCheckIsNecessary()
|
||||
{
|
||||
return shutdownConditionCount > 0;
|
||||
}
|
||||
|
||||
std::atomic_int &GetShutdownConditionCount()
|
||||
{
|
||||
return shutdownConditionCount;
|
||||
}
|
||||
|
||||
void SetMacroSwitchedScene(bool value)
|
||||
{
|
||||
static bool setupDone = false;
|
||||
if (!setupDone) {
|
||||
// Will always be called with switcher lock already held
|
||||
AddIntervalResetStep([]() { macroSceneSwitched = false; },
|
||||
false);
|
||||
setupDone = true;
|
||||
}
|
||||
macroSceneSwitched = value;
|
||||
}
|
||||
|
||||
bool MacroSwitchedScene()
|
||||
{
|
||||
return macroSceneSwitched;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
21
src/macro-core/macro-helpers.hpp
Normal file
21
src/macro-core/macro-helpers.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <string_view>
|
||||
|
||||
namespace advss {
|
||||
|
||||
constexpr std::string_view GetSceneSwitchActionId()
|
||||
{
|
||||
return "scene_switch";
|
||||
}
|
||||
std::condition_variable &GetMacroWaitCV();
|
||||
std::condition_variable &GetMacroTransitionCV();
|
||||
std::atomic_bool &MacroWaitShouldAbort();
|
||||
void SetMacroAbortWait(bool);
|
||||
bool ShutdownCheckIsNecessary();
|
||||
std::atomic_int &GetShutdownConditionCount();
|
||||
void SetMacroSwitchedScene(bool value);
|
||||
bool MacroSwitchedScene();
|
||||
|
||||
} // namespace advss
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
namespace advss {
|
||||
|
||||
static MacroProperties macroProperties;
|
||||
|
||||
void MacroProperties::Save(obs_data_t *obj) const
|
||||
{
|
||||
auto data = obs_data_create();
|
||||
@@ -325,4 +327,19 @@ bool MacroPropertiesDialog::AskForSettings(QWidget *parent,
|
||||
return true;
|
||||
}
|
||||
|
||||
MacroProperties &GetGlobalMacroProperties()
|
||||
{
|
||||
return macroProperties;
|
||||
}
|
||||
|
||||
void SaveGlobalMacroProperties(obs_data_t *obj)
|
||||
{
|
||||
macroProperties.Save(obj);
|
||||
}
|
||||
|
||||
void LoadGlobalMacroProperties(obs_data_t *obj)
|
||||
{
|
||||
macroProperties.Load(obj);
|
||||
}
|
||||
|
||||
} // 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