Compare commits

..

64 Commits

Author SHA1 Message Date
WarmUpTill
5d568683f7 Update obs-websocket-api.h 2025-07-06 11:06:25 +02:00
WarmUpTill
a26c37021d Fix crash on OBS shutdown 2025-07-06 11:06:22 +02:00
WarmUpTill
0cd7004f6a Setup MIDI device observers in parallel to avoid blocking OBS startup
Some checks failed
debian-build / build (push) Has been cancelled
Push to master / Check Formatting 🔍 (push) Has been cancelled
Push to master / Build Project 🧱 (push) Has been cancelled
Push to master / Create Release 🛫 (push) Has been cancelled
2025-06-25 13:56:40 +02:00
WarmUpTill
40c62ba700 CI: Add libremidi dependencies 2025-06-25 13:56:40 +02:00
Arimil
f2c7b532d9 Add support for kwin (wayland) (#1393)
Some checks failed
debian-build / build (push) Has been cancelled
Push to master / Check Formatting 🔍 (push) Has been cancelled
Push to master / Build Project 🧱 (push) Has been cancelled
Push to master / Create Release 🛫 (push) Has been cancelled
2025-06-21 19:51:25 +02:00
WarmUpTill
456a9c04c7 Add icon for windows installer
Some checks failed
debian-build / build (push) Waiting to run
Push to master / Check Formatting 🔍 (push) Waiting to run
Push to master / Build Project 🧱 (push) Waiting to run
Push to master / Create Release 🛫 (push) Blocked by required conditions
Check locale / ubuntu64 (push) Has been cancelled
2025-06-20 22:29:35 +02:00
WarmUpTill
3e1fdbde45 Add option to set and check list source settings by name
This makes it easier to select the intended settings value as the
underlying value often has no direct connection to the user facing name.

It also makes it possible to select list entries whos underlying value
changes frequently, but the user facing value does not.
(E.g. device IDs based on the input port compared to the device name)
2025-06-20 22:29:35 +02:00
WarmUpTill
874b9b86e2 Refactor locking of macro segments
This should avoid crashes when actions or conditions are performed in
parallel to the main macro loop and will improve the UI responsiveness
in some scenarios
2025-06-20 22:29:35 +02:00
WarmUpTill
98d1f83acc Cleanup 2025-06-20 22:29:35 +02:00
WarmUpTill
7e91f81957 Ease development with dirty dependency directory 2025-06-20 22:29:35 +02:00
WarmUpTill
20488afdd1 Fix tempvars being reset across macros for cached widgets
Some checks failed
debian-build / build (push) Has been cancelled
Check locale / ubuntu64 (push) Has been cancelled
Push to master / Check Formatting 🔍 (push) Has been cancelled
Push to master / Build Project 🧱 (push) Has been cancelled
Push to master / Create Release 🛫 (push) Has been cancelled
2025-06-12 21:29:07 +02:00
WarmUpTill
d9d387ad47 Fix crash when deleting cached macro widgets 2025-06-12 21:29:07 +02:00
WarmUpTill
0736d673e1 Add option to check if chat was cleared / message was removed 2025-06-12 21:29:07 +02:00
WarmUpTill
34151e4bc6 Fix "Get user info" only allowing small values for user ids 2025-06-12 21:29:07 +02:00
WarmUpTill
1346c19bec Fix crash when invalid token is used to connect to Twitch chat 2025-06-12 21:29:07 +02:00
WarmUpTill
be6bc48231 Fix macro selection resetting when any macro was removed 2025-06-12 18:33:24 +02:00
WarmUpTill
79a8ad57af Rework HTTP action URL input
The URL to be accessed can now be passed as a single URL instead of it
being split into a host and path component
2025-06-12 18:33:24 +02:00
WarmUpTill
daeb9275a3 Add support for inline scripts
* Script can be defined in the macro segment or loaded from a file
* Supports both LUA and Python
* Can be used for actions and conditions
* obs_script_create and obs_script_destroy are resolved at runtime
  (Let's hope the API remains stable)
2025-06-09 14:20:44 +02:00
WarmUpTill
73b542a4db Move scripting support to seperate project 2025-06-09 14:20:44 +02:00
WarmUpTill
e3471066e9 Export symbols 2025-06-09 14:20:44 +02:00
WarmUpTill
ec41c06b4d Update feature request description 2025-06-09 14:20:44 +02:00
WarmUpTill
201e45d058 Fix macro tree not resizing properly with OBS 31.1.0 2025-06-07 18:56:42 +02:00
WarmUpTill
b17aa30432 Fix attempting to cache widgets of about to be deleted macros 2025-06-06 19:14:46 +02:00
WarmUpTill
93703c80bc Hide option to verify timestamps when functionality is disabled 2025-06-01 11:57:26 +02:00
WarmUpTill
d7951a7179 Cleanup constness 2025-06-01 11:57:26 +02:00
WarmUpTill
d42a3b584a Rework resource tab hotkey handling
Added hotkey to add new entry
2025-06-01 11:57:26 +02:00
WarmUpTill
becd1bd02a Set default hotkey for new macro to CTRL + N 2025-06-01 11:57:26 +02:00
WarmUpTill
30422aecf3 Fix crash when deleting macro 2025-06-01 11:57:26 +02:00
WarmUpTill
c567e6ef7f Allow import of json files
Automatic backups are stored as json files
2025-06-01 11:57:26 +02:00
WarmUpTill
1ca61f3ed4 Add option to not link date-tz even if the source code exists 2025-05-28 22:11:07 +02:00
WarmUpTill
1affe9dce3 Fix macro segment list entries not resizing properly 2025-05-27 22:37:46 +02:00
WarmUpTill
406e3c1855 Cleanup
* Add variable support to process condition
* Display unresolved variable value in Window action
* Add tooltips to indicate that variables are supported
2025-05-27 22:37:46 +02:00
WarmUpTill
c05dd40c4c Add option to change various OBS video settings 2025-05-27 22:37:46 +02:00
WarmUpTill
9a86ecac42 Add option to disable widget caching 2025-05-27 22:37:46 +02:00
WarmUpTill
721a786e79 Rework preview dialog to improve performance
Object detection and OCR models were constantly being re-initialized
each frame due to copy in the signal / slot handling
2025-05-27 22:37:46 +02:00
WarmUpTill
32d29875ed Move responsibility of cascade init to ObjDetectParameters 2025-05-27 22:37:46 +02:00
warmuptill
0e5f56b562 Add tesseract config file support 2025-05-27 22:37:46 +02:00
WarmUpTill
5490fabf92 Add hotkey to create new macro 2025-05-27 22:37:46 +02:00
WarmUpTill
5e3ab19940 Add ProfileSelectionWidget
Refreshes list of profiles when widget becomes visible to support widget
caching.
2025-05-27 22:37:46 +02:00
WarmUpTill
1c94a1ab44 Add X and Y position tempvars to cursor condition 2025-05-27 22:37:46 +02:00
WarmUpTill
34baa56134 Update process list on visibility change
This is done to support widget caching
2025-05-27 22:37:46 +02:00
WarmUpTill
5ce4171773 Add MonitorSelectionWidget
Refreshes list of monitors when widget becomes visible to support widget
caching
2025-05-27 22:37:46 +02:00
WarmUpTill
c281c6db83 Add WindowSelectionWidget
Refreshes list of windows when widget becomes visible to support widget
caching
2025-05-27 22:37:46 +02:00
WarmUpTill
c43439ee64 Add option to keep selection when FilterComboBox entry doesn't exist 2025-05-27 22:37:46 +02:00
WarmUpTill
a84731b8fe Rework TransitionSelectionWidget to support widget caching 2025-05-27 22:37:46 +02:00
WarmUpTill
61fbff5821 Fix SetSourceSetting() not changing settings if the default value is set
This won't help in scenarios in which even a default value does not
exist, e.g. "text" for the text sources, as here it is unclear which
value type to use
2025-05-27 22:37:46 +02:00
WarmUpTill
1381654fed Add Add support for widget caching to FilterSelectionWidget 2025-05-27 22:37:46 +02:00
WarmUpTill
9805601c07 Add support for widget caching to SceneItemSelectionWidget 2025-05-27 22:37:46 +02:00
WarmUpTill
fcf57ee031 Add support for widget caching to SceneSelectionWidget 2025-05-27 22:37:46 +02:00
WarmUpTill
ba3e87a761 Rework SourceSelectionWidget to support widget caching 2025-05-27 22:37:46 +02:00
WarmUpTill
3dd3f576c3 Add hint that parallel condition check feature is experimental 2025-05-27 22:37:46 +02:00
WarmUpTill
7403a18e96 Cleanup 2025-05-27 22:37:46 +02:00
warmuptill
56494480ba Cache macro segment widgets for each macro 2025-05-27 22:37:46 +02:00
warmuptill
cdc5d16e95 Allow changing Tesseract model directory
This will prevent custom models being deleted when installing a new
version of the plugin, as the plugin's data directory might get wiped on
some operating systems.
2025-05-27 22:37:46 +02:00
warmuptill
27aed79305 Enable building with OCR support in Ubuntu environment 2025-05-27 22:37:46 +02:00
WarmUpTill
7ec95e33eb Hide outdated video condition options
The "throttle" and "reduce matching latency" optiohns were introduced
before "short circuit evaluation" was available and are now outdated.

Both don't behave as expected with this option enabled.
The throttling effect can be better achieved with an additional "Timer"
condition.
2025-05-27 22:37:46 +02:00
WarmUpTill
98260b25a1 Add option to toggle the pause state of a macro 2025-05-27 22:37:46 +02:00
WarmUpTill
45b37de9f7 Add MQTT connection tab 2025-05-27 20:23:07 +02:00
WarmUpTill
027a3e9074 Add MQTT condition and action 2025-05-27 20:23:07 +02:00
WarmUpTill
cab50e0922 Add MQTT helpers 2025-05-27 20:23:07 +02:00
WarmUpTill
88514e209d CI: build paho.mqtt.cpp libs 2025-05-27 20:23:07 +02:00
WarmUpTill
4ed7f13b72 Add paho.mqtt.cpp dependency 2025-05-27 20:23:07 +02:00
WarmUpTill
0fb11ac274 Add copy / move to MessageDispatcher 2025-05-27 20:23:07 +02:00
WarmUpTill
942933290a Remove unnecessary include 2025-05-27 20:23:07 +02:00
220 changed files with 6736 additions and 2396 deletions

View File

@@ -2,7 +2,7 @@
# https://github.com/obsproject/.github/tree/master/.github/ISSUE_TEMPLATE # https://github.com/obsproject/.github/tree/master/.github/ISSUE_TEMPLATE
name: Feature request name: Feature request
description: Suggest an idea for this projectReport a bug or crash description: Suggest an idea for this project
body: body:
- type: markdown - type: markdown
id: md_welcome id: md_welcome

View File

@@ -10,4 +10,9 @@ package 'libxss-dev'
package 'libopencv-dev' package 'libopencv-dev'
package 'libtesseract-dev' package 'libtesseract-dev'
package 'libproc2-dev' package 'libproc2-dev'
package 'libusb-1.0-0-dev' package 'libusb-1.0-0-dev'
package 'libpaho-mqttpp-dev'
package 'libpaho-mqtt-dev'
package 'libpaho-mqtt-dev'
package 'libasound2-dev'
package 'libpipewire-0.3-dev'

View File

@@ -478,6 +478,33 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
unset MACOSX_DEPLOYMENT_TARGET unset MACOSX_DEPLOYMENT_TARGET
popd popd
local mqtt_dir="${project_root}/deps/paho.mqtt.cpp"
local mqtt_build_dir="${mqtt_dir}/build_${target##*-}"
local -a mqtt_cmake_args=(
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_OSX_ARCHITECTURES=${${target##*-}//universal/x86_64;arm64}
-DCMAKE_OSX_DEPLOYMENT_TARGET=${DEPLOYMENT_TARGET:-10.15}
-DCMAKE_PREFIX_PATH="${advss_dep_path};${_plugin_deps}"
-DCMAKE_INSTALL_PREFIX="${advss_dep_path}"
-DPAHO_BUILD_SHARED=OFF
-DPAHO_BUILD_STATIC=ON
-DPAHO_WITH_MQTT_C=ON
-DOPENSSL_ROOT_DIR="${advss_dep_path}"
-DPAHO_WITH_SSL=OFF # TODO: figure out linking issues with openssl
)
pushd ${mqtt_dir}
log_info "Configure paho.mqtt.cpp ..."
cmake -S . -B ${mqtt_build_dir} ${mqtt_cmake_args}
log_info "Building paho.mqtt.cpp ..."
cmake --build ${mqtt_build_dir} --config Release
log_info "Installing paho.mqtt.cpp ..."
cmake --install ${mqtt_build_dir} --prefix "${advss_dep_path}" --config Release
popd
;; ;;
linux) linux)
# Nothing to do for now # Nothing to do for now

View File

@@ -219,6 +219,37 @@ function Build {
} else { } else {
Log-Information "Failed to locate msbuild.exe - skipping libusb build" Log-Information "Failed to locate msbuild.exe - skipping libusb build"
} }
Push-Location -Stack BuildMqttTemp
Ensure-Location $ProjectRoot
$MqttPath = "${ProjectRoot}/deps/paho.mqtt.cpp"
$MqttBuildPath = "${MqttPath}/build"
# Explicitly disable PkgConfig and tiff as it will lead build errors
$MqttCmakeArgs = @(
"-DCMAKE_BUILD_TYPE=${Configuration}"
"-DCMAKE_PREFIX_PATH:PATH=${OBSDepPath}"
"-DCMAKE_INSTALL_PREFIX:PATH=${ADVSSDepPath}"
"-DPAHO_WITH_MQTT_C=ON"
)
Log-Information "Configuring paho.mqtt.cpp..."
Invoke-External cmake -S ${MqttPath} -B ${MqttBuildPath} @MqttCmakeArgs
$MqttCmakeArgs = @(
'--config', "${Configuration}"
)
if ( $VerbosePreference -eq 'Continue' ) {
$MqttCmakeArgs += ('--verbose')
}
Log-Information "Building paho.mqtt.cpp..."
Invoke-External cmake --build "${MqttBuildPath}" @MqttCmakeArgs
Log-Information "Install paho.mqtt.cpp..."
Invoke-External cmake --install "${MqttBuildPath}" --prefix "${ADVSSDepPath}" @MqttCmakeArgs
} }
Build Build

3
.gitmodules vendored
View File

@@ -34,3 +34,6 @@
[submodule "deps/jsoncons"] [submodule "deps/jsoncons"]
path = deps/jsoncons path = deps/jsoncons
url = https://github.com/danielaparker/jsoncons.git url = https://github.com/danielaparker/jsoncons.git
[submodule "deps/paho.mqtt.cpp"]
path = deps/paho.mqtt.cpp
url = https://github.com/eclipse-paho/paho.mqtt.cpp.git

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.16...3.26) cmake_minimum_required(VERSION 3.21...3.26)
project(advanced-scene-switcher VERSION 1.0.0) project(advanced-scene-switcher VERSION 1.0.0)
@@ -103,8 +103,6 @@ target_sources(
lib/macro/macro-action-macro.hpp lib/macro/macro-action-macro.hpp
lib/macro/macro-action-queue.cpp lib/macro/macro-action-queue.cpp
lib/macro/macro-action-queue.hpp lib/macro/macro-action-queue.hpp
lib/macro/macro-action-script.cpp
lib/macro/macro-action-script.hpp
lib/macro/macro-action-variable.cpp lib/macro/macro-action-variable.cpp
lib/macro/macro-action-variable.hpp lib/macro/macro-action-variable.hpp
lib/macro/macro-action.cpp lib/macro/macro-action.cpp
@@ -117,8 +115,6 @@ target_sources(
lib/macro/macro-condition-macro.hpp lib/macro/macro-condition-macro.hpp
lib/macro/macro-condition-queue.cpp lib/macro/macro-condition-queue.cpp
lib/macro/macro-condition-queue.hpp lib/macro/macro-condition-queue.hpp
lib/macro/macro-condition-script.cpp
lib/macro/macro-condition-script.hpp
lib/macro/macro-condition-tempvar.cpp lib/macro/macro-condition-tempvar.cpp
lib/macro/macro-condition-tempvar.hpp lib/macro/macro-condition-tempvar.hpp
lib/macro/macro-condition-variable.cpp lib/macro/macro-condition-variable.cpp
@@ -139,14 +135,10 @@ target_sources(
lib/macro/macro-ref.hpp lib/macro/macro-ref.hpp
lib/macro/macro-run-button.cpp lib/macro/macro-run-button.cpp
lib/macro/macro-run-button.hpp lib/macro/macro-run-button.hpp
lib/macro/macro-script-handler.cpp
lib/macro/macro-script-handler.hpp
lib/macro/macro-segment-copy-paste.cpp lib/macro/macro-segment-copy-paste.cpp
lib/macro/macro-segment-copy-paste.hpp lib/macro/macro-segment-copy-paste.hpp
lib/macro/macro-segment-list.cpp lib/macro/macro-segment-list.cpp
lib/macro/macro-segment-list.hpp lib/macro/macro-segment-list.hpp
lib/macro/macro-segment-script.cpp
lib/macro/macro-segment-script.hpp
lib/macro/macro-segment-selection.cpp lib/macro/macro-segment-selection.cpp
lib/macro/macro-segment-selection.hpp lib/macro/macro-segment-selection.hpp
lib/macro/macro-segment.cpp lib/macro/macro-segment.cpp
@@ -223,17 +215,12 @@ target_sources(
lib/utils/plugin-state-helpers.hpp lib/utils/plugin-state-helpers.hpp
lib/utils/priority-helper.cpp lib/utils/priority-helper.cpp
lib/utils/priority-helper.hpp lib/utils/priority-helper.hpp
lib/utils/properties-view.cpp
lib/utils/properties-view.hpp
lib/utils/properties-view.moc.hpp
lib/utils/regex-config.cpp lib/utils/regex-config.cpp
lib/utils/regex-config.hpp lib/utils/regex-config.hpp
lib/utils/resizing-text-edit.cpp lib/utils/resizing-text-edit.cpp
lib/utils/resizing-text-edit.hpp lib/utils/resizing-text-edit.hpp
lib/utils/resource-table.cpp lib/utils/resource-table.cpp
lib/utils/resource-table.hpp lib/utils/resource-table.hpp
lib/utils/resource-table-hotkey-handler.cpp
lib/utils/resource-table-hotkey-handler.hpp
lib/utils/scene-selection.cpp lib/utils/scene-selection.cpp
lib/utils/scene-selection.hpp lib/utils/scene-selection.hpp
lib/utils/scene-switch-helpers.cpp lib/utils/scene-switch-helpers.cpp
@@ -428,6 +415,7 @@ else()
set_target_properties(${LIB_NAME} PROPERTIES PREFIX "") set_target_properties(${LIB_NAME} PROPERTIES PREFIX "")
set_target_properties(${LIB_NAME} PROPERTIES SOVERSION 1) set_target_properties(${LIB_NAME} PROPERTIES SOVERSION 1)
find_package(Qt6 REQUIRED COMPONENTS DBus)
find_package(X11 REQUIRED COMPONENTS Xss) find_package(X11 REQUIRED COMPONENTS Xss)
target_include_directories(${LIB_NAME} PRIVATE "${X11_INCLUDE_DIR}" target_include_directories(${LIB_NAME} PRIVATE "${X11_INCLUDE_DIR}"
"${X11_Xss_INCLUDE_PATH}") "${X11_Xss_INCLUDE_PATH}")
@@ -459,7 +447,8 @@ else()
) )
endif() endif()
target_include_directories(${LIB_NAME} PRIVATE "${PROC_INCLUDE_DIR}") target_include_directories(${LIB_NAME} PRIVATE "${PROC_INCLUDE_DIR}")
target_sources(${LIB_NAME} PRIVATE lib/linux/advanced-scene-switcher-nix.cpp) target_sources(${LIB_NAME} PRIVATE lib/linux/advanced-scene-switcher-nix.cpp
lib/linux/kwin-helpers.cpp)
# Don't include irrelevant folders into sources archive # Don't include irrelevant folders into sources archive
list(APPEND CPACK_SOURCE_IGNORE_FILES "\\.deps/.*") list(APPEND CPACK_SOURCE_IGNORE_FILES "\\.deps/.*")

View File

@@ -80,6 +80,8 @@ function(set_target_properties_plugin target)
configure_file(cmake/windows/resources/installer-Windows.iss.in configure_file(cmake/windows/resources/installer-Windows.iss.in
"${CMAKE_CURRENT_BINARY_DIR}/installer-Windows.generated.iss") "${CMAKE_CURRENT_BINARY_DIR}/installer-Windows.generated.iss")
configure_file(data/res/images/logo.ico
"${CMAKE_CURRENT_BINARY_DIR}/installer.ico" COPYONLY)
configure_file(cmake/windows/resources/resource.rc.in configure_file(cmake/windows/resources/resource.rc.in
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.rc") "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.rc")

View File

@@ -20,6 +20,8 @@ OutputBaseFilename={#MyAppName}-{#MyAppVersion}-Windows-Installer
Compression=lzma Compression=lzma
SolidCompression=yes SolidCompression=yes
DirExistsWarning=no DirExistsWarning=no
SetupIconFile=installer.ico
UninstallDisplayIcon={app}\data\obs-plugins\advanced-scene-switcher\res\images\logo.ico
[Languages] [Languages]
Name: "english"; MessagesFile: "compiler:Default.isl" Name: "english"; MessagesFile: "compiler:Default.isl"

View File

@@ -40,7 +40,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exportieren"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importieren" AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importieren"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportiere Erweiterter Automatischer Szenenwechsler Einstellungen zu Datei ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportiere Erweiterter Automatischer Szenenwechsler Einstellungen zu Datei ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Exportiere Erweiterter Automatischer Szenenwechsler Einstellungen von Datei ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Exportiere Erweiterter Automatischer Szenenwechsler Einstellungen von Datei ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text Dateien (*.txt)" AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text Dateien (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Importieren der Einstellungen ist fehlgeschlagen" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Importieren der Einstellungen ist fehlgeschlagen"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Einstellungen wurden erfolgreich importiert" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Einstellungen wurden erfolgreich importiert"
AdvSceneSwitcher.generalTab.priority.fileContent="Datei Inhalt" AdvSceneSwitcher.generalTab.priority.fileContent="Datei Inhalt"
@@ -194,12 +194,12 @@ AdvSceneSwitcher.condition.video.modelLoadFail="Modelldaten konnten nicht gelade
AdvSceneSwitcher.condition.video.type.main="OBS's Haupt-Ausgabe" AdvSceneSwitcher.condition.video.type.main="OBS's Haupt-Ausgabe"
AdvSceneSwitcher.condition.video.type.source="Quelle" AdvSceneSwitcher.condition.video.type.source="Quelle"
AdvSceneSwitcher.condition.video.type.scene="Szene" AdvSceneSwitcher.condition.video.type.scene="Szene"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}" AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Modelldaten (Haar-Kaskaden-Klassifikator): {{modelDataPath}}" AdvSceneSwitcher.condition.video.layout.modelPath="Modelldaten (Haar-Kaskaden-Klassifikator): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimale Anzahl von Nachbarn: {{minNeighbors}}" AdvSceneSwitcher.condition.video.layout.minNeighbor="Minimale Anzahl von Nachbarn: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzieren Sie die CPU-Belastung, indem Sie die Prüfung nur alle {{throttleCount}} Millisekunden" AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzieren Sie die CPU-Belastung, indem Sie die Prüfung nur alle {{throttleCount}} Millisekunden"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Kontrolle nur im Bereich durchführen" AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Kontrolle nur im Bereich durchführen"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}" AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.minSize="Minimale Größe:" AdvSceneSwitcher.condition.video.minSize="Minimale Größe:"
AdvSceneSwitcher.condition.video.maxSize="Maximale Größe:" AdvSceneSwitcher.condition.video.maxSize="Maximale Größe:"
AdvSceneSwitcher.condition.video.selectArea="Bereich auswählen" AdvSceneSwitcher.condition.video.selectArea="Bereich auswählen"
@@ -752,9 +752,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Starte/Stoppe den Erweite
AdvSceneSwitcher.hotkey.macro.pause="Pausiere Makro %1" AdvSceneSwitcher.hotkey.macro.pause="Pausiere Makro %1"
AdvSceneSwitcher.hotkey.macro.unpause="Makro %1 nicht mehr pausieren" AdvSceneSwitcher.hotkey.macro.unpause="Makro %1 nicht mehr pausieren"
AdvSceneSwitcher.hotkey.macro.togglePause="Pause von Makro %1 togglen" AdvSceneSwitcher.hotkey.macro.togglePause="Pause von Makro %1 togglen"
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Makro-Segmentauswahl nach oben verschieben" AdvSceneSwitcher.hotkey.macro.segment.up="Makro-Segmentauswahl nach oben verschieben"
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Makro-Segmentauswahl nach unten verschieben" AdvSceneSwitcher.hotkey.macro.segment.down="Makro-Segmentauswahl nach unten verschieben"
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Ausgewähltes Makro-Segment entfernen" AdvSceneSwitcher.hotkey.macro.segment.remove="Ausgewähltes Makro-Segment entfernen"
AdvSceneSwitcher.askBackup="Neue Version des Erweiterten Automatischen Szenenwechslers wurde erkannt.\nSoll ein Backup der alten Einstellungen angelegt werden?" AdvSceneSwitcher.askBackup="Neue Version des Erweiterten Automatischen Szenenwechslers wurde erkannt.\nSoll ein Backup der alten Einstellungen angelegt werden?"
AdvSceneSwitcher.askForMacro="Makro auswählen {{macroSelection}}" AdvSceneSwitcher.askForMacro="Makro auswählen {{macroSelection}}"

View File

@@ -42,6 +42,7 @@ AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailure="Display warni
AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailureMessage="<html><body>Loading of the following plugin libraries was unsuccessful, which could result in some Advanced Scene Switcher functions not being available:%1Check the OBS logs for details.<br>This message can be disabled on the General tab.</body></html>" AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailureMessage="<html><body>Loading of the following plugin libraries was unsuccessful, which could result in some Advanced Scene Switcher functions not being available:%1Check the OBS logs for details.<br>This message can be disabled on the General tab.</body></html>"
AdvSceneSwitcher.generalTab.generalBehavior.warnCorruptedInstallMessage="The plugin installation seems to be corrupted and might crash!\nPlease make sure the plugin was installed correctly!" AdvSceneSwitcher.generalTab.generalBehavior.warnCorruptedInstallMessage="The plugin installation seems to be corrupted and might crash!\nPlease make sure the plugin was installed correctly!"
AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs="Hide tabs which can be represented via macros" AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs="Hide tabs which can be represented via macros"
AdvSceneSwitcher.generalTab.generalBehavior.disableMacroWidgetCache="Disable macro widget caching"
AdvSceneSwitcher.generalTab.matchBehavior="Match behavior" AdvSceneSwitcher.generalTab.matchBehavior="Match behavior"
AdvSceneSwitcher.generalTab.priority="Priority" AdvSceneSwitcher.generalTab.priority="Priority"
AdvSceneSwitcher.generalTab.priority.description="Switching methods priority (Highest priority is at the top)" AdvSceneSwitcher.generalTab.priority.description="Switching methods priority (Highest priority is at the top)"
@@ -52,7 +53,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Export"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Import" AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Import"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Export Advanced Scene Switcher settings to file ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Export Advanced Scene Switcher settings to file ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Import Advanced Scene Switcher settings from file ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Import Advanced Scene Switcher settings from file ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text files (*.txt)" AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text files (*.txt);;JSON files (*.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Advanced Scene Switcher failed to import settings" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Advanced Scene Switcher failed to import settings"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Advanced Scene Switcher settings imported successfully" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Advanced Scene Switcher settings imported successfully"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportSensitiveDataWarning="Warning:\nThe exported data might contain sensitive information!" AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportSensitiveDataWarning="Warning:\nThe exported data might contain sensitive information!"
@@ -132,6 +133,18 @@ AdvSceneSwitcher.twitchConnectionTab.no="No"
AdvSceneSwitcher.twitchConnectionTab.removeSingleConnectionPopup.text="Are you sure you want to remove \"%1\"?" AdvSceneSwitcher.twitchConnectionTab.removeSingleConnectionPopup.text="Are you sure you want to remove \"%1\"?"
AdvSceneSwitcher.twitchConnectionTab.removeMultipleConnectionsPopup.text="Are you sure you want to remove %1 Twitch connections?" AdvSceneSwitcher.twitchConnectionTab.removeMultipleConnectionsPopup.text="Are you sure you want to remove %1 Twitch connections?"
# MQTT Connections Tab
AdvSceneSwitcher.mqttConnectionTab.title="MQTT Connections"
AdvSceneSwitcher.mqttConnectionTab.help="MQTT connections can be used to communicate with other devices.\n\nClick on the highlighted plus symbol to add a new connection."
AdvSceneSwitcher.mqttConnectionTab.mqttonnectionAddButton.tooltip="Add new MQTT connection"
AdvSceneSwitcher.mqttConnectionTab.mqttConnectionRemoveButton.tooltip="Remove selected MQTT connections"
AdvSceneSwitcher.mqttConnectionTab.name.header="Name"
AdvSceneSwitcher.mqttConnectionTab.address.header="Address"
AdvSceneSwitcher.mqttConnectionTab.topics.header="Topic subscription count"
AdvSceneSwitcher.mqttConnectionTab.status.header="Status"
AdvSceneSwitcher.mqttConnectionTab.removeSingleConnectionPopup.text="Are you sure you want to remove \"%1\"?"
AdvSceneSwitcher.mqttConnectionTab.removeMultipleConnectionsPopup.text="Are you sure you want to remove %1 connections?"
# Macro Tab # Macro Tab
AdvSceneSwitcher.macroTab.title="Macro" AdvSceneSwitcher.macroTab.title="Macro"
AdvSceneSwitcher.macroTab.macros="Macros" AdvSceneSwitcher.macroTab.macros="Macros"
@@ -203,7 +216,7 @@ AdvSceneSwitcher.macroTab.newMacroCheckInParallel="Evaluate conditions of new ma
AdvSceneSwitcher.macroTab.checkInParallel.tooltip="If this option is not enabled, this macro's conditions will be evaluated after the preceeding macro's condition check has completed.\nSo, if there are three macros - Macro A, Macro B, and Macro C - in the macro list the order the conditions in are evaluated is:\n • Macro A's conditions\n • Macro B's conditions\n • Macro C's conditions\nIf this option is enabled, the order might differ.\nEnabling this option can be useful for scenarios in which you have multiple long running condition checks, which you don't want to result in \"blocking\" other macros." AdvSceneSwitcher.macroTab.checkInParallel.tooltip="If this option is not enabled, this macro's conditions will be evaluated after the preceeding macro's condition check has completed.\nSo, if there are three macros - Macro A, Macro B, and Macro C - in the macro list the order the conditions in are evaluated is:\n • Macro A's conditions\n • Macro B's conditions\n • Macro C's conditions\nIf this option is enabled, the order might differ.\nEnabling this option can be useful for scenarios in which you have multiple long running condition checks, which you don't want to result in \"blocking\" other macros."
AdvSceneSwitcher.macroTab.saveSettingsOnMacroChange="Save settings when switching between macros" AdvSceneSwitcher.macroTab.saveSettingsOnMacroChange="Save settings when switching between macros"
AdvSceneSwitcher.macroTab.saveSettingsOnMacroChange.tooltip="Saving the settings can be an expensive operation if you are working with a very large scene collection.\nIn this case, it might make sense to disable this option." AdvSceneSwitcher.macroTab.saveSettingsOnMacroChange.tooltip="Saving the settings can be an expensive operation if you are working with a very large scene collection.\nIn this case, it might make sense to disable this option."
AdvSceneSwitcher.macroTab.currentCheckInParallel="Evaluate conditions of selected macro in parallel to other macros" AdvSceneSwitcher.macroTab.currentCheckInParallel="Evaluate conditions of selected macro in parallel to other macros (Experimental)"
AdvSceneSwitcher.macroTab.currentRegisterHotkeys="Register hotkeys to control the pause state of selected macro" AdvSceneSwitcher.macroTab.currentRegisterHotkeys="Register hotkeys to control the pause state of selected macro"
AdvSceneSwitcher.macroTab.currentUseShortCircuitEvaluation="Enable short circuit evaluation of macro conditions for currently selected macro" AdvSceneSwitcher.macroTab.currentUseShortCircuitEvaluation="Enable short circuit evaluation of macro conditions for currently selected macro"
AdvSceneSwitcher.macroTab.shortCircuit.tooltip="Enabling short circuit evaluation might improve the performance, as some condition checks are skipped, if the overall macro cannot be evaluated to \"true\" anymore.\nHowever, please note that condition checks, which are skipped over, will also not update their duration modifier checks." AdvSceneSwitcher.macroTab.shortCircuit.tooltip="Enabling short circuit evaluation might improve the performance, as some condition checks are skipped, if the overall macro cannot be evaluated to \"true\" anymore.\nHowever, please note that condition checks, which are skipped over, will also not update their duration modifier checks."
@@ -311,7 +324,7 @@ AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="During transi
AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}{{regex}}" AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}{{regex}}"
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}" AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
AdvSceneSwitcher.condition.window="Window" AdvSceneSwitcher.condition.window="Window"
AdvSceneSwitcher.condition.window.entry.window="{{checkTitle}}Window title matches{{windowRegex}}{{windows}}" AdvSceneSwitcher.condition.window.entry.window="{{checkTitle}}Window title matches{{windows}}{{windowRegex}}"
AdvSceneSwitcher.condition.window.entry.fullscreen="{{fullscreen}}Window is fullscreen" AdvSceneSwitcher.condition.window.entry.fullscreen="{{fullscreen}}Window is fullscreen"
AdvSceneSwitcher.condition.window.entry.maximized="{{maximized}}Window is maximized" AdvSceneSwitcher.condition.window.entry.maximized="{{maximized}}Window is maximized"
AdvSceneSwitcher.condition.window.entry.focused="{{focused}}Window is focused" AdvSceneSwitcher.condition.window.entry.focused="{{focused}}Window is focused"
@@ -380,6 +393,13 @@ AdvSceneSwitcher.condition.video.patternMatchSuccessFullImage="Full image matche
AdvSceneSwitcher.condition.video.objectMatchFail="Object was not found!" AdvSceneSwitcher.condition.video.objectMatchFail="Object was not found!"
AdvSceneSwitcher.condition.video.objectMatchSuccess="Object is highlighted in red" AdvSceneSwitcher.condition.video.objectMatchSuccess="Object is highlighted in red"
AdvSceneSwitcher.condition.video.ocrMatchSuccess="Detected text:\n\n%1" AdvSceneSwitcher.condition.video.ocrMatchSuccess="Detected text:\n\n%1"
AdvSceneSwitcher.condition.video.ocrMatchFail="Could not detect any text!"
AdvSceneSwitcher.condition.video.ocrUseConfigFile="Use custom tesseract config file"
AdvSceneSwitcher.condition.video.ocrOpenConfigFile="Open"
AdvSceneSwitcher.condition.video.ocrOpenConfig.createFailed="Could not create the config file!"
AdvSceneSwitcher.condition.video.ocrOpenConfig.openFailed="Could not open the config file!"
AdvSceneSwitcher.condition.video.ocrConfigReload="Reload configuration file"
AdvSceneSwitcher.condition.video.ocrConfigHint="Tesseract config files consist of lines with parameter-value pairs (space separated).\nFor example:\n\ntessedit_char_blacklist\t\t\t\t\"abc\"\nlanguage_model_penalty_non_dict_word\t0"
AdvSceneSwitcher.condition.video.modelLoadFail="Model data could not be loaded!" AdvSceneSwitcher.condition.video.modelLoadFail="Model data could not be loaded!"
AdvSceneSwitcher.condition.video.selectColor="Select Color" AdvSceneSwitcher.condition.video.selectColor="Select Color"
AdvSceneSwitcher.condition.video.ocrMode.singleColumn="Single column of text of variable sizes" AdvSceneSwitcher.condition.video.ocrMode.singleColumn="Single column of text of variable sizes"
@@ -399,16 +419,18 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="How similar
AdvSceneSwitcher.condition.video.type.main="OBS's main output" AdvSceneSwitcher.condition.video.type.main="OBS's main output"
AdvSceneSwitcher.condition.video.type.source="Source" AdvSceneSwitcher.condition.video.type.source="Source"
AdvSceneSwitcher.condition.video.type.scene="Scene" AdvSceneSwitcher.condition.video.type.scene="Scene"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}" AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Model data (haar cascade classifier):{{modelDataPath}}" AdvSceneSwitcher.condition.video.layout.modelPath="Model data (haar cascade classifier):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimum neighbors:{{minNeighbors}}" AdvSceneSwitcher.condition.video.layout.minNeighbor="Minimum neighbors:{{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduce CPU load by performing check only every{{throttleCount}}milliseconds" AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduce CPU load by performing check only every{{throttleCount}}milliseconds"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Perform check only in area" AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Perform check only in area"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}" AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.entry.orcColorPick="Check for text color:{{textColor}}{{selectColor}}" AdvSceneSwitcher.condition.video.layout.ocrColorPick="Check for text color:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="Check for text type:{{textType}}" AdvSceneSwitcher.condition.video.layout.ocrTextType="Check for text type:{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="Check for language:{{languageCode}}" AdvSceneSwitcher.condition.video.layout.ocrBaseDir="Tesseract base directory:{{tesseractBaseDir}}"
AdvSceneSwitcher.condition.video.entry.color="Check for color:{{color}}{{selectColor}}" AdvSceneSwitcher.condition.video.layout.ocrLanguage="Check for language:{{languageCode}}"
AdvSceneSwitcher.condition.video.layout.ocrConfig="Config file:{{configFile}}{{openConfigFile}}{{reloadConfig}}{{configFileHint}}"
AdvSceneSwitcher.condition.video.layout.color="Check for color:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="Minimum size:" AdvSceneSwitcher.condition.video.minSize="Minimum size:"
AdvSceneSwitcher.condition.video.maxSize="Maximum size:" AdvSceneSwitcher.condition.video.maxSize="Maximum size:"
AdvSceneSwitcher.condition.video.selectArea="Select area" AdvSceneSwitcher.condition.video.selectArea="Select area"
@@ -485,6 +507,7 @@ AdvSceneSwitcher.condition.source.type.showing="Is showing"
AdvSceneSwitcher.condition.source.type.settingsMatch="Settings match" AdvSceneSwitcher.condition.source.type.settingsMatch="Settings match"
AdvSceneSwitcher.condition.source.type.settingsChanged="Settings changed" AdvSceneSwitcher.condition.source.type.settingsChanged="Settings changed"
AdvSceneSwitcher.condition.source.type.individualSettingMatches="Setting value matches" AdvSceneSwitcher.condition.source.type.individualSettingMatches="Setting value matches"
AdvSceneSwitcher.condition.source.type.individualSettingListSelectionMatches="Settings value list selection matches"
AdvSceneSwitcher.condition.source.type.individualSettingChanged="Setting value changed" AdvSceneSwitcher.condition.source.type.individualSettingChanged="Setting value changed"
AdvSceneSwitcher.condition.source.type.width="Width" AdvSceneSwitcher.condition.source.type.width="Width"
AdvSceneSwitcher.condition.source.type.height="Height" AdvSceneSwitcher.condition.source.type.height="Height"
@@ -508,6 +531,7 @@ AdvSceneSwitcher.condition.filter.type.showing="Is disabled"
AdvSceneSwitcher.condition.filter.type.settingsMatch="Settings match" AdvSceneSwitcher.condition.filter.type.settingsMatch="Settings match"
AdvSceneSwitcher.condition.filter.type.settingsChanged="Settings changed" AdvSceneSwitcher.condition.filter.type.settingsChanged="Settings changed"
AdvSceneSwitcher.condition.filter.type.individualSettingMatches="Settings value matches" AdvSceneSwitcher.condition.filter.type.individualSettingMatches="Settings value matches"
AdvSceneSwitcher.condition.filter.type.individualSettingListSelectionMatches="Settings value list selection matches"
AdvSceneSwitcher.condition.filter.type.individualSettingChanged="Settings value changed" AdvSceneSwitcher.condition.filter.type.individualSettingChanged="Settings value changed"
AdvSceneSwitcher.condition.filter.refresh="Refresh" AdvSceneSwitcher.condition.filter.refresh="Refresh"
AdvSceneSwitcher.condition.filter.refresh.tooltip="Repopulate the filter settings selection with the settings of the filter which's name matches the variable value." AdvSceneSwitcher.condition.filter.refresh.tooltip="Repopulate the filter settings selection with the settings of the filter which's name matches the variable value."
@@ -708,6 +732,8 @@ AdvSceneSwitcher.condition.twitch.type.polling.channel.live="Stream is currently
AdvSceneSwitcher.condition.twitch.type.polling.channel.title="Current title matches" AdvSceneSwitcher.condition.twitch.type.polling.channel.title="Current title matches"
AdvSceneSwitcher.condition.twitch.type.polling.channel.category="Current category is" AdvSceneSwitcher.condition.twitch.type.polling.channel.category="Current category is"
AdvSceneSwitcher.condition.twitch.type.chat.message="Chat message received" AdvSceneSwitcher.condition.twitch.type.chat.message="Chat message received"
AdvSceneSwitcher.condition.twitch.type.chat.messageRemoved="Single chat message removed"
AdvSceneSwitcher.condition.twitch.type.chat.cleared="All messages of user or channel cleared"
AdvSceneSwitcher.condition.twitch.type.chat.properties="Chat message properties:" AdvSceneSwitcher.condition.twitch.type.chat.properties="Chat message properties:"
AdvSceneSwitcher.condition.twitch.type.chat.properties.select="Select chat message property:" AdvSceneSwitcher.condition.twitch.type.chat.properties.select="Select chat message property:"
AdvSceneSwitcher.condition.twitch.type.chat.properties.firstMessage="Is first message" AdvSceneSwitcher.condition.twitch.type.chat.properties.firstMessage="Is first message"
@@ -774,9 +800,12 @@ AdvSceneSwitcher.condition.streamDeck.stopListen="Stop listening"
AdvSceneSwitcher.condition.streamDeck.pluginDownload="<html><head/><body><p>The Stream Deck plugin can be found <a href=\"https://github.com/WarmUpTill/advanced-scene-switcher-streamdeck-plugin/releases\"><span style=\" text-decoration: underline; color:#268bd2;\">here on GitHub</span></a>.</p></body></html>" AdvSceneSwitcher.condition.streamDeck.pluginDownload="<html><head/><body><p>The Stream Deck plugin can be found <a href=\"https://github.com/WarmUpTill/advanced-scene-switcher-streamdeck-plugin/releases\"><span style=\" text-decoration: underline; color:#268bd2;\">here on GitHub</span></a>.</p></body></html>"
AdvSceneSwitcher.condition.gameCapture="Game capture" AdvSceneSwitcher.condition.gameCapture="Game capture"
AdvSceneSwitcher.condition.gameCapture.entry="{{sources}}hooked a game." AdvSceneSwitcher.condition.gameCapture.entry="{{sources}}hooked a game."
AdvSceneSwitcher.condition.screenshot="Screenshot" AdvSceneSwitcher.condition.screenshot="Screenshot"
AdvSceneSwitcher.condition.screenshot.entry="A screenshot was taken" AdvSceneSwitcher.condition.screenshot.entry="A screenshot was taken"
AdvSceneSwitcher.condition.mqtt="MQTT"
AdvSceneSwitcher.condition.mqtt.layout.match="Message was received from{{connection}} which matches{{regex}}:"
AdvSceneSwitcher.condition.mqtt.layout.listen="Set message selection to incoming message:{{listenButton}}"
AdvSceneSwitcher.condition.script="Script"
# Macro Actions # Macro Actions
AdvSceneSwitcher.action.unknown="Unknown action" AdvSceneSwitcher.action.unknown="Unknown action"
@@ -860,6 +889,7 @@ AdvSceneSwitcher.action.filter.entry="On{{sources}}{{actions}}{{filters}}{{refre
AdvSceneSwitcher.action.filter.entry.settings="{{settings}}{{settingsInputMethod}}{{settingValue}}{{tempVar}}" AdvSceneSwitcher.action.filter.entry.settings="{{settings}}{{settingsInputMethod}}{{settingValue}}{{tempVar}}"
AdvSceneSwitcher.action.filter.getSettings="Get current settings" AdvSceneSwitcher.action.filter.getSettings="Get current settings"
AdvSceneSwitcher.action.filter.inputMethod.individualManual="Set to fixed value" AdvSceneSwitcher.action.filter.inputMethod.individualManual="Set to fixed value"
AdvSceneSwitcher.action.filter.inputMethod.individualListEntryManual="Set to list entry"
AdvSceneSwitcher.action.filter.inputMethod.individualTempvar="Set to macro property" AdvSceneSwitcher.action.filter.inputMethod.individualTempvar="Set to macro property"
AdvSceneSwitcher.action.filter.inputMethod.json="Set setting JSON string" AdvSceneSwitcher.action.filter.inputMethod.json="Set setting JSON string"
AdvSceneSwitcher.action.source="Source" AdvSceneSwitcher.action.source="Source"
@@ -890,6 +920,7 @@ AdvSceneSwitcher.action.source.deinterlaceMode.yadif2x="Yadif 2x"
AdvSceneSwitcher.action.source.deinterlaceOrder.topFieldFirst="Top Field First" AdvSceneSwitcher.action.source.deinterlaceOrder.topFieldFirst="Top Field First"
AdvSceneSwitcher.action.source.deinterlaceOrder.bottomFieldFirst="Bottom Field First" AdvSceneSwitcher.action.source.deinterlaceOrder.bottomFieldFirst="Bottom Field First"
AdvSceneSwitcher.action.source.inputMethod.individualManual="Set to fixed value" AdvSceneSwitcher.action.source.inputMethod.individualManual="Set to fixed value"
AdvSceneSwitcher.action.source.inputMethod.individualListEntryManual="Set to list entry"
AdvSceneSwitcher.action.source.inputMethod.individualTempvar="Set to macro property" AdvSceneSwitcher.action.source.inputMethod.individualTempvar="Set to macro property"
AdvSceneSwitcher.action.source.inputMethod.json="Set setting JSON string" AdvSceneSwitcher.action.source.inputMethod.json="Set setting JSON string"
AdvSceneSwitcher.action.source.refresh="Refresh" AdvSceneSwitcher.action.source.refresh="Refresh"
@@ -911,6 +942,7 @@ AdvSceneSwitcher.action.media.seek.percentage.label="Percentage of total duratio
AdvSceneSwitcher.action.macro="Macro" AdvSceneSwitcher.action.macro="Macro"
AdvSceneSwitcher.action.macro.type.pause="Pause" AdvSceneSwitcher.action.macro.type.pause="Pause"
AdvSceneSwitcher.action.macro.type.unpause="Unpause" AdvSceneSwitcher.action.macro.type.unpause="Unpause"
AdvSceneSwitcher.action.macro.type.togglePause="Toggle pause"
AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter" AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter"
AdvSceneSwitcher.action.macro.type.run="Run macro" AdvSceneSwitcher.action.macro.type.run="Run macro"
AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Do not consider condition state" AdvSceneSwitcher.action.macro.type.run.conditions.ignore="Do not consider condition state"
@@ -1069,7 +1101,7 @@ AdvSceneSwitcher.action.http.type.post="POST"
AdvSceneSwitcher.action.http.type.put="PUT" AdvSceneSwitcher.action.http.type.put="PUT"
AdvSceneSwitcher.action.http.type.patch="PATCH" AdvSceneSwitcher.action.http.type.patch="PATCH"
AdvSceneSwitcher.action.http.type.delete="DELETE" AdvSceneSwitcher.action.http.type.delete="DELETE"
AdvSceneSwitcher.action.http.layout.method="Send{{method}}to URL{{url}}at path{{path}}" AdvSceneSwitcher.action.http.layout.method="Send{{method}}to URL{{url}}"
AdvSceneSwitcher.action.http.layout.contentType="Content type:{{contentType}}" AdvSceneSwitcher.action.http.layout.contentType="Content type:{{contentType}}"
AdvSceneSwitcher.action.http.layout.timeout="Timeout:{{timeout}}seconds" AdvSceneSwitcher.action.http.layout.timeout="Timeout:{{timeout}}seconds"
AdvSceneSwitcher.action.http.entry.line1="Send{{method}}to{{url}}" AdvSceneSwitcher.action.http.entry.line1="Send{{method}}to{{url}}"
@@ -1208,6 +1240,24 @@ AdvSceneSwitcher.action.window.entry="{{actions}}{{windows}}{{regex}}"
AdvSceneSwitcher.action.log="Log" AdvSceneSwitcher.action.log="Log"
AdvSceneSwitcher.action.log.placeholder="My log message!" AdvSceneSwitcher.action.log.placeholder="My log message!"
AdvSceneSwitcher.action.log.entry="Write to OBS log:{{logMessage}}" AdvSceneSwitcher.action.log.entry="Write to OBS log:{{logMessage}}"
AdvSceneSwitcher.action.mqtt="MQTT"
AdvSceneSwitcher.action.mqtt.topic="Topic:"
AdvSceneSwitcher.action.mqtt.qos="QoS:"
AdvSceneSwitcher.action.mqtt.retain="Retained message:"
AdvSceneSwitcher.action.mqtt.layout="Send message to{{connection}}"
AdvSceneSwitcher.action.obsSetting="OBS setting"
AdvSceneSwitcher.action.obsSetting.action.setFPSType="Set FPS selection type to"
AdvSceneSwitcher.action.obsSetting.action.setFPSCommonValue="Set FPS common selection to"
AdvSceneSwitcher.action.obsSetting.action.setFPSIntegerValue="Set FPS integer selection to"
AdvSceneSwitcher.action.obsSetting.action.setFPSFractionNumeratorValue="Set fractional FPS numerator selection to"
AdvSceneSwitcher.action.obsSetting.action.setFPSFractionDenominatorValue="Set fractional FPS denominator selection to"
AdvSceneSwitcher.action.obsSetting.action.setBaseCanvasX="Set base resolution X value"
AdvSceneSwitcher.action.obsSetting.action.setBaseCanvasY="Set base resolution Y value"
AdvSceneSwitcher.action.obsSetting.action.setOutputCanvasX="Set output resolution X value"
AdvSceneSwitcher.action.obsSetting.action.setOutputCanvasY="Set output resolution Y value"
AdvSceneSwitcher.action.obsSetting.getCurrentValue="Get current value"
AdvSceneSwitcher.action.obsSettings.layout="{{actions}}{{fpsType}}{{fpsIntValue}}{{fpsStringValue}}{{canvasSizeValue}}{{getCurrentValue}}"
AdvSceneSwitcher.action.script="Script"
# Hotkey # Hotkey
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher" AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher"
@@ -1216,9 +1266,10 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Toggle Start/Stop for the
AdvSceneSwitcher.hotkey.macro.pause="Pause macro %1" AdvSceneSwitcher.hotkey.macro.pause="Pause macro %1"
AdvSceneSwitcher.hotkey.macro.unpause="Unpause macro %1" AdvSceneSwitcher.hotkey.macro.unpause="Unpause macro %1"
AdvSceneSwitcher.hotkey.macro.togglePause="Toggle pause of macro %1" AdvSceneSwitcher.hotkey.macro.togglePause="Toggle pause of macro %1"
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Move macro segment selection up" AdvSceneSwitcher.hotkey.macro.new="Add new macro"
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Move macro segment selection down" AdvSceneSwitcher.hotkey.macro.segment.up="Move macro segment selection up"
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Remove selected macro segment" AdvSceneSwitcher.hotkey.macro.segment.down="Move macro segment selection down"
AdvSceneSwitcher.hotkey.macro.segment.remove="Remove selected macro segment"
AdvSceneSwitcher.askBackup="Detected a new version of the Advanced Scene Switcher.\nShould a backup of the old settings be created?" AdvSceneSwitcher.askBackup="Detected a new version of the Advanced Scene Switcher.\nShould a backup of the old settings be created?"
AdvSceneSwitcher.askForMacro="Select macro{{macroSelection}}" AdvSceneSwitcher.askForMacro="Select macro{{macroSelection}}"
@@ -1364,6 +1415,35 @@ AdvSceneSwitcher.osc.message.type.false="False"
AdvSceneSwitcher.osc.message.type.infinity="Infinitum" AdvSceneSwitcher.osc.message.type.infinity="Infinitum"
AdvSceneSwitcher.osc.message.type.null="Nil" AdvSceneSwitcher.osc.message.type.null="Nil"
AdvSceneSwitcher.mqttConnection.startListen="Start listening"
AdvSceneSwitcher.mqttConnection.stopListen="Stop listening"
AdvSceneSwitcher.mqttConnection.select="--select connection--"
AdvSceneSwitcher.mqttConnection.add="Add new connection"
AdvSceneSwitcher.mqttConnection.configure="Configure connection settings"
AdvSceneSwitcher.mqttConnection.invalid="Invalid connection selection"
AdvSceneSwitcher.mqttConnection.name="Name:"
AdvSceneSwitcher.mqttConnection.address="Address:"
AdvSceneSwitcher.mqttConnection.username="Username:"
AdvSceneSwitcher.mqttConnection.password="Password:"
AdvSceneSwitcher.mqttConnection.reconnect="Reconnect automatically:"
AdvSceneSwitcher.mqttConnection.reconnectDelay="Automatically reconnect after:"
AdvSceneSwitcher.mqttConnection.connectOnStart="Connect on startup:"
AdvSceneSwitcher.mqttConnection.test="Test connection"
AdvSceneSwitcher.mqttConnection.status.connected="Connected!"
AdvSceneSwitcher.mqttConnection.status.connecting="Connecting ..."
AdvSceneSwitcher.mqttConnection.status.disconnected="Could not connect!"
AdvSceneSwitcher.mqttConnection.topic="Topic"
AdvSceneSwitcher.mqttConnection.qos="QoS"
AdvSceneSwitcher.mqttConnection.topics="Topic subscriptions:"
AdvSceneSwitcher.mqttConnection.inputWarning.emptyTopic="Topic cannot be empty."
AdvSceneSwitcher.mqttConnection.inputWarning.emptyTopic.title="Input Error"
AdvSceneSwitcher.mqttConnection.inputWarning.duplicateTopic="This topic already exists."
AdvSceneSwitcher.mqttConnection.inputWarning.duplicateTopic.title="Duplicate Topic"
AdvSceneSwitcher.mqttConnection.inputWarning.qosRange="QoS must be 0, 1, or 2."
AdvSceneSwitcher.mqttConnection.inputWarning.qosRange.title="Invalid QoS"
AdvSceneSwitcher.mqttConnection.add.layout="Add topic subscription{{topic}}with QoS{{QoS}}"
AdvSceneSwitcher.mqttConnection.add.title="Add MQTT Topic Subscription"
AdvSceneSwitcher.twitchToken.name="Account name:" AdvSceneSwitcher.twitchToken.name="Account name:"
AdvSceneSwitcher.twitchToken.nameNotAvailable="Account already in use" AdvSceneSwitcher.twitchToken.nameNotAvailable="Account already in use"
AdvSceneSwitcher.twitchToken.select="--select Twitch connection--" AdvSceneSwitcher.twitchToken.select="--select Twitch connection--"
@@ -1442,6 +1522,17 @@ AdvSceneSwitcher.twitch.selection.points.reward.tooltip.noPermission="Can't sele
AdvSceneSwitcher.twitch.selection.points.reward.tooltip.noChannel="Can't select points reward without entering a channel first!" AdvSceneSwitcher.twitch.selection.points.reward.tooltip.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.twitch.selection.points.reward.tooltip.error="Can't select points reward because Twitch responded with an error! Check OBS logs for more details."
AdvSceneSwitcher.script.type.inline="Inline"
AdvSceneSwitcher.script.type.file="File"
AdvSceneSwitcher.script.type.layout="Script type:{{scriptType}}"
AdvSceneSwitcher.script.language.python="Python"
AdvSceneSwitcher.script.language.lua="LUA"
AdvSceneSwitcher.script.language.select="--select language--"
AdvSceneSwitcher.script.language.layout="Script language:{{language}}"
AdvSceneSwitcher.script.file.open="Open"
AdvSceneSwitcher.script.file.open.failed="Could not open script file!"
AdvSceneSwitcher.script.file.layout="Script file:{{path}}{{open}}"
AdvSceneSwitcher.tempVar.select="--select value--" AdvSceneSwitcher.tempVar.select="--select value--"
AdvSceneSwitcher.tempVar.selectionInfo.lastValues="Last values:" AdvSceneSwitcher.tempVar.selectionInfo.lastValues="Last values:"
@@ -1835,6 +1926,24 @@ AdvSceneSwitcher.tempVar.twitch.is_turbo.chatReceive.description="'true' if the
AdvSceneSwitcher.tempVar.twitch.is_vip.chatReceive="Is chatter a VIP" AdvSceneSwitcher.tempVar.twitch.is_vip.chatReceive="Is chatter a VIP"
AdvSceneSwitcher.tempVar.twitch.is_vip.chatReceive.description="'true' if the chatter is a VIP in the channel, 'false' otherwise." AdvSceneSwitcher.tempVar.twitch.is_vip.chatReceive.description="'true' if the chatter is a VIP in the channel, 'false' otherwise."
AdvSceneSwitcher.tempVar.twitch.login.chatRemove="User login"
AdvSceneSwitcher.tempVar.twitch.login.chatRemove.description="The name of the user who sent the message."
AdvSceneSwitcher.tempVar.twitch.message.chatRemove="Chat message"
AdvSceneSwitcher.tempVar.twitch.message_id.chatRemove.description="The chat message that was removed."
AdvSceneSwitcher.tempVar.twitch.message_id.chatRemove="Chat message ID"
AdvSceneSwitcher.tempVar.twitch.message_id.chatRemove.description="The ID of the message in UUID format."
AdvSceneSwitcher.tempVar.twitch.timestamp.chatRemove="Chat message timestamp"
AdvSceneSwitcher.tempVar.twitch.timestamp.chatRemove.description="The UNIX timestamp."
AdvSceneSwitcher.tempVar.twitch.login.chatClear="User login"
AdvSceneSwitcher.tempVar.twitch.login.chatClear.description="The login name of the user whose messages were removed from the chat room because they were banned or put in a timeout."
AdvSceneSwitcher.tempVar.twitch.user_id.chatClear="User ID"
AdvSceneSwitcher.tempVar.twitch.user_id.chatClear.description="Optional.\nThe User ID of the user that was banned or put in a timeout.\nEmpty in case the complete chat was cleared."
AdvSceneSwitcher.tempVar.twitch.ban_duration.chatClear="Ban duration"
AdvSceneSwitcher.tempVar.twitch.ban_duration.chatClear.description="Set to zero if the complete chat was cleared or a user was banned indefinitely.\nIs set to non-zero value, if a user was put in a timeout.\nWill contain the duration of the timeout in seconds."
AdvSceneSwitcher.tempVar.twitch.timestamp.chatClear="Timestamp"
AdvSceneSwitcher.tempVar.twitch.timestamp.chatClear.description="The UNIX timestamp."
AdvSceneSwitcher.tempVar.twitch.user_login.chatJoin="User login" AdvSceneSwitcher.tempVar.twitch.user_login.chatJoin="User login"
AdvSceneSwitcher.tempVar.twitch.user_login.chatJoin.description="The user login of the person who joined the chat room." AdvSceneSwitcher.tempVar.twitch.user_login.chatJoin.description="The user login of the person who joined the chat room."
@@ -2066,6 +2175,11 @@ AdvSceneSwitcher.tempVar.http.body="Message body"
AdvSceneSwitcher.tempVar.http.error="Error" AdvSceneSwitcher.tempVar.http.error="Error"
AdvSceneSwitcher.tempVar.http.error.description="Empty when no error occurred.\nOther possible values:\n\n * Could not establish connection\n * Failed to bind IP address\n * Failed to read connection\n * Failed to write connection\n * Maximum redirect count exceeded\n * Connection handling canceled\n * SSL connection failed\n * SSL certificate loading failed\n * SSL server verification failed\n * Unsupported HTTP multipart boundary characters\n * Compression failed\n * Connection timed out\n * Proxy connection failed\n * Unknown" AdvSceneSwitcher.tempVar.http.error.description="Empty when no error occurred.\nOther possible values:\n\n * Could not establish connection\n * Failed to bind IP address\n * Failed to read connection\n * Failed to write connection\n * Maximum redirect count exceeded\n * Connection handling canceled\n * SSL connection failed\n * SSL certificate loading failed\n * SSL server verification failed\n * Unsupported HTTP multipart boundary characters\n * Compression failed\n * Connection timed out\n * Proxy connection failed\n * Unknown"
AdvSceneSwitcher.tempVar.mqtt.message="Message"
AdvSceneSwitcher.tempVar.cursor.x="Cursor position (X)"
AdvSceneSwitcher.tempVar.cursor.y="Cursor position (Y)"
AdvSceneSwitcher.selectScene="--select scene--" AdvSceneSwitcher.selectScene="--select scene--"
AdvSceneSwitcher.selectPreviousScene="Previous Scene" AdvSceneSwitcher.selectPreviousScene="Previous Scene"
AdvSceneSwitcher.selectCurrentScene="Current Scene" AdvSceneSwitcher.selectCurrentScene="Current Scene"
@@ -2185,13 +2299,12 @@ AdvSceneSwitcher.script.timeout="Script timeout:{{timeout}}"
# This secion is copied from the OBS locale files # This secion is copied from the OBS locale files
# commonly shared locale # OBS commonly shared locale
Browse="Browse" Browse="Browse"
Show="Show" Show="Show"
Hide="Hide" Hide="Hide"
# OBS properties window
# properties window
Basic.PropertiesWindow="Properties for '%1'" Basic.PropertiesWindow="Properties for '%1'"
Basic.PropertiesWindow.AutoSelectFormat="%1 (autoselect: %2)" Basic.PropertiesWindow.AutoSelectFormat="%1 (autoselect: %2)"
Basic.PropertiesWindow.SelectColor="Select color" Basic.PropertiesWindow.SelectColor="Select color"
@@ -2208,7 +2321,7 @@ Basic.PropertiesWindow.AddEditableListFiles="Add files to '%1'"
Basic.PropertiesWindow.AddEditableListEntry="Add entry to '%1'" Basic.PropertiesWindow.AddEditableListEntry="Add entry to '%1'"
Basic.PropertiesWindow.EditEditableListEntry="Edit entry from '%1'" Basic.PropertiesWindow.EditEditableListEntry="Edit entry from '%1'"
# properties view # OBS properties view
Basic.PropertiesView.FPS.Simple="Simple FPS Values" Basic.PropertiesView.FPS.Simple="Simple FPS Values"
Basic.PropertiesView.FPS.Rational="Rational FPS Values" Basic.PropertiesView.FPS.Rational="Rational FPS Values"
Basic.PropertiesView.FPS.ValidFPSRanges="Valid FPS Ranges:" Basic.PropertiesView.FPS.ValidFPSRanges="Valid FPS Ranges:"
@@ -2216,6 +2329,11 @@ Basic.PropertiesView.UrlButton.Text="Open this link in your default web browser?
Basic.PropertiesView.UrlButton.Text.Url="URL: %1" Basic.PropertiesView.UrlButton.Text.Url="URL: %1"
Basic.PropertiesView.UrlButton.OpenUrl="Open URL" Basic.PropertiesView.UrlButton.OpenUrl="Open URL"
# OBS settings
Basic.Settings.Video.FPSCommon="Common FPS Values"
Basic.Settings.Video.FPSInteger="Integer FPS Value"
Basic.Settings.Video.FPSFraction="Fractional FPS Value"
# Legacy tabs below - please don't waste your time adding translations for these :) # Legacy tabs below - please don't waste your time adding translations for these :)
# Transition Tab # Transition Tab
AdvSceneSwitcher.transitionTab.title="Transition" AdvSceneSwitcher.transitionTab.title="Transition"

View File

@@ -38,7 +38,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exportar"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importar" AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importar"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportar los ajustes para Advanced Scene Switcher ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportar los ajustes para Advanced Scene Switcher ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importar los ajustes para Advanced Scene Switcher ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importar los ajustes para Advanced Scene Switcher ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Archivos de texto (*.txt)" AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Archivos de texto (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="La importacion la configuracion de escenas fallo" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="La importacion la configuracion de escenas fallo"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Configuración de escenas importada correctamente" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Configuración de escenas importada correctamente"
AdvSceneSwitcher.generalTab.priority.fileContent="Contenido del archivo" AdvSceneSwitcher.generalTab.priority.fileContent="Contenido del archivo"
@@ -154,12 +154,12 @@ AdvSceneSwitcher.condition.video.patternMatchSuccess="El patrón está resaltado
AdvSceneSwitcher.condition.video.objectMatchFail="¡No se encontró el objeto!" AdvSceneSwitcher.condition.video.objectMatchFail="¡No se encontró el objeto!"
AdvSceneSwitcher.condition.video.objectMatchSuccess="El objeto está resaltado en rojo" AdvSceneSwitcher.condition.video.objectMatchSuccess="El objeto está resaltado en rojo"
AdvSceneSwitcher.condition.video.modelLoadFail="¡No se pudieron cargar los datos del modelo!" AdvSceneSwitcher.condition.video.modelLoadFail="¡No se pudieron cargar los datos del modelo!"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}" AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Datos del modelo (haar cascade classifier): {{modelDataPath}}" AdvSceneSwitcher.condition.video.layout.modelPath="Datos del modelo (haar cascade classifier): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Mínimo de vecinos: {{minNeighbors}}" AdvSceneSwitcher.condition.video.layout.minNeighbor="Mínimo de vecinos: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzca la carga de la CPU realizando una comprobación solo cada {{throttleCount}} milisegundos" AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzca la carga de la CPU realizando una comprobación solo cada {{throttleCount}} milisegundos"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Realizar comprobación solo en el área" AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Realizar comprobación solo en el área"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}Realizar comprobación solo en el área {{checkArea}} {{selectArea}}" AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}Realizar comprobación solo en el área {{checkArea}} {{selectArea}}"
AdvSceneSwitcher.condition.video.minSize="Tamaño mínimo:" AdvSceneSwitcher.condition.video.minSize="Tamaño mínimo:"
AdvSceneSwitcher.condition.video.maxSize="Tamaño máximo:" AdvSceneSwitcher.condition.video.maxSize="Tamaño máximo:"
AdvSceneSwitcher.condition.video.selectArea="Seleccionar área" AdvSceneSwitcher.condition.video.selectArea="Seleccionar área"
@@ -640,9 +640,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Alternar inicio / detenci
AdvSceneSwitcher.hotkey.macro.pause="Pausar macro %1" AdvSceneSwitcher.hotkey.macro.pause="Pausar macro %1"
AdvSceneSwitcher.hotkey.macro.unpause="Despausar macro %1" AdvSceneSwitcher.hotkey.macro.unpause="Despausar macro %1"
AdvSceneSwitcher.hotkey.macro.togglePause="Alternar pausa de macro %1" AdvSceneSwitcher.hotkey.macro.togglePause="Alternar pausa de macro %1"
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Mover selección de segmento de macro hacia arriba" AdvSceneSwitcher.hotkey.macro.segment.up="Mover selección de segmento de macro hacia arriba"
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Mover selección de segmento de macro hacia abajo" AdvSceneSwitcher.hotkey.macro.segment.down="Mover selección de segmento de macro hacia abajo"
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Eliminar segmento de macro seleccionado" AdvSceneSwitcher.hotkey.macro.segment.remove="Eliminar segmento de macro seleccionado"
AdvSceneSwitcher.askBackup="Se detectó una nueva versión de Advanced Scene Switcher.\n¿Crear una copia de seguridad de la configuración anterior?" AdvSceneSwitcher.askBackup="Se detectó una nueva versión de Advanced Scene Switcher.\n¿Crear una copia de seguridad de la configuración anterior?"
AdvSceneSwitcher.askForMacro="Select macro {{macroSelection}}" AdvSceneSwitcher.askForMacro="Select macro {{macroSelection}}"

View File

@@ -43,7 +43,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exporter"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importer" AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importer"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exporter les paramètres d'Advanced Scene Switcher vers un fichier ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exporter les paramètres d'Advanced Scene Switcher vers un fichier ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importer les paramètres d'Advanced Scene Switcher depuis un fichier ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importer les paramètres d'Advanced Scene Switcher depuis un fichier ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Fichiers texte (*.txt)" AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Fichiers texte (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="L'importation des paramètres d'Advanced Scene Switcher a échoué" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="L'importation des paramètres d'Advanced Scene Switcher a échoué"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Les paramètres d'Advanced Scene Switcher ont été importés avec succès" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Les paramètres d'Advanced Scene Switcher ont été importés avec succès"
AdvSceneSwitcher.generalTab.priority.fileContent="Contenu du fichier" AdvSceneSwitcher.generalTab.priority.fileContent="Contenu du fichier"
@@ -257,14 +257,14 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="À quel poi
AdvSceneSwitcher.condition.video.type.main="Sortie principale d'OBS" AdvSceneSwitcher.condition.video.type.main="Sortie principale d'OBS"
AdvSceneSwitcher.condition.video.type.source="Source" AdvSceneSwitcher.condition.video.type.source="Source"
AdvSceneSwitcher.condition.video.type.scene="Scène" AdvSceneSwitcher.condition.video.type.scene="Scène"
AdvSceneSwitcher.condition.video.entry.modelPath="Données du modèle (classificateur de cascade de Haar) :{{modelDataPath}}" AdvSceneSwitcher.condition.video.layout.modelPath="Données du modèle (classificateur de cascade de Haar) :{{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Nombre minimum de voisins :{{minNeighbors}}" AdvSceneSwitcher.condition.video.layout.minNeighbor="Nombre minimum de voisins :{{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Réduire la charge CPU en effectuant la vérification uniquement toutes les{{throttleCount}}millisecondes" AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Réduire la charge CPU en effectuant la vérification uniquement toutes les{{throttleCount}}millisecondes"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Effectuer la vérification uniquement dans la zone" AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Effectuer la vérification uniquement dans la zone"
AdvSceneSwitcher.condition.video.entry.orcColorPick="Vérifier la couleur du texte :{{textColor}}{{selectColor}}" AdvSceneSwitcher.condition.video.layout.ocrColorPick="Vérifier la couleur du texte :{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="Vérifier le type de texte :{{textType}}" AdvSceneSwitcher.condition.video.layout.ocrTextType="Vérifier le type de texte :{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="Vérifier la langue :{{languageCode}}" AdvSceneSwitcher.condition.video.layout.ocrLanguage="Vérifier la langue :{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.color="Vérifier la couleur :{{color}}{{selectColor}}" AdvSceneSwitcher.condition.video.layout.color="Vérifier la couleur :{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="Taille minimale :" AdvSceneSwitcher.condition.video.minSize="Taille minimale :"
AdvSceneSwitcher.condition.video.maxSize="Taille maximale :" AdvSceneSwitcher.condition.video.maxSize="Taille maximale :"
AdvSceneSwitcher.condition.video.selectArea="Sélectionner la zone" AdvSceneSwitcher.condition.video.selectArea="Sélectionner la zone"
@@ -920,9 +920,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Basculer le démarrage/ar
AdvSceneSwitcher.hotkey.macro.pause="Mettre en pause la macro %1" AdvSceneSwitcher.hotkey.macro.pause="Mettre en pause la macro %1"
AdvSceneSwitcher.hotkey.macro.unpause="Reprendre la macro %1" AdvSceneSwitcher.hotkey.macro.unpause="Reprendre la macro %1"
AdvSceneSwitcher.hotkey.macro.togglePause="Basculer la pause de la macro %1" AdvSceneSwitcher.hotkey.macro.togglePause="Basculer la pause de la macro %1"
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Déplacer la sélection du segment de macro vers le haut" AdvSceneSwitcher.hotkey.macro.segment.up="Déplacer la sélection du segment de macro vers le haut"
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Déplacer la sélection du segment de macro vers le bas" AdvSceneSwitcher.hotkey.macro.segment.down="Déplacer la sélection du segment de macro vers le bas"
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Supprimer le segment de macro sélectionné" AdvSceneSwitcher.hotkey.macro.segment.remove="Supprimer le segment de macro sélectionné"
AdvSceneSwitcher.askBackup="Une nouvelle version du commutateur de scènes avancé a été détectée.\nSouhaitez-vous créer une sauvegarde des anciens paramètres ?" AdvSceneSwitcher.askBackup="Une nouvelle version du commutateur de scènes avancé a été détectée.\nSouhaitez-vous créer une sauvegarde des anciens paramètres ?"
AdvSceneSwitcher.askForMacro="Sélectionnez la macro{{macroSelection}}" AdvSceneSwitcher.askForMacro="Sélectionnez la macro{{macroSelection}}"

View File

@@ -48,7 +48,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="エクスポート"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="インポート" AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="インポート"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="高機能シーンスイッチャーの設定をファイルにエクスポート..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="高機能シーンスイッチャーの設定をファイルにエクスポート..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="高機能シーンスイッチャーの設定をファイルからインポート..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="高機能シーンスイッチャーの設定をファイルからインポート..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="テキストファイル(*.txt)" AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="テキストファイル(*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="高機能シーンスイッチャーの設定インポートに失敗しました" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="高機能シーンスイッチャーの設定インポートに失敗しました"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="高機能シーンスイッチャーの設定が正常にインポートされました" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="高機能シーンスイッチャーの設定が正常にインポートされました"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportSensitiveDataWarning="警告:\nエクスポートされたデータにはセンシティブ情報が含まれている可能性があります" AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportSensitiveDataWarning="警告:\nエクスポートされたデータにはセンシティブ情報が含まれている可能性があります"
@@ -379,16 +379,14 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="一致と
AdvSceneSwitcher.condition.video.type.main="OBS's main output" AdvSceneSwitcher.condition.video.type.main="OBS's main output"
AdvSceneSwitcher.condition.video.type.source="ソース" AdvSceneSwitcher.condition.video.type.source="ソース"
AdvSceneSwitcher.condition.video.type.scene="シーン" AdvSceneSwitcher.condition.video.type.scene="シーン"
; AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}" AdvSceneSwitcher.condition.video.layout.modelPath="モデルデータ (そのカスケード分類子):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="モデルデータ (そのカスケード分類子):{{modelDataPath}}" AdvSceneSwitcher.condition.video.layout.minNeighbor="最小近傍数:{{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="最小近傍数:{{minNeighbors}}" AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}:{{throttleCount}}ミリ秒ごとにのみチェックを実行することでCPU負荷を軽減します"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}:{{throttleCount}}ミリ秒ごとにのみチェックを実行することでCPU負荷を軽減します" AdvSceneSwitcher.condition.video.layout.checkAreaEnable="エリア内のみチェックを実施"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="エリア内のみチェックを実施" AdvSceneSwitcher.condition.video.layout.ocrColorPick="テキストの色の確認:{{textColor}}{{selectColor}}"
; AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}" AdvSceneSwitcher.condition.video.layout.ocrTextType="テキストタイプの確認:{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcColorPick="テキストの色の確認:{{textColor}}{{selectColor}}" AdvSceneSwitcher.condition.video.layout.ocrLanguage="言語の確認:{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="テキストタイプの確認:{{textType}}" AdvSceneSwitcher.condition.video.layout.color="カラーを確認してください:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="言語の確認:{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.color="カラーを確認してください:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="最小サイズ:" AdvSceneSwitcher.condition.video.minSize="最小サイズ:"
AdvSceneSwitcher.condition.video.maxSize="最大サイズ:" AdvSceneSwitcher.condition.video.maxSize="最大サイズ:"
AdvSceneSwitcher.condition.video.selectArea="範囲指定" AdvSceneSwitcher.condition.video.selectArea="範囲指定"
@@ -1130,9 +1128,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="高機能シーンスイ
AdvSceneSwitcher.hotkey.macro.pause="マクロ %1 を一時停止します" AdvSceneSwitcher.hotkey.macro.pause="マクロ %1 を一時停止します"
AdvSceneSwitcher.hotkey.macro.unpause="マクロ %1 の一時停止を解除します" AdvSceneSwitcher.hotkey.macro.unpause="マクロ %1 の一時停止を解除します"
AdvSceneSwitcher.hotkey.macro.togglePause="マクロ %1 の一時停止を切り替えます" AdvSceneSwitcher.hotkey.macro.togglePause="マクロ %1 の一時停止を切り替えます"
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="マクロセグメント選択を上に移動" AdvSceneSwitcher.hotkey.macro.segment.up="マクロセグメント選択を上に移動"
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="マクロセグメント選択を下に移動" AdvSceneSwitcher.hotkey.macro.segment.down="マクロセグメント選択を下に移動"
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="選択したマクロセグメントを削除" AdvSceneSwitcher.hotkey.macro.segment.remove="選択したマクロセグメントを削除"
AdvSceneSwitcher.askBackup="高機能シーンスイッチャーの新しいバージョンが検出されました。\n古い設定のバックアップを作成する必要がありますか" AdvSceneSwitcher.askBackup="高機能シーンスイッチャーの新しいバージョンが検出されました。\n古い設定のバックアップを作成する必要がありますか"
AdvSceneSwitcher.askForMacro="マクロ選択{{macroSelection}}" AdvSceneSwitcher.askForMacro="マクロ選択{{macroSelection}}"

View File

@@ -48,7 +48,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Exportar"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importar" AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Importar"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportar configurações do Advanced Scene Switcher para arquivo ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Exportar configurações do Advanced Scene Switcher para arquivo ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importar configurações do Advanced Scene Switcher de arquivo ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Importar configurações do Advanced Scene Switcher de arquivo ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Arquivos de texto (*.txt)" AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Arquivos de texto (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="O Advanced Scene Switcher falhou ao importar configurações" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="O Advanced Scene Switcher falhou ao importar configurações"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Configurações do Advanced Scene Switcher importadas com sucesso" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Configurações do Advanced Scene Switcher importadas com sucesso"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportSensitiveDataWarning="Aviso:\nOs dados exportados podem conter informações sensíveis!" AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportSensitiveDataWarning="Aviso:\nOs dados exportados podem conter informações sensíveis!"
@@ -372,16 +372,16 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="Quão semel
AdvSceneSwitcher.condition.video.type.main="Saída principal do OBS" AdvSceneSwitcher.condition.video.type.main="Saída principal do OBS"
AdvSceneSwitcher.condition.video.type.source="Fonte" AdvSceneSwitcher.condition.video.type.source="Fonte"
AdvSceneSwitcher.condition.video.type.scene="Cena" AdvSceneSwitcher.condition.video.type.scene="Cena"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}" AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Dados do modelo (classificador em cascata haar):{{modelDataPath}}" AdvSceneSwitcher.condition.video.layout.modelPath="Dados do modelo (classificador em cascata haar):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Vizinhos mínimos:{{minNeighbors}}" AdvSceneSwitcher.condition.video.layout.minNeighbor="Vizinhos mínimos:{{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduzir carga de CPU realizando a verificação apenas a cada {{throttleCount}} milissegundos" AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}Reduzir carga de CPU realizando a verificação apenas a cada {{throttleCount}} milissegundos"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Realizar verificação apenas na área" AdvSceneSwitcher.condition.video.layout.checkAreaEnable="Realizar verificação apenas na área"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}" AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.entry.orcColorPick="Verificar cor do texto:{{textColor}}{{selectColor}}" AdvSceneSwitcher.condition.video.layout.ocrColorPick="Verificar cor do texto:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="Verificar tipo de texto:{{textType}}" AdvSceneSwitcher.condition.video.layout.ocrTextType="Verificar tipo de texto:{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="Verificar idioma:{{languageCode}}" AdvSceneSwitcher.condition.video.layout.ocrLanguage="Verificar idioma:{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.color="Verificar cor:{{color}}{{selectColor}}" AdvSceneSwitcher.condition.video.layout.color="Verificar cor:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="Tamanho mínimo:" AdvSceneSwitcher.condition.video.minSize="Tamanho mínimo:"
AdvSceneSwitcher.condition.video.maxSize="Tamanho máximo:" AdvSceneSwitcher.condition.video.maxSize="Tamanho máximo:"
AdvSceneSwitcher.condition.video.selectArea="Selecionar área" AdvSceneSwitcher.condition.video.selectArea="Selecionar área"
@@ -1111,9 +1111,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Alternar Iniciar/Parar pa
AdvSceneSwitcher.hotkey.macro.pause="Pausar macro %1" AdvSceneSwitcher.hotkey.macro.pause="Pausar macro %1"
AdvSceneSwitcher.hotkey.macro.unpause="Retomar macro %1" AdvSceneSwitcher.hotkey.macro.unpause="Retomar macro %1"
AdvSceneSwitcher.hotkey.macro.togglePause="Alternar pausa da macro %1" AdvSceneSwitcher.hotkey.macro.togglePause="Alternar pausa da macro %1"
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="Mover seleção de segmento de macro para cima" AdvSceneSwitcher.hotkey.macro.segment.up="Mover seleção de segmento de macro para cima"
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="Mover seleção de segmento de macro para baixo" AdvSceneSwitcher.hotkey.macro.segment.down="Mover seleção de segmento de macro para baixo"
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="Remover segmento de macro selecionado" AdvSceneSwitcher.hotkey.macro.segment.remove="Remover segmento de macro selecionado"
AdvSceneSwitcher.askBackup="Detectada uma nova versão do Advanced Scene Switcher.\nDeve ser criado um backup das configurações antigas?" AdvSceneSwitcher.askBackup="Detectada uma nova versão do Advanced Scene Switcher.\nDeve ser criado um backup das configurações antigas?"
AdvSceneSwitcher.askForMacro="Selecionar macro{{macroSelection}}" AdvSceneSwitcher.askForMacro="Selecionar macro{{macroSelection}}"

View File

@@ -36,7 +36,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Экспорт"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Импорт" AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Импорт"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Экспортировать настройки расширенного переключателя сцен в файл ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Экспортировать настройки расширенного переключателя сцен в файл ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Импортировать настройки Advanced Scene Switcher из файла ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Импортировать настройки Advanced Scene Switcher из файла ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Текстовые файлы (*.txt)" AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Текстовые файлы (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Advanced Scene Switcher не удалось импортировать настройки" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Advanced Scene Switcher не удалось импортировать настройки"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Настройки Advanced Scene Switcher импортированы успешно" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Настройки Advanced Scene Switcher импортированы успешно"
AdvSceneSwitcher.generalTab.priority.fileContent="Содержание файла" AdvSceneSwitcher.generalTab.priority.fileContent="Содержание файла"

View File

@@ -38,7 +38,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Dışa Aktar"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="İçe Aktar" AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="İçe Aktar"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Gelişmiş Sahne Değiştirici ayarlarını dosyaya aktar ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Gelişmiş Sahne Değiştirici ayarlarını dosyaya aktar ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Gelişmiş Sahne Değiştirici ayarlarını dosyadan içe aktar ..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Gelişmiş Sahne Değiştirici ayarlarını dosyadan içe aktar ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text dosyası (*.txt)" AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text dosyası (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Gelişmiş Sahne Değiştirici ayarları dosyadan içe aktarmakta başarısız oldu" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Gelişmiş Sahne Değiştirici ayarları dosyadan içe aktarmakta başarısız oldu"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Gelişmiş Sahne Değiştirici ayarları başarılı bir şekilde dosyadan içe aktarıldı" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Gelişmiş Sahne Değiştirici ayarları başarılı bir şekilde dosyadan içe aktarıldı"
AdvSceneSwitcher.generalTab.priority.fileContent="Dosya İçeriği" AdvSceneSwitcher.generalTab.priority.fileContent="Dosya İçeriği"
@@ -139,10 +139,10 @@ AdvSceneSwitcher.condition.video.screenshotFail="Kaynağın ekran görüntüsü
AdvSceneSwitcher.condition.video.patternMatchFail="Desen bulunamadı!" AdvSceneSwitcher.condition.video.patternMatchFail="Desen bulunamadı!"
AdvSceneSwitcher.condition.video.objectMatchFail="Nesne bulunamadı!" AdvSceneSwitcher.condition.video.objectMatchFail="Nesne bulunamadı!"
AdvSceneSwitcher.condition.video.modelLoadFail="Model verileri yüklenemedi!" AdvSceneSwitcher.condition.video.modelLoadFail="Model verileri yüklenemedi!"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}" AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Model verileri (haar kademeli sınıflandırıcı):{{modelDataPath}}" AdvSceneSwitcher.condition.video.layout.modelPath="Model verileri (haar kademeli sınıflandırıcı):{{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimum komşular: {{minNeighbors}}" AdvSceneSwitcher.condition.video.layout.minNeighbor="Minimum komşular: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}} Yalnızca her seferinde kontrol gerçekleştirerek CPU yükünü azaltın {{throttleCount}} millisaniyeler" AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}} Yalnızca her seferinde kontrol gerçekleştirerek CPU yükünü azaltın {{throttleCount}} millisaniyeler"
AdvSceneSwitcher.condition.stream="Yayınlama" AdvSceneSwitcher.condition.stream="Yayınlama"
AdvSceneSwitcher.condition.stream.state.start="Yayın çalışıyor" AdvSceneSwitcher.condition.stream.state.start="Yayın çalışıyor"
AdvSceneSwitcher.condition.stream.state.stop="Yayın durdu" AdvSceneSwitcher.condition.stream.state.stop="Yayın durdu"

View File

@@ -51,7 +51,7 @@ AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="导出设置"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="导入设置" AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="导入设置"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="导出高级场景切换器到文件..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="导出高级场景切换器到文件..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="导入高级场景切换器到文件..." AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="导入高级场景切换器到文件..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="文本文件 (*.txt)" AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="文本文件 (*.txt *.json)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="高级场景切换器导入设置失败" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="高级场景切换器导入设置失败"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="高级场景切换器导入设置成功" AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="高级场景切换器导入设置成功"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportSensitiveDataWarning="警告:\n导出的数据可能包含敏感信息!" AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportSensitiveDataWarning="警告:\n导出的数据可能包含敏感信息!"
@@ -395,16 +395,16 @@ AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="颜色与
AdvSceneSwitcher.condition.video.type.main="OBS的主输出" AdvSceneSwitcher.condition.video.type.main="OBS的主输出"
AdvSceneSwitcher.condition.video.type.source="源" AdvSceneSwitcher.condition.video.type.source="源"
AdvSceneSwitcher.condition.video.type.scene="场景" AdvSceneSwitcher.condition.video.type.scene="场景"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}" AdvSceneSwitcher.condition.video.layout="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="模型数据 (haar级联分类器): {{modelDataPath}}" AdvSceneSwitcher.condition.video.layout.modelPath="模型数据 (haar级联分类器): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="最小区域: {{minNeighbors}}" AdvSceneSwitcher.condition.video.layout.minNeighbor="最小区域: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}每隔{{throttleCount}} 毫秒,才执行一次检查,从而减少 CPU 负载." AdvSceneSwitcher.condition.video.layout.throttle="{{throttleEnable}}每隔{{throttleCount}} 毫秒,才执行一次检查,从而减少 CPU 负载."
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="仅在区域内执行检查" AdvSceneSwitcher.condition.video.layout.checkAreaEnable="仅在区域内执行检查"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}" AdvSceneSwitcher.condition.video.layout.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.entry.orcColorPick="文本检查颜色:{{textColor}}{{selectColor}}" AdvSceneSwitcher.condition.video.layout.ocrColorPick="文本检查颜色:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="文本检查类型:{{textType}}" AdvSceneSwitcher.condition.video.layout.ocrTextType="文本检查类型:{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="语言检查:{{languageCode}}" AdvSceneSwitcher.condition.video.layout.ocrLanguage="语言检查:{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.color="颜色检查:{{color}}{{selectColor}}" AdvSceneSwitcher.condition.video.layout.color="颜色检查:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="最小尺寸:" AdvSceneSwitcher.condition.video.minSize="最小尺寸:"
AdvSceneSwitcher.condition.video.maxSize="最大尺寸:" AdvSceneSwitcher.condition.video.maxSize="最大尺寸:"
AdvSceneSwitcher.condition.video.selectArea="选择区域" AdvSceneSwitcher.condition.video.selectArea="选择区域"
@@ -1189,9 +1189,9 @@ AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="切换(启动/停止)高
AdvSceneSwitcher.hotkey.macro.pause="停用宏 %1" AdvSceneSwitcher.hotkey.macro.pause="停用宏 %1"
AdvSceneSwitcher.hotkey.macro.unpause="启用宏 %1" AdvSceneSwitcher.hotkey.macro.unpause="启用宏 %1"
AdvSceneSwitcher.hotkey.macro.togglePause="切换(停用/启用)宏 %1" AdvSceneSwitcher.hotkey.macro.togglePause="切换(停用/启用)宏 %1"
AdvSceneSwitcher.hotkey.upMacroSegmentHotkey="上移选择宏" AdvSceneSwitcher.hotkey.macro.segment.up="上移选择宏"
AdvSceneSwitcher.hotkey.downMacroSegmentHotkey="下移选择宏" AdvSceneSwitcher.hotkey.macro.segment.down="下移选择宏"
AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey="删除选定的宏" AdvSceneSwitcher.hotkey.macro.segment.remove="删除选定的宏"
AdvSceneSwitcher.askBackup="检测到新版本的高级场景切换器。\n是否要创建旧版本的设置备份?" AdvSceneSwitcher.askBackup="检测到新版本的高级场景切换器。\n是否要创建旧版本的设置备份?"
AdvSceneSwitcher.askForMacro="选择宏 {{macroSelection}}" AdvSceneSwitcher.askForMacro="选择宏 {{macroSelection}}"

BIN
data/res/images/logo.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@@ -22,7 +22,7 @@ with this program. If not, see <https://www.gnu.org/licenses/>
#include <obs.h> #include <obs.h>
#define OBS_WEBSOCKET_API_VERSION 2 #define OBS_WEBSOCKET_API_VERSION 3
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -31,6 +31,8 @@ extern "C" {
typedef void *obs_websocket_vendor; typedef void *obs_websocket_vendor;
typedef void (*obs_websocket_request_callback_function)(obs_data_t *, typedef void (*obs_websocket_request_callback_function)(obs_data_t *,
obs_data_t *, void *); obs_data_t *, void *);
typedef void (*obs_websocket_event_callback_function)(uint64_t, const char *,
const char *, void *);
struct obs_websocket_request_response { struct obs_websocket_request_response {
unsigned int status_code; unsigned int status_code;
@@ -45,6 +47,11 @@ struct obs_websocket_request_callback {
void *priv_data; void *priv_data;
}; };
struct obs_websocket_event_callback {
obs_websocket_event_callback_function callback;
void *priv_data;
};
static proc_handler_t *_ph; static proc_handler_t *_ph;
/* ==================== INTERNAL API FUNCTIONS ==================== */ /* ==================== INTERNAL API FUNCTIONS ==================== */
@@ -123,7 +130,6 @@ obs_websocket_call_request(const char *request_type, obs_data_t *request_data
request_data_string = obs_data_get_json(request_data); request_data_string = obs_data_get_json(request_data);
calldata_t cd = {0, 0, 0, 0}; calldata_t cd = {0, 0, 0, 0};
calldata_set_string(&cd, "request_type", request_type); calldata_set_string(&cd, "request_type", request_type);
calldata_set_string(&cd, "request_data", request_data_string); calldata_set_string(&cd, "request_data", request_data_string);
@@ -152,6 +158,48 @@ static inline void obs_websocket_request_response_free(
bfree(response); bfree(response);
} }
// Register an event handler to receive obs-websocket events
static inline bool obs_websocket_register_event_callback(
obs_websocket_event_callback_function event_callback, void *priv_data)
{
if (!obs_websocket_ensure_ph())
return false;
struct obs_websocket_event_callback cb = {event_callback, priv_data};
calldata_t cd = {0, 0, 0, 0};
calldata_set_ptr(&cd, "callback", &cb);
proc_handler_call(_ph, "register_event_callback", &cd);
bool ret = calldata_bool(&cd, "success");
calldata_free(&cd);
return ret;
}
// Unregister an existing event handler
static inline bool obs_websocket_unregister_event_callback(
obs_websocket_event_callback_function event_callback, void *priv_data)
{
if (!obs_websocket_ensure_ph())
return false;
struct obs_websocket_event_callback cb = {event_callback, priv_data};
calldata_t cd = {0, 0, 0, 0};
calldata_set_ptr(&cd, "callback", &cb);
proc_handler_call(_ph, "unregister_event_callback", &cd);
bool ret = calldata_bool(&cd, "success");
calldata_free(&cd);
return ret;
}
/* ==================== VENDOR API FUNCTIONS ==================== */ /* ==================== VENDOR API FUNCTIONS ==================== */
// ALWAYS CALL ONLY VIA `obs_module_post_load()` CALLBACK! // ALWAYS CALL ONLY VIA `obs_module_post_load()` CALLBACK!
@@ -163,7 +211,6 @@ obs_websocket_register_vendor(const char *vendor_name)
return NULL; return NULL;
calldata_t cd = {0, 0, 0, 0}; calldata_t cd = {0, 0, 0, 0};
calldata_set_string(&cd, "name", vendor_name); calldata_set_string(&cd, "name", vendor_name);
proc_handler_call(_ph, "vendor_register", &cd); proc_handler_call(_ph, "vendor_register", &cd);
@@ -179,11 +226,10 @@ static inline bool obs_websocket_vendor_register_request(
obs_websocket_request_callback_function request_callback, obs_websocket_request_callback_function request_callback,
void *priv_data) void *priv_data)
{ {
calldata_t cd = {0, 0, 0, 0};
struct obs_websocket_request_callback cb = {request_callback, struct obs_websocket_request_callback cb = {request_callback,
priv_data}; priv_data};
calldata_t cd = {0, 0, 0, 0};
calldata_set_string(&cd, "type", request_type); calldata_set_string(&cd, "type", request_type);
calldata_set_ptr(&cd, "callback", &cb); calldata_set_ptr(&cd, "callback", &cb);
@@ -200,7 +246,6 @@ obs_websocket_vendor_unregister_request(obs_websocket_vendor vendor,
const char *request_type) const char *request_type)
{ {
calldata_t cd = {0, 0, 0, 0}; calldata_t cd = {0, 0, 0, 0};
calldata_set_string(&cd, "type", request_type); calldata_set_string(&cd, "type", request_type);
bool success = obs_websocket_vendor_run_simple_proc( bool success = obs_websocket_vendor_run_simple_proc(
@@ -217,7 +262,6 @@ static inline bool obs_websocket_vendor_emit_event(obs_websocket_vendor vendor,
obs_data_t *event_data) obs_data_t *event_data)
{ {
calldata_t cd = {0, 0, 0, 0}; calldata_t cd = {0, 0, 0, 0};
calldata_set_string(&cd, "type", event_name); calldata_set_string(&cd, "type", event_name);
calldata_set_ptr(&cd, "data", (void *)event_data); calldata_set_ptr(&cd, "data", (void *)event_data);

1
deps/paho.mqtt.cpp vendored Submodule

Submodule deps/paho.mqtt.cpp added at 165476b1dc

View File

@@ -181,8 +181,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QComboBox" name="logLevel"> <widget class="QComboBox" name="logLevel"/>
</widget>
</item> </item>
<item> <item>
<spacer name="horizontalSpacer_49"> <spacer name="horizontalSpacer_49">
@@ -295,6 +294,17 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
<widget class="QCheckBox" name="disableMacroWidgetCache">
<property name="text">
<string>AdvSceneSwitcher.generalTab.generalBehavior.disableMacroWidgetCache</string>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_26"> <layout class="QHBoxLayout" name="horizontalLayout_26">
<item> <item>

View File

@@ -11,6 +11,7 @@ namespace advss {
class MacroActionEdit; class MacroActionEdit;
class MacroConditionEdit; class MacroConditionEdit;
class MacroSegment;
class Duration; class Duration;
class SequenceWidget; class SequenceWidget;
struct SceneGroup; struct SceneGroup;
@@ -66,6 +67,7 @@ public slots:
void on_showTrayNotifications_stateChanged(int state); void on_showTrayNotifications_stateChanged(int state);
void on_uiHintsDisable_stateChanged(int state); void on_uiHintsDisable_stateChanged(int state);
void on_disableComboBoxFilter_stateChanged(int state); void on_disableComboBoxFilter_stateChanged(int state);
void on_disableMacroWidgetCache_stateChanged(int state);
void on_warnPluginLoadFailure_stateChanged(int state); void on_warnPluginLoadFailure_stateChanged(int state);
void on_hideLegacyTabs_stateChanged(int state); void on_hideLegacyTabs_stateChanged(int state);
void on_priorityUp_clicked(); void on_priorityUp_clicked();
@@ -191,7 +193,7 @@ signals:
void MacroRemoved(const QString &name); void MacroRemoved(const QString &name);
void MacroRenamed(const QString &oldName, const QString &newName); void MacroRenamed(const QString &oldName, const QString &newName);
void MacroSegmentOrderChanged(); void MacroSegmentOrderChanged();
void SegmentTempVarsChanged(); void SegmentTempVarsChanged(MacroSegment *);
void HighlightMacrosChanged(bool value); void HighlightMacrosChanged(bool value);
void ConnectionAdded(const QString &); void ConnectionAdded(const QString &);

View File

@@ -205,6 +205,16 @@ void AdvSceneSwitcher::on_disableComboBoxFilter_stateChanged(int state)
FilterComboBox::SetFilterBehaviourEnabled(!state); FilterComboBox::SetFilterBehaviourEnabled(!state);
} }
void AdvSceneSwitcher::on_disableMacroWidgetCache_stateChanged(int state)
{
if (loading) {
return;
}
switcher->disableMacroWidgetCache = state;
MacroSegmentList::SetCachingEnabled(!state);
}
void AdvSceneSwitcher::on_warnPluginLoadFailure_stateChanged(int state) void AdvSceneSwitcher::on_warnPluginLoadFailure_stateChanged(int state)
{ {
if (loading) { if (loading) {
@@ -275,12 +285,15 @@ static bool containsSensitiveData(obs_data_t *data)
obs_data_get_array(data, "twitchConnections"); obs_data_get_array(data, "twitchConnections");
OBSDataArrayAutoRelease websocketConnections = OBSDataArrayAutoRelease websocketConnections =
obs_data_get_array(data, "websocketConnections"); obs_data_get_array(data, "websocketConnections");
OBSDataArrayAutoRelease mqttConnections =
obs_data_get_array(data, "mqttConnections");
auto isNotEmpty = [](obs_data_array *array) { auto isNotEmpty = [](obs_data_array *array) {
return obs_data_array_count(array) > 0; return obs_data_array_count(array) > 0;
}; };
return isNotEmpty(twitchTokens) || isNotEmpty(websocketConnections); return isNotEmpty(twitchTokens) || isNotEmpty(websocketConnections) ||
isNotEmpty(mqttConnections);
} }
void AdvSceneSwitcher::on_exportSettings_clicked() void AdvSceneSwitcher::on_exportSettings_clicked()
@@ -537,6 +550,8 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
obs_data_set_bool(obj, "disableHints", disableHints); obs_data_set_bool(obj, "disableHints", disableHints);
obs_data_set_bool(obj, "disableFilterComboboxFilter", obs_data_set_bool(obj, "disableFilterComboboxFilter",
disableFilterComboboxFilter); disableFilterComboboxFilter);
obs_data_set_bool(obj, "disableMacroWidgetCache",
disableMacroWidgetCache);
obs_data_set_bool(obj, "warnPluginLoadFailure", warnPluginLoadFailure); obs_data_set_bool(obj, "warnPluginLoadFailure", warnPluginLoadFailure);
obs_data_set_bool(obj, "hideLegacyTabs", hideLegacyTabs); obs_data_set_bool(obj, "hideLegacyTabs", hideLegacyTabs);
@@ -594,6 +609,8 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
disableHints = obs_data_get_bool(obj, "disableHints"); disableHints = obs_data_get_bool(obj, "disableHints");
disableFilterComboboxFilter = disableFilterComboboxFilter =
obs_data_get_bool(obj, "disableFilterComboboxFilter"); obs_data_get_bool(obj, "disableFilterComboboxFilter");
disableMacroWidgetCache =
obs_data_get_bool(obj, "disableMacroWidgetCache");
obs_data_set_default_bool(obj, "warnPluginLoadFailure", true); obs_data_set_default_bool(obj, "warnPluginLoadFailure", true);
warnPluginLoadFailure = obs_data_get_bool(obj, "warnPluginLoadFailure"); warnPluginLoadFailure = obs_data_get_bool(obj, "warnPluginLoadFailure");
obs_data_set_default_bool(obj, "hideLegacyTabs", true); obs_data_set_default_bool(obj, "hideLegacyTabs", true);
@@ -889,6 +906,9 @@ void AdvSceneSwitcher::SetupGeneralTab()
switcher->disableFilterComboboxFilter); switcher->disableFilterComboboxFilter);
FilterComboBox::SetFilterBehaviourEnabled( FilterComboBox::SetFilterBehaviourEnabled(
!switcher->disableFilterComboboxFilter); !switcher->disableFilterComboboxFilter);
ui->disableMacroWidgetCache->setChecked(
switcher->disableMacroWidgetCache);
MacroSegmentList::SetCachingEnabled(!switcher->disableMacroWidgetCache);
ui->warnPluginLoadFailure->setChecked(switcher->warnPluginLoadFailure); ui->warnPluginLoadFailure->setChecked(switcher->warnPluginLoadFailure);
ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs); ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs);

View File

@@ -259,7 +259,8 @@ void AudioSwitch::setVolumeLevel(void *data, const float *,
} }
} }
obs_volmeter_t *AddVolmeterToSource(AudioSwitch *entry, obs_weak_source *source) static obs_volmeter_t *addVolmeterToSource(AudioSwitch *entry,
obs_weak_source *source)
{ {
obs_volmeter_t *volmeter = obs_volmeter_create(OBS_FADER_LOG); obs_volmeter_t *volmeter = obs_volmeter_create(OBS_FADER_LOG);
obs_volmeter_add_callback(volmeter, AudioSwitch::setVolumeLevel, entry); obs_volmeter_add_callback(volmeter, AudioSwitch::setVolumeLevel, entry);
@@ -279,7 +280,7 @@ void AudioSwitch::resetVolmeter()
obs_volmeter_remove_callback(volmeter, setVolumeLevel, this); obs_volmeter_remove_callback(volmeter, setVolumeLevel, this);
obs_volmeter_destroy(volmeter); obs_volmeter_destroy(volmeter);
volmeter = AddVolmeterToSource(this, audioSource); volmeter = addVolmeterToSource(this, audioSource);
} }
bool AudioSwitch::initialized() bool AudioSwitch::initialized()
@@ -318,7 +319,7 @@ void AudioSwitch::load(obs_data_t *obj)
duration.Load(obj, "duration"); duration.Load(obj, "duration");
ignoreInactiveSource = obs_data_get_bool(obj, "ignoreInactiveSource"); ignoreInactiveSource = obs_data_get_bool(obj, "ignoreInactiveSource");
volmeter = AddVolmeterToSource(this, audioSource); volmeter = addVolmeterToSource(this, audioSource);
} }
void AudioSwitchFallback::save(obs_data_t *obj) void AudioSwitchFallback::save(obs_data_t *obj)
@@ -349,7 +350,7 @@ AudioSwitch::AudioSwitch(const AudioSwitch &other)
condition(other.condition), condition(other.condition),
duration(other.duration) duration(other.duration)
{ {
volmeter = AddVolmeterToSource(this, other.audioSource); volmeter = addVolmeterToSource(this, other.audioSource);
} }
AudioSwitch::AudioSwitch(AudioSwitch &&other) noexcept AudioSwitch::AudioSwitch(AudioSwitch &&other) noexcept

View File

@@ -32,6 +32,7 @@
#endif #endif
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include "kwin-helpers.h"
namespace advss { namespace advss {
@@ -44,6 +45,10 @@ static XScreenSaverAllocInfoFunc allocSSFunc = nullptr;
static XScreenSaverQueryInfoFunc querySSFunc = nullptr; static XScreenSaverQueryInfoFunc querySSFunc = nullptr;
bool canGetIdleTime = false; bool canGetIdleTime = false;
static bool KWin = false;
static FocusNotifier notifier;
static QString KWinScriptObjectPath;
static QLibrary *libprocps = nullptr; static QLibrary *libprocps = nullptr;
#ifdef PROCPS_AVAILABLE #ifdef PROCPS_AVAILABLE
typedef PROCTAB *(*openproc_func)(int flags); typedef PROCTAB *(*openproc_func)(int flags);
@@ -275,6 +280,11 @@ int getActiveWindow(Window *&window)
void GetCurrentWindowTitle(std::string &title) void GetCurrentWindowTitle(std::string &title)
{ {
if (KWin) {
title = FocusNotifier::getActiveWindowTitle();
return;
}
Window *data = 0; Window *data = 0;
if (getActiveWindow(data) != Success || !data) { if (getActiveWindow(data) != Success || !data) {
return; return;
@@ -286,6 +296,7 @@ void GetCurrentWindowTitle(std::string &title)
auto name = getWindowName(data[0]); auto name = getWindowName(data[0]);
XFree(data); XFree(data);
if (name.empty()) { if (name.empty()) {
return; return;
} }
@@ -412,6 +423,10 @@ void GetProcessList(QStringList &processes)
long getForegroundProcessPid() long getForegroundProcessPid()
{ {
if (KWin) {
return FocusNotifier::getActiveWindowPID();
}
Window *window; Window *window;
if (getActiveWindow(window) != Success || !window || !*window) { if (getActiveWindow(window) != Success || !window || !*window) {
return -1; return -1;
@@ -437,6 +452,7 @@ long getForegroundProcessPid()
pid = *((long *)prop); pid = *((long *)prop);
XFree(prop); XFree(prop);
return pid; return pid;
} }
@@ -562,6 +578,17 @@ void PlatformInit()
return; return;
} }
KWin = isKWinAvailable();
if (!(KWin && startKWinScript(KWinScriptObjectPath) &&
registerKWinDBusListener(&notifier))) {
// something bad happened while trying to initialize
// the KWin script/dbus so disable it
KWin = false;
blog(LOG_INFO, "not using KWin compat");
} else {
blog(LOG_INFO, "using KWin compat");
}
initXss(); initXss();
initProcps(); initProcps();
initProc2(); initProc2();
@@ -583,6 +610,8 @@ void PlatformCleanup()
cleanupHelper(libproc2); cleanupHelper(libproc2);
cleanupDisplay(); cleanupDisplay();
XSetErrorHandler(NULL); XSetErrorHandler(NULL);
if (KWin && !KWinScriptObjectPath.isEmpty())
stopKWinScript(KWinScriptObjectPath);
} }
} // namespace advss } // namespace advss

166
lib/linux/kwin-helpers.cpp Normal file
View File

@@ -0,0 +1,166 @@
#include "kwin-helpers.h"
#include "log-helper.hpp"
#include <QDir>
#include <QFile>
#include <QFileDevice>
#include <QTextStream>
#include <QtDBus/QDBusConnectionInterface>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusReply>
namespace advss {
int FocusNotifier::activePID = -1;
std::string FocusNotifier::activeTitle = {};
int FocusNotifier::getActiveWindowPID()
{
return activePID;
}
std::string FocusNotifier::getActiveWindowTitle()
{
return activeTitle;
}
void FocusNotifier::focusChanged(const int pid)
{
activePID = pid;
}
void FocusNotifier::focusTitle(const QString &title)
{
activeTitle = title.toStdString();
}
bool isKWinAvailable()
{
const QDBusConnectionInterface *interface =
QDBusConnection::sessionBus().interface();
if (!interface)
return false;
const QStringList services =
interface->registeredServiceNames().value();
return services.contains("org.kde.KWin");
}
bool startKWinScript(QString &scriptObjectPath)
{
const QString scriptPath =
"/tmp/AdvancedSceneSwitcher/KWinFocusNotifier.js";
const QString script =
R"(workspace.windowActivated.connect(function(client) {
if (!client) return;
if (!client.pid) return;
if (!client.caption) return;
callDBus(
"com.github.AdvancedSceneSwitcher",
"/com/github/AdvancedSceneSwitcher",
"com.github.AdvancedSceneSwitcher",
"focusChanged",
client.pid
);
callDBus(
"com.github.AdvancedSceneSwitcher",
"/com/github/AdvancedSceneSwitcher",
"com.github.AdvancedSceneSwitcher",
"focusTitle",
client.caption
);
}))";
if (const QDir dir; !dir.mkpath(QFileInfo(scriptPath).absolutePath())) {
blog(LOG_ERROR, "error creating /tmp/AdvancedSceneSwitcher");
return false;
}
QFile scriptFile(scriptPath);
if (!scriptFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
blog(LOG_ERROR,
"error opening KWinFocusNotifier.js for writing");
return false;
}
scriptFile.setPermissions(QFileDevice::ReadOwner |
QFileDevice::WriteOwner);
QTextStream outputStream(&scriptFile);
outputStream << script;
scriptFile.close();
const QDBusConnection bus = QDBusConnection::sessionBus();
QDBusInterface scriptingIface("org.kde.KWin", "/Scripting",
"org.kde.kwin.Scripting", bus);
if (!scriptingIface.isValid()) {
return false;
}
const QDBusReply<bool> scriptRunningReply =
scriptingIface.call("isScriptLoaded", scriptPath);
if (scriptRunningReply.isValid() && scriptRunningReply.value()) {
// script already registered and running, don't do it again
// this will leave the script running since we do not have
// a valid script id anymore, but at the very least this prevents
// it from running multiple times
return true;
}
const QDBusReply<int> scriptIdReply =
scriptingIface.call("loadScript", scriptPath);
if (!scriptIdReply.isValid()) {
return false;
}
const int scriptId = scriptIdReply.value();
scriptObjectPath =
QString("/Scripting/Script%1").arg(QString::number(scriptId));
QDBusInterface scriptRunner("org.kde.KWin", scriptObjectPath,
"org.kde.kwin.Script", bus);
if (!scriptRunner.isValid()) {
return false;
}
const QDBusReply<void> runReply = scriptRunner.call("run");
return runReply.isValid();
}
bool stopKWinScript(const QString &scriptObjectPath)
{
QDBusInterface scriptRunner("org.kde.KWin", scriptObjectPath,
"org.kde.kwin.Script",
QDBusConnection::sessionBus());
if (!scriptRunner.isValid()) {
return false;
}
const QDBusReply<void> stopReply = scriptRunner.call("stop");
return stopReply.isValid();
}
bool registerKWinDBusListener(FocusNotifier *notifier)
{
static const QString serviceName = "com.github.AdvancedSceneSwitcher";
static const QString objectPath = "/com/github/AdvancedSceneSwitcher";
auto bus = QDBusConnection::sessionBus();
if (bus.objectRegisteredAt(objectPath)) {
// already registered?
return true;
}
if (!bus.registerService(serviceName)) {
return false;
}
if (!bus.registerObject(objectPath, notifier,
QDBusConnection::ExportAllSlots)) {
return false;
}
return true;
}
} // namespace advss

33
lib/linux/kwin-helpers.h Normal file
View File

@@ -0,0 +1,33 @@
#pragma once
#include <QObject>
#include <QString>
#include <string>
namespace advss {
class FocusNotifier final : public QObject {
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "com.github.AdvancedSceneSwitcher")
static int activePID;
static std::string activeTitle;
public:
using QObject::QObject;
static int getActiveWindowPID();
static std::string getActiveWindowTitle();
public slots:
void focusChanged(const int pid);
void focusTitle(const QString &title);
};
bool isKWinAvailable();
bool startKWinScript(QString &scriptObjectPath);
bool stopKWinScript(const QString &scriptObjectPath);
bool registerKWinDBusListener(FocusNotifier *notifier);
void printDBusError();
} // namespace advss

View File

@@ -35,12 +35,14 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
_enable(new SwitchButton()), _enable(new SwitchButton()),
_entryData(entryData) _entryData(entryData)
{ {
auto actionStateTimer = new QTimer(this);
QWidget::connect(_actionSelection, QWidget::connect(_actionSelection,
SIGNAL(currentTextChanged(const QString &)), this, SIGNAL(currentTextChanged(const QString &)), this,
SLOT(ActionSelectionChanged(const QString &))); SLOT(ActionSelectionChanged(const QString &)));
QWidget::connect(_enable, SIGNAL(checked(bool)), this, QWidget::connect(_enable, SIGNAL(checked(bool)), this,
SLOT(ActionEnableChanged(bool))); SLOT(ActionEnableChanged(bool)));
QWidget::connect(&_actionStateTimer, SIGNAL(timeout()), this, QWidget::connect(actionStateTimer, SIGNAL(timeout()), this,
SLOT(UpdateActionState())); SLOT(UpdateActionState()));
populateActionSelection(_actionSelection); populateActionSelection(_actionSelection);
@@ -63,7 +65,7 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
_entryData = entryData; _entryData = entryData;
SetupWidgets(true); SetupWidgets(true);
_actionStateTimer.start(300); actionStateTimer->start(300);
_loading = false; _loading = false;
} }

View File

@@ -32,7 +32,6 @@ private:
SwitchButton *_enable; SwitchButton *_enable;
std::shared_ptr<MacroAction> *_entryData; std::shared_ptr<MacroAction> *_entryData;
QTimer _actionStateTimer;
bool _loading = true; bool _loading = true;
}; };

View File

@@ -20,7 +20,7 @@ public:
MacroActionFactory() = delete; MacroActionFactory() = delete;
EXPORT static bool Register(const std::string &id, MacroActionInfo); EXPORT static bool Register(const std::string &id, MacroActionInfo);
static bool Deregister(const std::string &id); EXPORT static bool Deregister(const std::string &id);
static std::shared_ptr<MacroAction> Create(const std::string &id, static std::shared_ptr<MacroAction> Create(const std::string &id,
Macro *m); Macro *m);
static QWidget *CreateWidget(const std::string &id, QWidget *parent, static QWidget *CreateWidget(const std::string &id, QWidget *parent,

View File

@@ -12,25 +12,6 @@ bool MacroActionMacro::_registered = MacroActionFactory::Register(
{MacroActionMacro::Create, MacroActionMacroEdit::Create, {MacroActionMacro::Create, MacroActionMacroEdit::Create,
"AdvSceneSwitcher.action.macro"}); "AdvSceneSwitcher.action.macro"});
const static std::map<MacroActionMacro::Action, std::string> actionTypes = {
{MacroActionMacro::Action::PAUSE,
"AdvSceneSwitcher.action.macro.type.pause"},
{MacroActionMacro::Action::UNPAUSE,
"AdvSceneSwitcher.action.macro.type.unpause"},
{MacroActionMacro::Action::RESET_COUNTER,
"AdvSceneSwitcher.action.macro.type.resetCounter"},
{MacroActionMacro::Action::RUN,
"AdvSceneSwitcher.action.macro.type.run"},
{MacroActionMacro::Action::STOP,
"AdvSceneSwitcher.action.macro.type.stop"},
{MacroActionMacro::Action::DISABLE_ACTION,
"AdvSceneSwitcher.action.macro.type.disableAction"},
{MacroActionMacro::Action::ENABLE_ACTION,
"AdvSceneSwitcher.action.macro.type.enableAction"},
{MacroActionMacro::Action::TOGGLE_ACTION,
"AdvSceneSwitcher.action.macro.type.toggleAction"},
};
bool MacroActionMacro::PerformAction() bool MacroActionMacro::PerformAction()
{ {
auto macro = _macro.GetMacro(); auto macro = _macro.GetMacro();
@@ -45,6 +26,9 @@ bool MacroActionMacro::PerformAction()
case Action::UNPAUSE: case Action::UNPAUSE:
macro->SetPaused(false); macro->SetPaused(false);
break; break;
case Action::TOGGLE_PAUSE:
macro->SetPaused(!macro->Paused());
break;
case Action::RESET_COUNTER: case Action::RESET_COUNTER:
macro->ResetRunCount(); macro->ResetRunCount();
break; break;
@@ -210,8 +194,31 @@ void MacroActionMacro::RunActions(Macro *actionMacro) const
static void populateActionSelection(QComboBox *list) static void populateActionSelection(QComboBox *list)
{ {
for (const auto &[_, name] : actionTypes) { static const std::vector<std::pair<MacroActionMacro::Action, std::string>>
list->addItem(obs_module_text(name.c_str())); actions = {
{MacroActionMacro::Action::PAUSE,
"AdvSceneSwitcher.action.macro.type.pause"},
{MacroActionMacro::Action::UNPAUSE,
"AdvSceneSwitcher.action.macro.type.unpause"},
{MacroActionMacro::Action::TOGGLE_PAUSE,
"AdvSceneSwitcher.action.macro.type.togglePause"},
{MacroActionMacro::Action::RESET_COUNTER,
"AdvSceneSwitcher.action.macro.type.resetCounter"},
{MacroActionMacro::Action::RUN,
"AdvSceneSwitcher.action.macro.type.run"},
{MacroActionMacro::Action::STOP,
"AdvSceneSwitcher.action.macro.type.stop"},
{MacroActionMacro::Action::DISABLE_ACTION,
"AdvSceneSwitcher.action.macro.type.disableAction"},
{MacroActionMacro::Action::ENABLE_ACTION,
"AdvSceneSwitcher.action.macro.type.enableAction"},
{MacroActionMacro::Action::TOGGLE_ACTION,
"AdvSceneSwitcher.action.macro.type.toggleAction"},
};
for (const auto &[value, name] : actions) {
list->addItem(obs_module_text(name.c_str()),
static_cast<int>(value));
} }
} }
@@ -321,7 +328,8 @@ void MacroActionMacroEdit::UpdateEntryData()
if (!_entryData) { if (!_entryData) {
return; return;
} }
_actions->setCurrentIndex(static_cast<int>(_entryData->_action)); _actions->setCurrentIndex(
_actions->findData(static_cast<int>(_entryData->_action)));
_actionIndex->SetValue(_entryData->_actionIndex); _actionIndex->SetValue(_entryData->_actionIndex);
_actionIndex->SetMacro(_entryData->_macro.GetMacro()); _actionIndex->SetMacro(_entryData->_macro.GetMacro());
_macros->SetCurrentMacro(_entryData->_macro); _macros->SetCurrentMacro(_entryData->_macro);
@@ -350,10 +358,11 @@ void MacroActionMacroEdit::MacroChanged(const QString &text)
SetWidgetVisibility(); SetWidgetVisibility();
} }
void MacroActionMacroEdit::ActionChanged(int value) void MacroActionMacroEdit::ActionChanged(int idx)
{ {
GUARD_LOADING_AND_LOCK(); GUARD_LOADING_AND_LOCK();
_entryData->_action = static_cast<MacroActionMacro::Action>(value); _entryData->_action = static_cast<MacroActionMacro::Action>(
_actions->itemData(idx).toInt());
SetWidgetVisibility(); SetWidgetVisibility();
} }

View File

@@ -49,6 +49,7 @@ public:
DISABLE_ACTION, DISABLE_ACTION,
ENABLE_ACTION, ENABLE_ACTION,
TOGGLE_ACTION, TOGGLE_ACTION,
TOGGLE_PAUSE,
}; };
Action _action = Action::RUN; Action _action = Action::RUN;
IntVariable _actionIndex = 1; IntVariable _actionIndex = 1;

View File

@@ -170,11 +170,7 @@ void MacroActionQueueEdit::UpdateEntryData()
void MacroActionQueueEdit::MacroChanged(const QString &text) void MacroActionQueueEdit::MacroChanged(const QString &text)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_macro = text; _entryData->_macro = text;
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));
@@ -182,11 +178,7 @@ void MacroActionQueueEdit::MacroChanged(const QString &text)
void MacroActionQueueEdit::QueueChanged(const QString &text) void MacroActionQueueEdit::QueueChanged(const QString &text)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_queue = GetWeakActionQueueByQString(text); _entryData->_queue = GetWeakActionQueueByQString(text);
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));
@@ -194,11 +186,7 @@ void MacroActionQueueEdit::QueueChanged(const QString &text)
void MacroActionQueueEdit::ActionChanged(int value) void MacroActionQueueEdit::ActionChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_action = static_cast<MacroActionQueue::Action>(value); _entryData->_action = static_cast<MacroActionQueue::Action>(value);
SetWidgetVisibility(); SetWidgetVisibility();
emit HeaderInfoChanged( emit HeaderInfoChanged(

View File

@@ -20,7 +20,7 @@ class MacroConditionFactory {
public: public:
MacroConditionFactory() = delete; MacroConditionFactory() = delete;
EXPORT static bool Register(const std::string &, MacroConditionInfo); EXPORT static bool Register(const std::string &, MacroConditionInfo);
static bool Deregister(const std::string &); EXPORT static bool Deregister(const std::string &);
static std::shared_ptr<MacroCondition> Create(const std::string &, static std::shared_ptr<MacroCondition> Create(const std::string &,
Macro *m); Macro *m);
static QWidget *CreateWidget(const std::string &id, QWidget *parent, static QWidget *CreateWidget(const std::string &id, QWidget *parent,

View File

@@ -538,11 +538,7 @@ void MacroConditionMacroEdit::UpdateEntryData()
void MacroConditionMacroEdit::MacroChanged(const QString &text) void MacroConditionMacroEdit::MacroChanged(const QString &text)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_macro = text; _entryData->_macro = text;
_actionIndex->SetMacro(_entryData->_macro.GetMacro()); _actionIndex->SetMacro(_entryData->_macro.GetMacro());
emit HeaderInfoChanged( emit HeaderInfoChanged(
@@ -551,21 +547,13 @@ void MacroConditionMacroEdit::MacroChanged(const QString &text)
void MacroConditionMacroEdit::CountChanged(const NumberVariable<int> &value) void MacroConditionMacroEdit::CountChanged(const NumberVariable<int> &value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_count = value; _entryData->_count = value;
} }
void MacroConditionMacroEdit::CountConditionChanged(int cond) void MacroConditionMacroEdit::CountConditionChanged(int cond)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_counterCondition = _entryData->_counterCondition =
static_cast<MacroConditionMacro::CounterCondition>(cond); static_cast<MacroConditionMacro::CounterCondition>(cond);
} }
@@ -590,11 +578,7 @@ void MacroConditionMacroEdit::MacroRemove(const QString &)
void MacroConditionMacroEdit::TypeChanged(int type) void MacroConditionMacroEdit::TypeChanged(int type)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->SetType(static_cast<MacroConditionMacro::Type>(type)); _entryData->SetType(static_cast<MacroConditionMacro::Type>(type));
SetupWidgets(); SetupWidgets();
} }
@@ -640,11 +624,7 @@ void MacroConditionMacroEdit::UpdatePaused()
void MacroConditionMacroEdit::MultiStateConditionChanged(int cond) void MacroConditionMacroEdit::MultiStateConditionChanged(int cond)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_multiSateCondition = _entryData->_multiSateCondition =
static_cast<MacroConditionMacro::MultiStateCondition>(cond); static_cast<MacroConditionMacro::MultiStateCondition>(cond);
} }
@@ -652,21 +632,13 @@ void MacroConditionMacroEdit::MultiStateConditionChanged(int cond)
void MacroConditionMacroEdit::MultiStateCountChanged( void MacroConditionMacroEdit::MultiStateCountChanged(
const NumberVariable<int> &value) const NumberVariable<int> &value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_multiSateCount = value; _entryData->_multiSateCount = value;
} }
void MacroConditionMacroEdit::Add(const std::string &name) void MacroConditionMacroEdit::Add(const std::string &name)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
MacroRef macro(name); MacroRef macro(name);
_entryData->_macros.push_back(macro); _entryData->_macros.push_back(macro);
adjustSize(); adjustSize();
@@ -675,11 +647,7 @@ void MacroConditionMacroEdit::Add(const std::string &name)
void MacroConditionMacroEdit::Remove(int idx) void MacroConditionMacroEdit::Remove(int idx)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_macros.erase(std::next(_entryData->_macros.begin(), idx)); _entryData->_macros.erase(std::next(_entryData->_macros.begin(), idx));
adjustSize(); adjustSize();
updateGeometry(); updateGeometry();
@@ -687,12 +655,8 @@ void MacroConditionMacroEdit::Remove(int idx)
void MacroConditionMacroEdit::Replace(int idx, const std::string &name) void MacroConditionMacroEdit::Replace(int idx, const std::string &name)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
MacroRef macro(name); MacroRef macro(name);
auto lock = LockContext();
_entryData->_macros[idx] = macro; _entryData->_macros[idx] = macro;
adjustSize(); adjustSize();
updateGeometry(); updateGeometry();
@@ -700,11 +664,7 @@ void MacroConditionMacroEdit::Replace(int idx, const std::string &name)
void MacroConditionMacroEdit::ActionIndexChanged(const IntVariable &value) void MacroConditionMacroEdit::ActionIndexChanged(const IntVariable &value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_actionIndex = value; _entryData->_actionIndex = value;
} }

View File

@@ -115,11 +115,7 @@ MacroConditionQueueEdit::MacroConditionQueueEdit(
void MacroConditionQueueEdit::ConditionChanged(int condition) void MacroConditionQueueEdit::ConditionChanged(int condition)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_condition = _entryData->_condition =
static_cast<MacroConditionQueue::Condition>(condition); static_cast<MacroConditionQueue::Condition>(condition);
emit HeaderInfoChanged( emit HeaderInfoChanged(
@@ -129,11 +125,7 @@ void MacroConditionQueueEdit::ConditionChanged(int condition)
void MacroConditionQueueEdit::QueueChanged(const QString &text) void MacroConditionQueueEdit::QueueChanged(const QString &text)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_queue = GetWeakActionQueueByQString(text); _entryData->_queue = GetWeakActionQueueByQString(text);
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));
@@ -141,11 +133,7 @@ void MacroConditionQueueEdit::QueueChanged(const QString &text)
void MacroConditionQueueEdit::SizeChanged(const NumberVariable<int> &value) void MacroConditionQueueEdit::SizeChanged(const NumberVariable<int> &value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_size = value; _entryData->_size = value;
} }

View File

@@ -264,32 +264,19 @@ void MacroConditionTempVarEdit::UpdateEntryData()
void MacroConditionTempVarEdit::VariableChanged(const TempVariableRef &var) void MacroConditionTempVarEdit::VariableChanged(const TempVariableRef &var)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_tempVar = var; _entryData->_tempVar = var;
} }
void MacroConditionTempVarEdit::Variable2Changed(const QString &text) void MacroConditionTempVarEdit::Variable2Changed(const QString &text)
{ {
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_variable2 = GetWeakVariableByQString(text); _entryData->_variable2 = GetWeakVariableByQString(text);
} }
void MacroConditionTempVarEdit::ConditionChanged(int value) void MacroConditionTempVarEdit::ConditionChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_type = _entryData->_type =
static_cast<MacroConditionTempVar::Condition>(value); static_cast<MacroConditionTempVar::Condition>(value);
SetWidgetVisibility(); SetWidgetVisibility();
@@ -297,11 +284,7 @@ void MacroConditionTempVarEdit::ConditionChanged(int value)
void MacroConditionTempVarEdit::StrValueChanged() void MacroConditionTempVarEdit::StrValueChanged()
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_strValue = _strValue->toPlainText().toStdString(); _entryData->_strValue = _strValue->toPlainText().toStdString();
adjustSize(); adjustSize();
updateGeometry(); updateGeometry();
@@ -309,21 +292,13 @@ void MacroConditionTempVarEdit::StrValueChanged()
void MacroConditionTempVarEdit::NumValueChanged(double val) void MacroConditionTempVarEdit::NumValueChanged(double val)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_numValue = val; _entryData->_numValue = val;
} }
void MacroConditionTempVarEdit::RegexChanged(const RegexConfig &conf) void MacroConditionTempVarEdit::RegexChanged(const RegexConfig &conf)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_regex = conf; _entryData->_regex = conf;
adjustSize(); adjustSize();
updateGeometry(); updateGeometry();

View File

@@ -236,11 +236,7 @@ void MacroConditionVariableEdit::UpdateEntryData()
void MacroConditionVariableEdit::VariableChanged(const QString &text) void MacroConditionVariableEdit::VariableChanged(const QString &text)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_variable = GetWeakVariableByQString(text); _entryData->_variable = GetWeakVariableByQString(text);
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));
@@ -248,22 +244,13 @@ void MacroConditionVariableEdit::VariableChanged(const QString &text)
void MacroConditionVariableEdit::Variable2Changed(const QString &text) void MacroConditionVariableEdit::Variable2Changed(const QString &text)
{ {
GUARD_LOADING_AND_LOCK();
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_variable2 = GetWeakVariableByQString(text); _entryData->_variable2 = GetWeakVariableByQString(text);
} }
void MacroConditionVariableEdit::ConditionChanged(int value) void MacroConditionVariableEdit::ConditionChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_type = _entryData->_type =
static_cast<MacroConditionVariable::Condition>(value); static_cast<MacroConditionVariable::Condition>(value);
SetWidgetVisibility(); SetWidgetVisibility();
@@ -271,11 +258,7 @@ void MacroConditionVariableEdit::ConditionChanged(int value)
void MacroConditionVariableEdit::StrValueChanged() void MacroConditionVariableEdit::StrValueChanged()
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_strValue = _strValue->toPlainText().toStdString(); _entryData->_strValue = _strValue->toPlainText().toStdString();
adjustSize(); adjustSize();
updateGeometry(); updateGeometry();
@@ -283,21 +266,13 @@ void MacroConditionVariableEdit::StrValueChanged()
void MacroConditionVariableEdit::NumValueChanged(double val) void MacroConditionVariableEdit::NumValueChanged(double val)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_numValue = val; _entryData->_numValue = val;
} }
void MacroConditionVariableEdit::RegexChanged(const RegexConfig &conf) void MacroConditionVariableEdit::RegexChanged(const RegexConfig &conf)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_regex = conf; _entryData->_regex = conf;
adjustSize(); adjustSize();
updateGeometry(); updateGeometry();

View File

@@ -78,36 +78,36 @@ bool MacroSwitchedScene()
return macroSceneSwitched; return macroSceneSwitched;
} }
std::string GetMacroName(Macro *macro) std::string GetMacroName(const Macro *macro)
{ {
return macro ? macro->Name() : ""; return macro ? macro->Name() : "";
} }
std::chrono::high_resolution_clock::time_point std::chrono::high_resolution_clock::time_point
LastMacroConditionCheckTime(Macro *macro) LastMacroConditionCheckTime(const Macro *macro)
{ {
return macro ? macro->LastConditionCheckTime() return macro ? macro->LastConditionCheckTime()
: std::chrono::high_resolution_clock::time_point{}; : std::chrono::high_resolution_clock::time_point{};
} }
bool MacroIsStopped(Macro *macro) bool MacroIsStopped(const Macro *macro)
{ {
return macro ? macro->GetStop() : true; return macro ? macro->GetStop() : true;
} }
bool MacroIsPaused(Macro *macro) bool MacroIsPaused(const Macro *macro)
{ {
return macro ? macro->Paused() : true; return macro ? macro->Paused() : true;
} }
bool MacroWasPausedSince( bool MacroWasPausedSince(
Macro *macro, const Macro *macro,
const std::chrono::high_resolution_clock::time_point &time) const std::chrono::high_resolution_clock::time_point &time)
{ {
return macro ? macro->WasPausedSince(time) : false; return macro ? macro->WasPausedSince(time) : false;
} }
bool MacroWasCheckedSinceLastStart(Macro *macro) bool MacroWasCheckedSinceLastStart(const Macro *macro)
{ {
if (!macro) { if (!macro) {
return false; return false;
@@ -144,7 +144,7 @@ void ResetMacroRunCount(Macro *macro)
macro->ResetRunCount(); macro->ResetRunCount();
} }
bool IsValidMacroSegmentIndex(Macro *m, const int idx, bool isCondition) bool IsValidMacroSegmentIndex(const Macro *m, const int idx, bool isCondition)
{ {
if (!m || idx < 0) { if (!m || idx < 0) {
return false; return false;

View File

@@ -41,17 +41,17 @@ EXPORT std::atomic_int &GetShutdownConditionCount();
EXPORT void SetMacroSwitchedScene(bool value); EXPORT void SetMacroSwitchedScene(bool value);
EXPORT bool MacroSwitchedScene(); EXPORT bool MacroSwitchedScene();
EXPORT std::string GetMacroName(Macro *); EXPORT std::string GetMacroName(const Macro *);
EXPORT std::chrono::high_resolution_clock::time_point EXPORT std::chrono::high_resolution_clock::time_point
LastMacroConditionCheckTime(Macro *); LastMacroConditionCheckTime(const Macro *);
EXPORT bool MacroIsStopped(Macro *); EXPORT bool MacroIsStopped(const Macro *);
EXPORT bool MacroIsPaused(Macro *); EXPORT bool MacroIsPaused(const Macro *);
EXPORT bool EXPORT bool
MacroWasPausedSince(Macro *, MacroWasPausedSince(const Macro *,
const std::chrono::high_resolution_clock::time_point &); const std::chrono::high_resolution_clock::time_point &);
EXPORT bool MacroWasCheckedSinceLastStart(Macro *); EXPORT bool MacroWasCheckedSinceLastStart(const Macro *);
EXPORT void AddMacroHelperThread(Macro *, std::thread &&); EXPORT void AddMacroHelperThread(Macro *, std::thread &&);
@@ -68,6 +68,6 @@ EXPORT void InvalidateMacroTempVarValues();
EXPORT void ResetMacroConditionTimers(Macro *); EXPORT void ResetMacroConditionTimers(Macro *);
EXPORT void ResetMacroRunCount(Macro *); EXPORT void ResetMacroRunCount(Macro *);
bool IsValidMacroSegmentIndex(Macro *m, const int idx, bool isCondition); bool IsValidMacroSegmentIndex(const Macro *m, const int idx, bool isCondition);
} // namespace advss } // namespace advss

View File

@@ -13,6 +13,8 @@
namespace advss { namespace advss {
bool MacroSegmentList::_useCache = true;
MacroSegmentList::MacroSegmentList(QWidget *parent) MacroSegmentList::MacroSegmentList(QWidget *parent)
: QScrollArea(parent), : QScrollArea(parent),
_layout(new QVBoxLayout), _layout(new QVBoxLayout),
@@ -40,12 +42,21 @@ MacroSegmentList::MacroSegmentList(QWidget *parent)
[this]() { SetupVisibleMacroSegmentWidgets(); }); [this]() { SetupVisibleMacroSegmentWidgets(); });
} }
static void clearWidgetVector(const std::vector<QWidget *> &widgets)
{
for (auto widget : widgets) {
widget->deleteLater();
}
};
MacroSegmentList::~MacroSegmentList() MacroSegmentList::~MacroSegmentList()
{ {
if (_autoScrollThread.joinable()) { if (_autoScrollThread.joinable()) {
_autoScroll = false; _autoScroll = false;
_autoScrollThread.join(); _autoScrollThread.join();
} }
ClearWidgetCache();
} }
static bool posIsInScrollbar(const QScrollBar *scrollbar, const QPoint &pos) static bool posIsInScrollbar(const QScrollBar *scrollbar, const QPoint &pos)
@@ -56,7 +67,7 @@ static bool posIsInScrollbar(const QScrollBar *scrollbar, const QPoint &pos)
if (!scrollbar->isVisible()) { if (!scrollbar->isVisible()) {
return false; return false;
} }
const auto geo = scrollbar->geometry(); const auto &geo = scrollbar->geometry();
const auto globalGeo = QRect(scrollbar->mapToGlobal(geo.topLeft()), const auto globalGeo = QRect(scrollbar->mapToGlobal(geo.topLeft()),
scrollbar->mapToGlobal(geo.bottomRight())); scrollbar->mapToGlobal(geo.bottomRight()));
return globalGeo.contains(pos); return globalGeo.contains(pos);
@@ -125,6 +136,61 @@ void MacroSegmentList::Clear(int idx) const
ClearLayout(_contentLayout, idx); ClearLayout(_contentLayout, idx);
} }
void MacroSegmentList::SetCachingEnabled(bool enable)
{
_useCache = enable;
}
void MacroSegmentList::CacheCurrentWidgetsFor(const Macro *macro)
{
if (!_useCache) {
return;
}
std::vector<QWidget *> result;
int idx = 0;
QLayoutItem *item;
while ((item = _contentLayout->takeAt(idx))) {
if (!item || !item->widget()) {
continue;
}
auto widget = item->widget();
widget->hide();
result.emplace_back(widget);
}
_widgetCache[macro] = result;
}
bool MacroSegmentList::PopulateWidgetsFromCache(const Macro *macro)
{
if (!_useCache) {
return false;
}
auto it = _widgetCache.find(macro);
if (it == _widgetCache.end()) {
return false;
}
for (auto widget : it->second) {
_contentLayout->addWidget(widget);
widget->show();
}
return true;
}
void MacroSegmentList::ClearWidgetsFromCacheFor(const Macro *macro)
{
auto it = _widgetCache.find(macro);
if (it == _widgetCache.end()) {
return;
}
clearWidgetVector(it->second);
_widgetCache.erase(it);
}
void MacroSegmentList::Highlight(int idx, QColor color) void MacroSegmentList::Highlight(int idx, QColor color)
{ {
auto item = _contentLayout->itemAt(idx); auto item = _contentLayout->itemAt(idx);
@@ -270,6 +336,13 @@ void MacroSegmentList::HideLastDropLine()
_dropLineIdx = -1; _dropLineIdx = -1;
} }
void MacroSegmentList::ClearWidgetCache()
{
for (const auto &[_, widgets] : _widgetCache) {
clearWidgetVector(widgets);
}
}
static bool isInUpperHalfOf(const QPoint &pos, const QRect &rect) static bool isInUpperHalfOf(const QPoint &pos, const QRect &rect)
{ {
return QRect(rect.topLeft(), return QRect(rect.topLeft(),
@@ -492,7 +565,7 @@ void MacroSegmentList::dropEvent(QDropEvent *event)
void MacroSegmentList::resizeEvent(QResizeEvent *event) void MacroSegmentList::resizeEvent(QResizeEvent *event)
{ {
QWidget::resizeEvent(event); QScrollArea::resizeEvent(event);
SetupVisibleMacroSegmentWidgets(); SetupVisibleMacroSegmentWidgets();
} }

View File

@@ -9,12 +9,14 @@
namespace advss { namespace advss {
class Macro;
class MacroSegmentList : public QScrollArea { class MacroSegmentList : public QScrollArea {
Q_OBJECT Q_OBJECT
public: public:
MacroSegmentList(QWidget *parent = nullptr); MacroSegmentList(QWidget *parent = nullptr);
virtual ~MacroSegmentList(); ~MacroSegmentList();
void SetHelpMsg(const QString &msg) const; void SetHelpMsg(const QString &msg) const;
void SetHelpMsgVisible(bool visible) const; void SetHelpMsgVisible(bool visible) const;
MacroSegmentEdit *WidgetAt(int idx) const; MacroSegmentEdit *WidgetAt(int idx) const;
@@ -24,6 +26,10 @@ public:
void Add(QWidget *widget); void Add(QWidget *widget);
void Remove(int idx) const; void Remove(int idx) const;
void Clear(int idx = 0) const; // Clear all elements >= idx void Clear(int idx = 0) const; // Clear all elements >= idx
static void SetCachingEnabled(bool enable);
void CacheCurrentWidgetsFor(const Macro *);
bool PopulateWidgetsFromCache(const Macro *);
void ClearWidgetsFromCacheFor(const Macro *);
void Highlight(int idx, QColor color = QColor(Qt::green)); void Highlight(int idx, QColor color = QColor(Qt::green));
void SetCollapsed(bool) const; void SetCollapsed(bool) const;
void SetSelection(int idx) const; void SetSelection(int idx) const;
@@ -55,6 +61,7 @@ private:
bool IsInListArea(const QPoint &) const; bool IsInListArea(const QPoint &) const;
QRect GetContentItemRectWithPadding(int idx) const; QRect GetContentItemRectWithPadding(int idx) const;
void HideLastDropLine(); void HideLastDropLine();
void ClearWidgetCache();
int _dragPosition = -1; int _dragPosition = -1;
int _dropLineIdx = -1; int _dropLineIdx = -1;
@@ -67,6 +74,9 @@ private:
QLabel *_helpMsg; QLabel *_helpMsg;
bool _checkVisibility = true; bool _checkVisibility = true;
static bool _useCache;
std::unordered_map<const Macro *, std::vector<QWidget *>> _widgetCache;
}; };
} // namespace advss } // namespace advss

View File

@@ -107,7 +107,7 @@ void MacroSegment::SetupTempVars()
void MacroSegment::ClearAvailableTempvars() void MacroSegment::ClearAvailableTempvars()
{ {
_tempVariables.clear(); _tempVariables.clear();
NotifyUIAboutTempVarChange(); NotifyUIAboutTempVarChange(this);
} }
static std::shared_ptr<MacroSegment> static std::shared_ptr<MacroSegment>
@@ -149,7 +149,7 @@ void MacroSegment::AddTempvar(const std::string &id, const std::string &name,
TempVariable var(id, name, description, sharedSegment); TempVariable var(id, name, description, sharedSegment);
_tempVariables.emplace_back(std::move(var)); _tempVariables.emplace_back(std::move(var));
NotifyUIAboutTempVarChange(); NotifyUIAboutTempVarChange(this);
} }
void MacroSegment::SetTempVarValue(const std::string &id, void MacroSegment::SetTempVarValue(const std::string &id,

View File

@@ -19,7 +19,7 @@ namespace advss {
class Macro; class Macro;
class EXPORT MacroSegment { class EXPORT MacroSegment : public Lockable {
public: public:
MacroSegment(Macro *m, bool supportsVariableValue); MacroSegment(Macro *m, bool supportsVariableValue);
virtual ~MacroSegment() = default; virtual ~MacroSegment() = default;

View File

@@ -76,12 +76,16 @@ void MacroSelection::ShowAllMacros()
void MacroSelection::MacroRemove(const QString &name) void MacroSelection::MacroRemove(const QString &name)
{ {
const bool currentSelectionWasRemoved = name == currentText();
int idx = findText(name); int idx = findText(name);
if (idx == -1) { if (idx == -1) {
return; return;
} }
removeItem(idx); removeItem(idx);
setCurrentIndex(-1); if (currentSelectionWasRemoved) {
setCurrentIndex(-1);
}
} }
void MacroSelection::MacroRename(const QString &oldName, const QString &newName) void MacroSelection::MacroRename(const QString &oldName, const QString &newName)

View File

@@ -100,6 +100,13 @@ bool AdvSceneSwitcher::AddNewMacro(std::shared_ptr<Macro> &res,
void AdvSceneSwitcher::on_macroAdd_clicked() void AdvSceneSwitcher::on_macroAdd_clicked()
{ {
// Hotkey to add new macro will also use this function.
// Since we don't want the hotkey to have an effect if the macro tab is
// not focused we need to check this here.
if (!MacroTabIsInFocus()) {
return;
}
std::string name; std::string name;
std::shared_ptr<Macro> newMacro; std::shared_ptr<Macro> newMacro;
if (!AddNewMacro(newMacro, name)) { if (!AddNewMacro(newMacro, name)) {
@@ -133,6 +140,42 @@ void AdvSceneSwitcher::on_macroAdd_clicked()
emit MacroAdded(QString::fromStdString(name)); emit MacroAdded(QString::fromStdString(name));
} }
static void addGroupSubitems(std::vector<std::shared_ptr<Macro>> &macros,
const std::shared_ptr<Macro> &group)
{
std::vector<std::shared_ptr<Macro>> subitems;
subitems.reserve(group->GroupSize());
// Find all subitems
auto allMacros = GetMacros();
for (auto it = allMacros.begin(); it < allMacros.end(); it++) {
if ((*it)->Name() != group->Name()) {
continue;
}
for (uint32_t i = 1; i <= group->GroupSize(); i++) {
subitems.emplace_back(*std::next(it, i));
}
break;
}
// Remove subitems which were already selected to avoid duplicates
for (const auto &subitem : subitems) {
auto it = std::find(macros.begin(), macros.end(), subitem);
if (it == macros.end()) {
continue;
}
macros.erase(it);
}
// Add group subitems
auto it = std::find(macros.begin(), macros.end(), group);
if (it == macros.end()) {
return;
}
it = std::next(it);
macros.insert(it, subitems.begin(), subitems.end());
}
void AdvSceneSwitcher::RemoveMacro(std::shared_ptr<Macro> &macro) void AdvSceneSwitcher::RemoveMacro(std::shared_ptr<Macro> &macro)
{ {
if (!macro) { if (!macro) {
@@ -148,7 +191,27 @@ void AdvSceneSwitcher::RemoveMacro(std::shared_ptr<Macro> &macro)
} }
} }
const auto clearWidgetCache = [this](Macro *macro) {
ui->conditionsList->ClearWidgetsFromCacheFor(macro);
ui->actionsList->ClearWidgetsFromCacheFor(macro);
ui->elseActionsList->ClearWidgetsFromCacheFor(macro);
};
if (macro->IsGroup()) {
std::vector<std::shared_ptr<Macro>> macros = {macro};
addGroupSubitems(macros, macro);
for (auto macro : macros) {
clearWidgetCache(macro.get());
}
} else {
clearWidgetCache(macro.get());
}
// Don't cache widgets for about to be deleted macros
MacroSegmentList::SetCachingEnabled(false);
ui->macros->Remove(macro); ui->macros->Remove(macro);
MacroSegmentList::SetCachingEnabled(!switcher->disableMacroWidgetCache);
emit MacroRemoved(name); emit MacroRemoved(name);
} }
@@ -247,41 +310,6 @@ void AdvSceneSwitcher::RenameSelectedMacro()
ui->macroName->setText(QString::fromStdString(name)); ui->macroName->setText(QString::fromStdString(name));
} }
static void addGroupSubitems(std::vector<std::shared_ptr<Macro>> &macros,
const std::shared_ptr<Macro> &group)
{
std::vector<std::shared_ptr<Macro>> subitems;
subitems.reserve(group->GroupSize());
// Find all subitems
auto allMacros = GetMacros();
for (auto it = allMacros.begin(); it < allMacros.end(); it++) {
if ((*it)->Name() == group->Name()) {
for (uint32_t i = 1; i <= group->GroupSize(); i++) {
subitems.emplace_back(*std::next(it, i));
}
break;
}
}
// Remove subitems which were already selected to avoid duplicates
for (const auto &subitem : subitems) {
auto it = std::find(macros.begin(), macros.end(), subitem);
if (it == macros.end()) {
continue;
}
macros.erase(it);
}
// Add group subitems
auto it = std::find(macros.begin(), macros.end(), group);
if (it == macros.end()) {
return;
}
it = std::next(it);
macros.insert(it, subitems.begin(), subitems.end());
}
void AdvSceneSwitcher::ExportMacros() const void AdvSceneSwitcher::ExportMacros() const
{ {
auto selectedMacros = GetSelectedMacros(); auto selectedMacros = GetSelectedMacros();
@@ -537,6 +565,11 @@ void AdvSceneSwitcher::on_runMacroOnChange_stateChanged(int value) const
void AdvSceneSwitcher::PopulateMacroActions(Macro &m, uint32_t afterIdx) void AdvSceneSwitcher::PopulateMacroActions(Macro &m, uint32_t afterIdx)
{ {
auto &actions = m.Actions(); auto &actions = m.Actions();
ui->actionsList->SetHelpMsgVisible(actions.size() == 0);
if (ui->actionsList->PopulateWidgetsFromCache(&m)) {
return;
}
// The layout system has not completed geometry propagation yet, so we // The layout system has not completed geometry propagation yet, so we
// can skip those checks for now // can skip those checks for now
@@ -547,7 +580,6 @@ void AdvSceneSwitcher::PopulateMacroActions(Macro &m, uint32_t afterIdx)
actions[afterIdx]->GetId()); actions[afterIdx]->GetId());
ui->actionsList->Add(newEntry); ui->actionsList->Add(newEntry);
} }
ui->actionsList->SetHelpMsgVisible(actions.size() == 0);
// Give the layout system time before enabling the visibility checks and // Give the layout system time before enabling the visibility checks and
// fully constructing the visible macro segments // fully constructing the visible macro segments
@@ -559,6 +591,11 @@ void AdvSceneSwitcher::PopulateMacroActions(Macro &m, uint32_t afterIdx)
void AdvSceneSwitcher::PopulateMacroElseActions(Macro &m, uint32_t afterIdx) void AdvSceneSwitcher::PopulateMacroElseActions(Macro &m, uint32_t afterIdx)
{ {
auto &actions = m.ElseActions(); auto &actions = m.ElseActions();
ui->elseActionsList->SetHelpMsgVisible(actions.size() == 0);
if (ui->elseActionsList->PopulateWidgetsFromCache(&m)) {
return;
}
// The layout system has not completed geometry propagation yet, so we // The layout system has not completed geometry propagation yet, so we
// can skip those checks for now // can skip those checks for now
@@ -569,7 +606,6 @@ void AdvSceneSwitcher::PopulateMacroElseActions(Macro &m, uint32_t afterIdx)
actions[afterIdx]->GetId()); actions[afterIdx]->GetId());
ui->elseActionsList->Add(newEntry); ui->elseActionsList->Add(newEntry);
} }
ui->elseActionsList->SetHelpMsgVisible(actions.size() == 0);
// Give the layout system time before enabling the visibility checks and // Give the layout system time before enabling the visibility checks and
// fully constructing the visible macro segments // fully constructing the visible macro segments
@@ -582,6 +618,11 @@ void AdvSceneSwitcher::PopulateMacroConditions(Macro &m, uint32_t afterIdx)
{ {
bool root = afterIdx == 0; bool root = afterIdx == 0;
auto &conditions = m.Conditions(); auto &conditions = m.Conditions();
ui->conditionsList->SetHelpMsgVisible(conditions.size() == 0);
if (ui->conditionsList->PopulateWidgetsFromCache(&m)) {
return;
}
// The layout system has not completed geometry propagation yet, so we // The layout system has not completed geometry propagation yet, so we
// can skip those checks for now // can skip those checks for now
@@ -594,7 +635,6 @@ void AdvSceneSwitcher::PopulateMacroConditions(Macro &m, uint32_t afterIdx)
ui->conditionsList->Add(newEntry); ui->conditionsList->Add(newEntry);
root = false; root = false;
} }
ui->conditionsList->SetHelpMsgVisible(conditions.size() == 0);
// Give the layout system time before enabling the visibility checks and // Give the layout system time before enabling the visibility checks and
// fully constructing the visible macro segments // fully constructing the visible macro segments
@@ -779,6 +819,10 @@ void AdvSceneSwitcher::MacroSelectionAboutToChange() const
} }
macro->SetElseActionSplitterPosition( macro->SetElseActionSplitterPosition(
ui->macroElseActionSplitter->sizes()); ui->macroElseActionSplitter->sizes());
ui->conditionsList->CacheCurrentWidgetsFor(macro);
ui->actionsList->CacheCurrentWidgetsFor(macro);
ui->elseActionsList->CacheCurrentWidgetsFor(macro);
} }
void AdvSceneSwitcher::MacroSelectionChanged() void AdvSceneSwitcher::MacroSelectionChanged()

View File

@@ -1301,10 +1301,10 @@ QSize MacroTreeDelegate::sizeHint(const QStyleOptionViewItem &option,
QWidget *item = tree->indexWidget(index); QWidget *item = tree->indexWidget(index);
if (!item) { if (!item) {
return (QSize(0, 0)); return QStyledItemDelegate::sizeHint(option, index);
} }
return (QSize(option.widget->minimumWidth(), item->height())); return QSize(item->sizeHint());
} }
} // namespace advss } // namespace advss

View File

@@ -173,7 +173,10 @@ static bool checkCondition(const std::shared_ptr<MacroCondition> &condition)
static constexpr auto perfLogThreshold = 300ms; static constexpr auto perfLogThreshold = 300ms;
const auto startTime = std::chrono::high_resolution_clock::now(); const auto startTime = std::chrono::high_resolution_clock::now();
const bool conditionMatched = condition->CheckCondition(); bool conditionMatched = false;
condition->WithLock([&condition, &conditionMatched]() {
conditionMatched = condition->CheckCondition();
});
const auto endTime = std::chrono::high_resolution_clock::now(); const auto endTime = std::chrono::high_resolution_clock::now();
const auto timeSpent = endTime - startTime; const auto timeSpent = endTime - startTime;
@@ -444,9 +447,12 @@ bool Macro::RunActionsHelper(
} }
if (action->Enabled()) { if (action->Enabled()) {
action->LogAction(); action->LogAction();
bool actionResult = false;
action->WithLock([&action, &actionResult]() {
actionResult = action->PerformAction();
});
actionsExecutedSuccessfully = actionsExecutedSuccessfully =
actionsExecutedSuccessfully && actionsExecutedSuccessfully && actionResult;
action->PerformAction();
} else { } else {
vblog(LOG_INFO, "skipping disabled action %s", vblog(LOG_INFO, "skipping disabled action %s",
action->GetId().c_str()); action->GetId().c_str());
@@ -724,16 +730,31 @@ std::deque<std::shared_ptr<MacroCondition>> &Macro::Conditions()
return _conditions; return _conditions;
} }
const std::deque<std::shared_ptr<MacroCondition>> &Macro::Conditions() const
{
return _conditions;
}
std::deque<std::shared_ptr<MacroAction>> &Macro::Actions() std::deque<std::shared_ptr<MacroAction>> &Macro::Actions()
{ {
return _actions; return _actions;
} }
const std::deque<std::shared_ptr<MacroAction>> &Macro::Actions() const
{
return _actions;
}
std::deque<std::shared_ptr<MacroAction>> &Macro::ElseActions() std::deque<std::shared_ptr<MacroAction>> &Macro::ElseActions()
{ {
return _elseActions; return _elseActions;
} }
const std::deque<std::shared_ptr<MacroAction>> &Macro::ElseActions() const
{
return _elseActions;
}
static void updateIndicesHelper(std::deque<std::shared_ptr<MacroSegment>> &list) static void updateIndicesHelper(std::deque<std::shared_ptr<MacroSegment>> &list)
{ {
int idx = 0; int idx = 0;
@@ -918,9 +939,12 @@ bool Macro::Load(obs_data_t *obj)
auto newEntry = MacroConditionFactory::Create(id, this); auto newEntry = MacroConditionFactory::Create(id, this);
if (newEntry) { if (newEntry) {
_conditions.emplace_back(newEntry); _conditions.emplace_back(newEntry);
auto c = _conditions.back().get(); auto condition = _conditions.back().get();
c->Load(arrayObj); condition->WithLock([&]() {
c->ValidateLogicSelection(root, Name().c_str()); condition->Load(arrayObj);
condition->ValidateLogicSelection(
root, Name().c_str());
});
} else { } else {
blog(LOG_WARNING, blog(LOG_WARNING,
"discarding condition entry with unknown id (%s) for macro %s", "discarding condition entry with unknown id (%s) for macro %s",
@@ -933,12 +957,15 @@ bool Macro::Load(obs_data_t *obj)
OBSDataArrayAutoRelease actions = obs_data_get_array(obj, "actions"); OBSDataArrayAutoRelease actions = obs_data_get_array(obj, "actions");
count = obs_data_array_count(actions); count = obs_data_array_count(actions);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
OBSDataAutoRelease array_obj = obs_data_array_item(actions, i); OBSDataAutoRelease arrayObj = obs_data_array_item(actions, i);
std::string id = obs_data_get_string(array_obj, "id"); std::string id = obs_data_get_string(arrayObj, "id");
auto newEntry = MacroActionFactory::Create(id, this); auto newEntry = MacroActionFactory::Create(id, this);
if (newEntry) { if (newEntry) {
_actions.emplace_back(newEntry); _actions.emplace_back(newEntry);
_actions.back()->Load(array_obj); auto action = _actions.back().get();
action->WithLock([action, &arrayObj]() {
action->Load(arrayObj);
});
} else { } else {
blog(LOG_WARNING, blog(LOG_WARNING,
"discarding action entry with unknown id (%s) for macro %s", "discarding action entry with unknown id (%s) for macro %s",
@@ -951,13 +978,16 @@ bool Macro::Load(obs_data_t *obj)
obs_data_get_array(obj, "elseActions"); obs_data_get_array(obj, "elseActions");
count = obs_data_array_count(elseActions); count = obs_data_array_count(elseActions);
for (size_t i = 0; i < count; i++) { for (size_t i = 0; i < count; i++) {
OBSDataAutoRelease array_obj = OBSDataAutoRelease arrayObj =
obs_data_array_item(elseActions, i); obs_data_array_item(elseActions, i);
std::string id = obs_data_get_string(array_obj, "id"); std::string id = obs_data_get_string(arrayObj, "id");
auto newEntry = MacroActionFactory::Create(id, this); auto newEntry = MacroActionFactory::Create(id, this);
if (newEntry) { if (newEntry) {
_elseActions.emplace_back(newEntry); _elseActions.emplace_back(newEntry);
_elseActions.back()->Load(array_obj); auto action = _actions.back().get();
action->WithLock([action, &arrayObj]() {
action->Load(arrayObj);
});
} else { } else {
blog(LOG_WARNING, blog(LOG_WARNING,
"discarding elseAction entry with unknown id (%s) for macro %s", "discarding elseAction entry with unknown id (%s) for macro %s",
@@ -974,13 +1004,13 @@ bool Macro::Load(obs_data_t *obj)
bool Macro::PostLoad() bool Macro::PostLoad()
{ {
for (auto &c : _conditions) { for (auto &c : _conditions) {
c->PostLoad(); c->WithLock([c]() { c->PostLoad(); });
} }
for (auto &a : _actions) { for (auto &a : _actions) {
a->PostLoad(); a->WithLock([a]() { a->PostLoad(); });
} }
for (auto &a : _elseActions) { for (auto &a : _elseActions) {
a->PostLoad(); a->WithLock([a]() { a->PostLoad(); });
} }
return true; return true;
} }

View File

@@ -95,8 +95,11 @@ public:
// Macro segments // Macro segments
std::deque<std::shared_ptr<MacroCondition>> &Conditions(); std::deque<std::shared_ptr<MacroCondition>> &Conditions();
const std::deque<std::shared_ptr<MacroCondition>> &Conditions() const;
std::deque<std::shared_ptr<MacroAction>> &Actions(); std::deque<std::shared_ptr<MacroAction>> &Actions();
const std::deque<std::shared_ptr<MacroAction>> &Actions() const;
std::deque<std::shared_ptr<MacroAction>> &ElseActions(); std::deque<std::shared_ptr<MacroAction>> &ElseActions();
const std::deque<std::shared_ptr<MacroAction>> &ElseActions() const;
void UpdateActionIndices(); void UpdateActionIndices();
void UpdateElseActionIndices(); void UpdateElseActionIndices();
void UpdateConditionIndices(); void UpdateConditionIndices();

View File

@@ -25,6 +25,14 @@ SwitcherData::SwitcherData(obs_module_t *m, translateFunc t)
_translate = t; _translate = t;
} }
SwitcherData::~SwitcherData()
{
// Assume that OBS is shutting down, as the switcher object will only be
// destroyed when the plugin is unloaded
obsIsShuttingDown = true;
Stop();
}
const char *SwitcherData::Translate(const char *text) const char *SwitcherData::Translate(const char *text)
{ {
return _translate(text); return _translate(text);
@@ -255,6 +263,16 @@ static void removeMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
} }
} }
static void addNewMacroHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
bool pressed)
{
if (pressed && SettingsWindowIsOpened()) {
QMetaObject::invokeMethod(GetSettingsWindow(),
"on_macroAdd_clicked",
Qt::QueuedConnection);
}
}
static void registerHotkeys() static void registerHotkeys()
{ {
switcher->startHotkey = obs_hotkey_register_frontend( switcher->startHotkey = obs_hotkey_register_frontend(
@@ -270,19 +288,21 @@ static void registerHotkeys()
obs_module_text( obs_module_text(
"AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey"), "AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey"),
startStopToggleHotkeyFunc, NULL); startStopToggleHotkeyFunc, NULL);
switcher->newMacroHotkey = obs_hotkey_register_frontend(
"newMacroSwitcherHotkey",
obs_module_text("AdvSceneSwitcher.hotkey.macro.new"),
addNewMacroHotkeyFunc, NULL);
switcher->upMacroSegment = obs_hotkey_register_frontend( switcher->upMacroSegment = obs_hotkey_register_frontend(
"upMacroSegmentSwitcherHotkey", "upMacroSegmentSwitcherHotkey",
obs_module_text("AdvSceneSwitcher.hotkey.upMacroSegmentHotkey"), obs_module_text("AdvSceneSwitcher.hotkey.macro.segment.up"),
upMacroSegmentHotkeyFunc, NULL); upMacroSegmentHotkeyFunc, NULL);
switcher->downMacroSegment = obs_hotkey_register_frontend( switcher->downMacroSegment = obs_hotkey_register_frontend(
"downMacroSegmentSwitcherHotkey", "downMacroSegmentSwitcherHotkey",
obs_module_text( obs_module_text("AdvSceneSwitcher.hotkey.macro.segment.down"),
"AdvSceneSwitcher.hotkey.downMacroSegmentHotkey"),
downMacroSegmentHotkeyFunc, NULL); downMacroSegmentHotkeyFunc, NULL);
switcher->removeMacroSegment = obs_hotkey_register_frontend( switcher->removeMacroSegment = obs_hotkey_register_frontend(
"removeMacroSegmentSwitcherHotkey", "removeMacroSegmentSwitcherHotkey",
obs_module_text( obs_module_text("AdvSceneSwitcher.hotkey.macro.segment.remove"),
"AdvSceneSwitcher.hotkey.removeMacroSegmentHotkey"),
removeMacroSegmentHotkeyFunc, NULL); removeMacroSegmentHotkeyFunc, NULL);
switcher->hotkeysRegistered = true; switcher->hotkeysRegistered = true;
@@ -300,6 +320,7 @@ void SwitcherData::SaveHotkeys(obs_data_t *obj)
saveHotkey(obj, startHotkey, "startHotkey"); saveHotkey(obj, startHotkey, "startHotkey");
saveHotkey(obj, stopHotkey, "stopHotkey"); saveHotkey(obj, stopHotkey, "stopHotkey");
saveHotkey(obj, toggleHotkey, "toggleHotkey"); saveHotkey(obj, toggleHotkey, "toggleHotkey");
saveHotkey(obj, newMacroHotkey, "newMacroHotkey");
saveHotkey(obj, upMacroSegment, "upMacroSegmentHotkey"); saveHotkey(obj, upMacroSegment, "upMacroSegmentHotkey");
saveHotkey(obj, downMacroSegment, "downMacroSegmentHotkey"); saveHotkey(obj, downMacroSegment, "downMacroSegmentHotkey");
saveHotkey(obj, removeMacroSegment, "removeMacroSegmentHotkey"); saveHotkey(obj, removeMacroSegment, "removeMacroSegmentHotkey");
@@ -312,14 +333,31 @@ static void loadHotkey(obs_data_t *obj, obs_hotkey_id id, const char *name)
obs_data_array_release(a); obs_data_array_release(a);
} }
static void setDefaultHotkeyBinding(obs_data_t *data, const char *name,
const char *value)
{
OBSDataAutoRelease hotkeyData = obs_data_create_from_json(value);
OBSDataArrayAutoRelease hotkeyArray = obs_data_array_create();
obs_data_array_push_back(hotkeyArray, hotkeyData);
obs_data_set_default_array(data, name, hotkeyArray);
}
void SwitcherData::LoadHotkeys(obs_data_t *obj) void SwitcherData::LoadHotkeys(obs_data_t *obj)
{ {
if (!hotkeysRegistered) { if (!hotkeysRegistered) {
registerHotkeys(); registerHotkeys();
} }
setDefaultHotkeyBinding(obj, "newMacroHotkey",
"{"
"\"control\": true,"
"\"key\": \"OBS_KEY_N\""
"}");
loadHotkey(obj, startHotkey, "startHotkey"); loadHotkey(obj, startHotkey, "startHotkey");
loadHotkey(obj, stopHotkey, "stopHotkey"); loadHotkey(obj, stopHotkey, "stopHotkey");
loadHotkey(obj, toggleHotkey, "toggleHotkey"); loadHotkey(obj, toggleHotkey, "toggleHotkey");
loadHotkey(obj, newMacroHotkey, "newMacroHotkey");
loadHotkey(obj, upMacroSegment, "upMacroSegmentHotkey"); loadHotkey(obj, upMacroSegment, "upMacroSegmentHotkey");
loadHotkey(obj, downMacroSegment, "downMacroSegmentHotkey"); loadHotkey(obj, downMacroSegment, "downMacroSegmentHotkey");
loadHotkey(obj, removeMacroSegment, "removeMacroSegmentHotkey"); loadHotkey(obj, removeMacroSegment, "removeMacroSegmentHotkey");

View File

@@ -45,6 +45,9 @@ std::unique_lock<std::mutex> *GetSwitcherLoopLock();
class SwitcherData { class SwitcherData {
public: public:
SwitcherData(obs_module_t *modulePtr, translateFunc translate);
~SwitcherData();
void Thread(); void Thread();
void Start(); void Start();
void Stop(); void Stop();
@@ -85,9 +88,6 @@ public:
/* --- End of saving / loading section --- */ /* --- End of saving / loading section --- */
SwitcherData(obs_module_t *m, translateFunc t);
inline ~SwitcherData() { Stop(); }
public: public:
SwitcherThread *th = nullptr; SwitcherThread *th = nullptr;
std::mutex m; std::mutex m;
@@ -102,7 +102,7 @@ public:
bool firstBoot = true; bool firstBoot = true;
bool transitionActive = false; bool transitionActive = false;
bool sceneColletionStop = false; bool sceneColletionStop = false;
bool obsIsShuttingDown = false; std::atomic_bool obsIsShuttingDown = {false};
bool firstInterval = true; bool firstInterval = true;
bool firstIntervalAfterStop = true; bool firstIntervalAfterStop = true;
bool startupLoadDone = false; bool startupLoadDone = false;
@@ -149,6 +149,7 @@ public:
obs_hotkey_id startHotkey = OBS_INVALID_HOTKEY_ID; obs_hotkey_id startHotkey = OBS_INVALID_HOTKEY_ID;
obs_hotkey_id stopHotkey = OBS_INVALID_HOTKEY_ID; obs_hotkey_id stopHotkey = OBS_INVALID_HOTKEY_ID;
obs_hotkey_id toggleHotkey = OBS_INVALID_HOTKEY_ID; obs_hotkey_id toggleHotkey = OBS_INVALID_HOTKEY_ID;
obs_hotkey_id newMacroHotkey = OBS_INVALID_HOTKEY_ID;
obs_hotkey_id upMacroSegment = OBS_INVALID_HOTKEY_ID; obs_hotkey_id upMacroSegment = OBS_INVALID_HOTKEY_ID;
obs_hotkey_id downMacroSegment = OBS_INVALID_HOTKEY_ID; obs_hotkey_id downMacroSegment = OBS_INVALID_HOTKEY_ID;
obs_hotkey_id removeMacroSegment = OBS_INVALID_HOTKEY_ID; obs_hotkey_id removeMacroSegment = OBS_INVALID_HOTKEY_ID;
@@ -163,6 +164,7 @@ public:
bool warnPluginLoadFailure = true; bool warnPluginLoadFailure = true;
bool disableHints = false; bool disableHints = false;
bool disableFilterComboboxFilter = false; bool disableFilterComboboxFilter = false;
bool disableMacroWidgetCache = false;
bool hideLegacyTabs = true; bool hideLegacyTabs = true;
bool saveWindowGeo = false; bool saveWindowGeo = false;
QPoint windowPos = {}; QPoint windowPos = {};

View File

@@ -7,7 +7,7 @@
namespace advss { namespace advss {
class SliderIgnoreScroll : public QSlider { class ADVSS_EXPORT SliderIgnoreScroll : public QSlider {
Q_OBJECT Q_OBJECT
public: public:

View File

@@ -9,15 +9,14 @@
namespace advss { namespace advss {
class DurationSelection : public QWidget { class ADVSS_EXPORT DurationSelection : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
EXPORT DurationSelection(QWidget *parent = nullptr, DurationSelection(QWidget *parent = nullptr,
bool showUnitSelection = true, bool showUnitSelection = true, double minValue = 0.0);
double minValue = 0.0); void SetDuration(const Duration &);
EXPORT void SetDuration(const Duration &);
Duration GetDuration() const { return _current; } Duration GetDuration() const { return _current; }
EXPORT QDoubleSpinBox *SpinBox() { return _duration->SpinBox(); } QDoubleSpinBox *SpinBox() { return _duration->SpinBox(); }
private slots: private slots:
void _DurationChanged(const NumberVariable<double> &value); void _DurationChanged(const NumberVariable<double> &value);

View File

@@ -62,6 +62,11 @@ void FilterComboBox::SetFilterBehaviourEnabled(bool value)
FilterComboBox::_filteringEnabled = value; FilterComboBox::_filteringEnabled = value;
} }
void FilterComboBox::SetAllowUnmatchedSelection(bool allow)
{
_allowUnmatchedSelection = allow;
}
void FilterComboBox::setCurrentText(const QString &text) void FilterComboBox::setCurrentText(const QString &text)
{ {
if (_filteringEnabled) { if (_filteringEnabled) {
@@ -82,7 +87,7 @@ void FilterComboBox::setItemText(int index, const QString &text)
void FilterComboBox::focusOutEvent(QFocusEvent *event) void FilterComboBox::focusOutEvent(QFocusEvent *event)
{ {
// Reset on invalid selection // Reset on invalid selection
if (findText(currentText()) == -1) { if (!_allowUnmatchedSelection && findText(currentText()) == -1) {
setCurrentIndex(-1); setCurrentIndex(-1);
Emit(-1, ""); Emit(-1, "");
} }

View File

@@ -13,6 +13,7 @@ public:
FilterComboBox(QWidget *parent = nullptr, FilterComboBox(QWidget *parent = nullptr,
const QString &placehodler = ""); const QString &placehodler = "");
static void SetFilterBehaviourEnabled(bool); static void SetFilterBehaviourEnabled(bool);
void SetAllowUnmatchedSelection(bool allow);
void setCurrentText(const QString &text); void setCurrentText(const QString &text);
void setItemText(int index, const QString &text); void setItemText(int index, const QString &text);
@@ -27,6 +28,7 @@ private slots:
private: private:
void Emit(int index, const QString &text); void Emit(int index, const QString &text);
bool _allowUnmatchedSelection = false;
int _lastEmittedIndex = -1; int _lastEmittedIndex = -1;
QString _lastEmittedText; QString _lastEmittedText;

View File

@@ -9,6 +9,27 @@ namespace advss {
template<class T> class MessageDispatcher { template<class T> class MessageDispatcher {
public: public:
MessageDispatcher() = default;
~MessageDispatcher() = default;
MessageDispatcher(const MessageDispatcher &other)
: _clients(other._clients)
{
}
MessageDispatcher(MessageDispatcher &&other) noexcept
: _clients(other._clients)
{
}
MessageDispatcher<T> &operator=(const MessageDispatcher<T> &other)
{
_clients = other._clients;
return *this;
}
MessageDispatcher<T> &operator=(MessageDispatcher<T> &&other) noexcept
{
std::swap(_clients, other._clients);
return *this;
}
[[nodiscard]] std::shared_ptr<MessageBuffer<T>> RegisterClient(); [[nodiscard]] std::shared_ptr<MessageBuffer<T>> RegisterClient();
void DispatchMessage(const T &message); void DispatchMessage(const T &message);

View File

@@ -25,8 +25,8 @@ EXPORT void StopPlugin();
EXPORT void StartPlugin(); EXPORT void StartPlugin();
EXPORT bool PluginIsRunning(); EXPORT bool PluginIsRunning();
EXPORT int GetIntervalValue(); EXPORT int GetIntervalValue();
void AddStartStep(std::function<void()>); EXPORT void AddStartStep(std::function<void()>);
void AddStopStep(std::function<void()>); EXPORT void AddStopStep(std::function<void()>);
void RunStartSteps(); void RunStartSteps();
void RunStopSteps(); void RunStopSteps();
void RunIntervalResetSteps(); void RunIntervalResetSteps();

View File

@@ -5,15 +5,15 @@
namespace advss { namespace advss {
class ResizingPlainTextEdit : public QPlainTextEdit { class ADVSS_EXPORT ResizingPlainTextEdit : public QPlainTextEdit {
Q_OBJECT Q_OBJECT
public: public:
ResizingPlainTextEdit(QWidget *parent, const int scrollAt = 10, ResizingPlainTextEdit(QWidget *parent, const int scrollAt = 10,
const int minLines = 3, const int minLines = 3,
const int paddingLines = 2); const int paddingLines = 2);
virtual ~ResizingPlainTextEdit(){}; virtual ~ResizingPlainTextEdit(){};
EXPORT int maxLength(); int maxLength();
EXPORT void setMaxLength(int maxLength); void setMaxLength(int maxLength);
protected: protected:
bool eventFilter(QObject *obj, QEvent *event) override; bool eventFilter(QObject *obj, QEvent *event) override;

View File

@@ -1,70 +0,0 @@
#include "resource-table-hotkey-handler.hpp"
#include <QKeyEvent>
#include <QWidget>
#include <unordered_map>
namespace advss {
void RegisterHotkeyFunction(QWidget *widget, Qt::Key key,
std::function<void()> func)
{
ResourceTabHotkeyHandler::Instance()->RegisterHandler(widget, key,
func);
}
void DeregisterHotkeyFunctions(QWidget *widget)
{
ResourceTabHotkeyHandler::Instance()->Deregister(widget);
}
ResourceTabHotkeyHandler *ResourceTabHotkeyHandler::Instance()
{
static ResourceTabHotkeyHandler handler;
return &handler;
}
void ResourceTabHotkeyHandler::RegisterHandler(QWidget *widget, Qt::Key key,
std::function<void()> func)
{
std::lock_guard<std::mutex> lock(_mutex);
_callbacks.emplace(widget, CallbackData{key, func});
widget->installEventFilter(this);
}
void ResourceTabHotkeyHandler::Deregister(QWidget *widget)
{
std::lock_guard<std::mutex> lock(_mutex);
_callbacks.erase(widget);
}
bool ResourceTabHotkeyHandler::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() != QEvent::KeyPress) {
return QObject::eventFilter(obj, event);
}
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
auto pressedKey = keyEvent->key();
std::lock_guard<std::mutex> lock(_mutex);
auto it = _callbacks.find(obj);
if (it == _callbacks.end()) {
return QObject::eventFilter(obj, event);
}
auto current = it;
while (current != _callbacks.end() && current->first == it->first) {
auto &[_, cbData] = *current;
if (pressedKey != cbData.key) {
++current;
continue;
}
cbData.func();
++current;
continue;
}
return QObject::eventFilter(obj, event);
}
} // namespace advss

View File

@@ -1,37 +0,0 @@
#pragma once
#include "export-symbol-helper.hpp"
#include <map>
#include <mutex>
#include <QEvent>
#include <QObject>
namespace advss {
EXPORT void RegisterHotkeyFunction(QWidget *, Qt::Key,
std::function<void()> func);
EXPORT void DeregisterHotkeyFunctions(QWidget *);
class ResourceTabHotkeyHandler : public QObject {
Q_OBJECT
public:
static ResourceTabHotkeyHandler *Instance();
void RegisterHandler(QWidget *, Qt::Key, std::function<void()> func);
void Deregister(QWidget *);
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
private:
struct CallbackData {
Qt::Key key;
std::function<void()> func;
};
ResourceTabHotkeyHandler() : QObject(){};
std::multimap<QObject *, CallbackData> _callbacks;
std::mutex _mutex;
};
} // namespace advss

View File

@@ -1,10 +1,10 @@
#include "resource-table.hpp" #include "resource-table.hpp"
#include "plugin-state-helpers.hpp" #include "plugin-state-helpers.hpp"
#include "resource-table-hotkey-handler.hpp"
#include "ui-helpers.hpp" #include "ui-helpers.hpp"
#include <QGridLayout> #include <QGridLayout>
#include <QHeaderView> #include <QHeaderView>
#include <QShortcut>
namespace advss { namespace advss {
@@ -64,13 +64,16 @@ ResourceTable::ResourceTable(QTabWidget *parent, const QString &help,
QWidget::connect(_table, &QTableWidget::cellDoubleClicked, QWidget::connect(_table, &QTableWidget::cellDoubleClicked,
[openSettings]() { openSettings(); }); [openSettings]() { openSettings(); });
RegisterHotkeyFunction(this, Qt::Key_F2, openSettings); auto settingsShortcut = new QShortcut(QKeySequence("F2"), this);
RegisterHotkeyFunction(this, Qt::Key_Delete, [this]() { Remove(); }); QWidget::connect(settingsShortcut, &QShortcut::activated, this,
} openSettings);
auto removeShortcut = new QShortcut(QKeySequence("Del"), this);
QWidget::connect(removeShortcut, &QShortcut::activated, this,
[this]() { Remove(); });
ResourceTable::~ResourceTable() auto newShortcut = new QShortcut(QKeySequence("Ctrl+N"), this);
{ QWidget::connect(newShortcut, &QShortcut::activated, this,
DeregisterHotkeyFunctions(this); [this]() { Add(); });
} }
void ResourceTable::SetHelpVisible(bool visible) const void ResourceTable::SetHelpVisible(bool visible) const

View File

@@ -18,7 +18,6 @@ public:
const QString &addToolTip, const QString &removeToolTip, const QString &addToolTip, const QString &removeToolTip,
const QStringList &headers, const QStringList &headers,
const std::function<void()> &openSettings); const std::function<void()> &openSettings);
virtual ~ResourceTable();
QTableWidget *Table() const { return _table; } QTableWidget *Table() const { return _table; }
void SetHelpVisible(bool) const; void SetHelpVisible(bool) const;

View File

@@ -409,6 +409,13 @@ void SceneSelectionWidget::SetScene(const SceneSelection &s)
_currentSelection = s; _currentSelection = s;
} }
void SceneSelectionWidget::showEvent(QShowEvent *event)
{
FilterComboBox::showEvent(event);
const QSignalBlocker b(this);
Reset();
}
bool SceneSelectionWidget::IsCurrentSceneSelected(const QString &name) bool SceneSelectionWidget::IsCurrentSceneSelected(const QString &name)
{ {
return name == QString::fromStdString((obs_module_text( return name == QString::fromStdString((obs_module_text(
@@ -435,9 +442,8 @@ void SceneSelectionWidget::SelectionChanged(int)
void SceneSelectionWidget::ItemAdd(const QString &) void SceneSelectionWidget::ItemAdd(const QString &)
{ {
blockSignals(true); const QSignalBlocker b(this);
Reset(); Reset();
blockSignals(false);
} }
bool SceneSelectionWidget::NameUsed(const QString &name) bool SceneSelectionWidget::NameUsed(const QString &name)
@@ -462,9 +468,8 @@ void SceneSelectionWidget::ItemRemove(const QString &name)
void SceneSelectionWidget::ItemRename(const QString &, const QString &) void SceneSelectionWidget::ItemRename(const QString &, const QString &)
{ {
blockSignals(true); const QSignalBlocker b(this);
Reset(); Reset();
blockSignals(false);
} }
} // namespace advss } // namespace advss

View File

@@ -45,6 +45,10 @@ public:
bool previous = false, bool current = false, bool previous = false, bool current = false,
bool preview = false); bool preview = false);
EXPORT void SetScene(const SceneSelection &); EXPORT void SetScene(const SceneSelection &);
protected:
void showEvent(QShowEvent *event) override;
signals: signals:
void SceneChanged(const SceneSelection &); void SceneChanged(const SceneSelection &);

View File

@@ -164,7 +164,7 @@ void SourceSelectionWidget::PopulateSelection()
} }
_variablesEndIdx = count(); _variablesEndIdx = count();
AddSelectionGroup(this, _sourceNames); AddSelectionGroup(this, _populateSourcesCallback());
_sourcesEndIdx = count(); _sourcesEndIdx = count();
// Remove last separator // Remove last separator
@@ -172,13 +172,13 @@ void SourceSelectionWidget::PopulateSelection()
setCurrentIndex(-1); setCurrentIndex(-1);
} }
SourceSelectionWidget::SourceSelectionWidget(QWidget *parent, SourceSelectionWidget::SourceSelectionWidget(
const QStringList &sourceNames, QWidget *parent, const std::function<QStringList()> &populate,
bool addVariables) bool addVariables)
: FilterComboBox(parent, : FilterComboBox(parent,
obs_module_text("AdvSceneSwitcher.selectSource")), obs_module_text("AdvSceneSwitcher.selectSource")),
_addVariables(addVariables), _addVariables(addVariables),
_sourceNames(sourceNames) _populateSourcesCallback(populate)
{ {
setDuplicatesEnabled(true); setDuplicatesEnabled(true);
PopulateSelection(); PopulateSelection();
@@ -200,6 +200,11 @@ SourceSelectionWidget::SourceSelectionWidget(QWidget *parent,
void SourceSelectionWidget::SetSource(const SourceSelection &s) void SourceSelectionWidget::SetSource(const SourceSelection &s)
{ {
{
const QSignalBlocker b(this);
PopulateSelection();
}
int idx = -1; int idx = -1;
switch (s.GetType()) { switch (s.GetType()) {
@@ -229,23 +234,23 @@ void SourceSelectionWidget::SetSource(const SourceSelection &s)
_currentSelection = s; _currentSelection = s;
} }
void SourceSelectionWidget::SetSourceNameList(const QStringList &list)
{
_sourceNames = list;
Reset();
}
void SourceSelectionWidget::SelectionChanged(int) void SourceSelectionWidget::SelectionChanged(int)
{ {
_currentSelection = CurrentSelection(); _currentSelection = CurrentSelection();
emit SourceChanged(_currentSelection); emit SourceChanged(_currentSelection);
} }
void SourceSelectionWidget::showEvent(QShowEvent *event)
{
FilterComboBox::showEvent(event);
const QSignalBlocker b(this);
Reset();
}
void SourceSelectionWidget::ItemAdd(const QString &) void SourceSelectionWidget::ItemAdd(const QString &)
{ {
blockSignals(true); const QSignalBlocker b(this);
Reset(); Reset();
blockSignals(false);
} }
bool SourceSelectionWidget::NameUsed(const QString &name) bool SourceSelectionWidget::NameUsed(const QString &name)
@@ -265,9 +270,8 @@ void SourceSelectionWidget::ItemRemove(const QString &name)
void SourceSelectionWidget::ItemRename(const QString &, const QString &) void SourceSelectionWidget::ItemRename(const QString &, const QString &)
{ {
blockSignals(true); const QSignalBlocker b(this);
Reset(); Reset();
blockSignals(false);
} }
} // namespace advss } // namespace advss

View File

@@ -39,13 +39,16 @@ class ADVSS_EXPORT SourceSelectionWidget : public FilterComboBox {
Q_OBJECT Q_OBJECT
public: public:
SourceSelectionWidget(QWidget *parent, const QStringList &sourceNames, SourceSelectionWidget(QWidget *parent,
const std::function<QStringList()> &populate,
bool addVariables = true); bool addVariables = true);
void SetSource(const SourceSelection &); void SetSource(const SourceSelection &);
void SetSourceNameList(const QStringList &);
signals: signals:
void SourceChanged(const SourceSelection &); void SourceChanged(const SourceSelection &);
protected:
void showEvent(QShowEvent *event) override;
private slots: private slots:
void SelectionChanged(int); void SelectionChanged(int);
void ItemAdd(const QString &name); void ItemAdd(const QString &name);
@@ -59,7 +62,7 @@ private:
bool NameUsed(const QString &name); bool NameUsed(const QString &name);
bool _addVariables; bool _addVariables;
QStringList _sourceNames; std::function<QStringList()> _populateSourcesCallback;
SourceSelection _currentSelection; SourceSelection _currentSelection;
// Order of entries // Order of entries

View File

@@ -20,4 +20,36 @@ std::unique_lock<std::mutex> *GetLoopLock()
return GetSwitcherLoopLock(); return GetSwitcherLoopLock();
} }
PerInstanceMutex::PerInstanceMutex() {}
PerInstanceMutex::~PerInstanceMutex(){};
PerInstanceMutex::PerInstanceMutex(const PerInstanceMutex &) {}
PerInstanceMutex &PerInstanceMutex::operator=(const PerInstanceMutex &)
{
return *this;
}
PerInstanceMutex::operator std::mutex &()
{
return _mtx;
}
PerInstanceMutex::operator const std::mutex &() const
{
return _mtx;
}
std::lock_guard<std::mutex> Lockable::Lock()
{
return std::lock_guard<std::mutex>(_mtx);
}
void Lockable::WithLock(const std::function<void()> &func)
{
const auto lock = Lock();
func();
}
} // namespace advss } // namespace advss

View File

@@ -1,6 +1,8 @@
#pragma once #pragma once
#include "export-symbol-helper.hpp" #include "export-symbol-helper.hpp"
#include <functional>
#include <memory>
#include <mutex> #include <mutex>
namespace advss { namespace advss {
@@ -10,10 +12,46 @@ namespace advss {
if (_loading || !_entryData) { \ if (_loading || !_entryData) { \
return; \ return; \
} \ } \
auto lock = LockContext(); auto lock = _entryData->Lock();
[[nodiscard]] EXPORT std::mutex *GetMutex(); [[nodiscard]] EXPORT std::mutex *GetMutex();
[[nodiscard]] EXPORT std::lock_guard<std::mutex> LockContext(); [[nodiscard]] EXPORT std::lock_guard<std::mutex> LockContext();
[[nodiscard]] EXPORT std::unique_lock<std::mutex> *GetLoopLock(); [[nodiscard]] EXPORT std::unique_lock<std::mutex> *GetLoopLock();
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4251)
#endif
// std::mutex wrapper with no-op copy constructor and assignment operator
class EXPORT PerInstanceMutex {
public:
PerInstanceMutex();
~PerInstanceMutex();
PerInstanceMutex(const PerInstanceMutex &);
PerInstanceMutex &operator=(const PerInstanceMutex &);
operator std::mutex &();
operator const std::mutex &() const;
private:
std::mutex _mtx;
};
#ifdef _MSC_VER
#pragma warning(pop)
#endif
class EXPORT Lockable {
public:
Lockable() = default;
virtual ~Lockable() = default;
[[nodiscard]] std::lock_guard<std::mutex> Lock();
void WithLock(const std::function<void()> &func);
private:
PerInstanceMutex _mtx;
};
} // namespace advss } // namespace advss

View File

@@ -274,8 +274,9 @@ TempVariableSelection::TempVariableSelection(QWidget *parent)
SLOT(HighlightChanged(int))); SLOT(HighlightChanged(int)));
QWidget::connect(window(), SIGNAL(MacroSegmentOrderChanged()), this, QWidget::connect(window(), SIGNAL(MacroSegmentOrderChanged()), this,
SLOT(MacroSegmentsChanged())); SLOT(MacroSegmentsChanged()));
QWidget::connect(window(), SIGNAL(SegmentTempVarsChanged()), this, QWidget::connect(window(),
SLOT(SegmentTempVarsChanged())); SIGNAL(SegmentTempVarsChanged(MacroSegment *)), this,
SLOT(SegmentTempVarsChanged(MacroSegment *)));
auto layout = new QHBoxLayout(); auto layout = new QHBoxLayout();
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
@@ -314,9 +315,15 @@ void TempVariableSelection::MacroSegmentsChanged()
SetVariable(currentSelection); SetVariable(currentSelection);
} }
void TempVariableSelection::SegmentTempVarsChanged() void TempVariableSelection::SegmentTempVarsChanged(MacroSegment *segment)
{ {
MacroSegmentsChanged(); const auto currentSegment = GetSegment();
const auto currentMacro = currentSegment ? currentSegment->GetMacro()
: nullptr;
const auto changeMacro = segment ? segment->GetMacro() : nullptr;
if (currentMacro == changeMacro) {
MacroSegmentsChanged();
}
} }
void TempVariableSelection::HighlightChanged(int idx) void TempVariableSelection::HighlightChanged(int idx)
@@ -427,13 +434,11 @@ QString TempVariableSelection::SetupInfoLabel()
MacroSegment *TempVariableSelection::GetSegment() const MacroSegment *TempVariableSelection::GetSegment() const
{ {
const QWidget *widget = this; const QWidget *widget = this;
{ while (widget) {
while (widget) { if (qobject_cast<const MacroSegmentEdit *>(widget)) {
if (qobject_cast<const MacroSegmentEdit *>(widget)) { break;
break;
}
widget = widget->parentWidget();
} }
widget = widget->parentWidget();
} }
if (!widget) { if (!widget) {
return nullptr; return nullptr;
@@ -442,17 +447,18 @@ MacroSegment *TempVariableSelection::GetSegment() const
return segmentWidget->Data().get(); return segmentWidget->Data().get();
} }
void NotifyUIAboutTempVarChange() void NotifyUIAboutTempVarChange(MacroSegment *segment)
{ {
obs_queue_task( obs_queue_task(
OBS_TASK_UI, OBS_TASK_UI,
[](void *) { [](void *segment) {
if (!SettingsWindowIsOpened()) { if (!SettingsWindowIsOpened()) {
return; return;
} }
AdvSceneSwitcher::window->SegmentTempVarsChanged(); AdvSceneSwitcher::window->SegmentTempVarsChanged(
(MacroSegment *)segment);
}, },
nullptr, false); segment, false);
} }
} // namespace advss } // namespace advss

View File

@@ -88,7 +88,7 @@ public:
private slots: private slots:
void SelectionIdxChanged(int); void SelectionIdxChanged(int);
void MacroSegmentsChanged(); void MacroSegmentsChanged();
void SegmentTempVarsChanged(); void SegmentTempVarsChanged(MacroSegment *);
void HighlightChanged(int); void HighlightChanged(int);
signals: signals:
@@ -104,6 +104,6 @@ private:
AutoUpdateTooltipLabel *_info; AutoUpdateTooltipLabel *_info;
}; };
void NotifyUIAboutTempVarChange(); void NotifyUIAboutTempVarChange(MacroSegment *);
} // namespace advss } // namespace advss

View File

@@ -6,6 +6,7 @@
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
#include <QGraphicsColorizeEffect> #include <QGraphicsColorizeEffect>
#include <QListView>
#include <QMainWindow> #include <QMainWindow>
#include <QPropertyAnimation> #include <QPropertyAnimation>
#include <QScrollBar> #include <QScrollBar>
@@ -104,6 +105,19 @@ int FindIdxInRagne(QComboBox *list, int start, int stop,
return foundIdx; return foundIdx;
} }
void SetRowVisibleByValue(QComboBox *list, const QString &value, bool show)
{
int index = list->findText(value);
if (index == -1) {
return;
}
auto view = qobject_cast<QListView *>(list->view());
if (view) {
view->setRowHidden(index, !show);
}
}
QWidget *GetSettingsWindow() QWidget *GetSettingsWindow()
{ {
return SettingsWindowIsOpened() ? AdvSceneSwitcher::window : nullptr; return SettingsWindowIsOpened() ? AdvSceneSwitcher::window : nullptr;

View File

@@ -20,9 +20,12 @@ EXPORT QObject *HighlightWidget(QWidget *widget, QColor startColor,
EXPORT void SetHeightToContentHeight(QListWidget *list); EXPORT void SetHeightToContentHeight(QListWidget *list);
EXPORT void SetButtonIcon(QAbstractButton *button, const char *path); EXPORT void SetButtonIcon(QAbstractButton *button, const char *path);
EXPORT int EXPORT int
FindIdxInRagne(QComboBox *list, int start, int stop, const std::string &value, FindIdxInRagne(QComboBox *list, int start, int stop, const std::string &value,
Qt::MatchFlags = Qt::MatchExactly | Qt::MatchCaseSensitive); Qt::MatchFlags = Qt::MatchExactly | Qt::MatchCaseSensitive);
EXPORT void SetRowVisibleByValue(QComboBox *list, const QString &value,
bool show);
EXPORT bool DisplayMessage(const QString &msg, bool question = false, EXPORT bool DisplayMessage(const QString &msg, bool question = false,
bool modal = true); bool modal = true);

View File

@@ -117,9 +117,25 @@ void RegisterWebsocketRequest(
}); });
} }
static bool websocketModuleIsLoaded()
{
bool websocketModuleFound = false;
const auto checkModule = [](void *param, obs_module_t *module) {
bool *moduleFound = static_cast<bool *>(param);
auto name = obs_get_module_name(module);
if (name && strcmp(name, "obs-websocket") == 0) {
*moduleFound = true;
}
};
obs_enum_modules(checkModule, &websocketModuleFound);
return websocketModuleFound;
}
void SendWebsocketVendorEvent(const std::string &eventName, obs_data_t *data) void SendWebsocketVendorEvent(const std::string &eventName, obs_data_t *data)
{ {
if (OBSIsShuttingDown()) { // If obs-websocket was loaded, but was unloaded at some point any calls
// to obs_websocket_vendor_emit_event() will segfault
if (OBSIsShuttingDown() || !websocketModuleIsLoaded()) {
return; return;
} }
obs_websocket_vendor_emit_event(vendor, eventName.c_str(), data); obs_websocket_vendor_emit_event(vendor, eventName.c_str(), data);

View File

@@ -4,15 +4,15 @@
namespace advss { namespace advss {
class VariableTextEdit : public ResizingPlainTextEdit { class ADVSS_EXPORT VariableTextEdit : public ResizingPlainTextEdit {
Q_OBJECT Q_OBJECT
public: public:
EXPORT VariableTextEdit(QWidget *parent, const int scrollAt = 10, VariableTextEdit(QWidget *parent, const int scrollAt = 10,
const int minLines = 3, const int minLines = 3, const int paddingLines = 2);
const int paddingLines = 2); virtual ~VariableTextEdit(){};
EXPORT void setPlainText(const QString &); void setPlainText(const QString &);
EXPORT void setPlainText(const StringVariable &); void setPlainText(const StringVariable &);
EXPORT void setToolTip(const QString &string); void setToolTip(const QString &string);
private: private:
}; };

View File

@@ -30,7 +30,9 @@ install_advss_plugin_dependency(...)
add_plugin(http) add_plugin(http)
add_plugin(midi) add_plugin(midi)
add_plugin(mqtt)
add_plugin(openvr) add_plugin(openvr)
add_plugin(scripting)
add_plugin(stream-deck) add_plugin(stream-deck)
add_plugin(twitch) add_plugin(twitch)
add_plugin(usb) add_plugin(usb)

View File

@@ -21,6 +21,8 @@ target_sources(
macro-action-log.hpp macro-action-log.hpp
macro-action-media.cpp macro-action-media.cpp
macro-action-media.hpp macro-action-media.hpp
macro-action-obs-settings.cpp
macro-action-obs-settings.hpp
macro-action-osc.cpp macro-action-osc.cpp
macro-action-osc.hpp macro-action-osc.hpp
macro-action-plugin-state.cpp macro-action-plugin-state.cpp
@@ -181,7 +183,9 @@ target_sources(
utils/websocket-helpers.cpp utils/websocket-helpers.cpp
utils/websocket-helpers.hpp utils/websocket-helpers.hpp
utils/websocket-tab.cpp utils/websocket-tab.cpp
utils/websocket-tab.hpp) utils/websocket-tab.hpp
utils/window-selection.cpp
utils/window-selection.hpp)
if(OS_WINDOWS) if(OS_WINDOWS)
target_sources(${PROJECT_NAME} PRIVATE utils/windows/windows.cpp) target_sources(${PROJECT_NAME} PRIVATE utils/windows/windows.cpp)

View File

@@ -421,10 +421,17 @@ static inline void populateFadeTypeSelection(QComboBox *list)
} }
} }
static QStringList getAudioSourcesList()
{
auto sources = GetAudioSourceNames();
sources.sort();
return sources;
}
MacroActionAudioEdit::MacroActionAudioEdit( MacroActionAudioEdit::MacroActionAudioEdit(
QWidget *parent, std::shared_ptr<MacroActionAudio> entryData) QWidget *parent, std::shared_ptr<MacroActionAudio> entryData)
: QWidget(parent), : QWidget(parent),
_sources(new SourceSelectionWidget(this, QStringList(), true)), _sources(new SourceSelectionWidget(this, getAudioSourcesList, true)),
_actions(new QComboBox), _actions(new QComboBox),
_fadeTypes(new QComboBox), _fadeTypes(new QComboBox),
_syncOffset(new VariableSpinBox), _syncOffset(new VariableSpinBox),
@@ -468,9 +475,6 @@ MacroActionAudioEdit::MacroActionAudioEdit(
_rate->setSuffix("%"); _rate->setSuffix("%");
populateActionSelection(_actions); populateActionSelection(_actions);
auto sources = GetAudioSourceNames();
sources.sort();
_sources->SetSourceNameList(sources);
populateFadeTypeSelection(_fadeTypes); populateFadeTypeSelection(_fadeTypes);
PopulateMonitorTypeSelection(_monitorTypes); PopulateMonitorTypeSelection(_monitorTypes);
@@ -518,7 +522,7 @@ MacroActionAudioEdit::MacroActionAudioEdit(
QWidget::connect(_fadeTypes, SIGNAL(currentIndexChanged(int)), this, QWidget::connect(_fadeTypes, SIGNAL(currentIndexChanged(int)), this,
SLOT(FadeTypeChanged(int))); SLOT(FadeTypeChanged(int)));
std::unordered_map<std::string, QWidget *> widgetPlaceholders = { const std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{audioSources}}", _sources}, {"{{audioSources}}", _sources},
{"{{actions}}", _actions}, {"{{actions}}", _actions},
{"{{syncOffset}}", _syncOffset}, {"{{syncOffset}}", _syncOffset},
@@ -662,11 +666,7 @@ void MacroActionAudioEdit::UpdateEntryData()
void MacroActionAudioEdit::SourceChanged(const SourceSelection &source) void MacroActionAudioEdit::SourceChanged(const SourceSelection &source)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_audioSource = source; _entryData->_audioSource = source;
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));
@@ -674,11 +674,7 @@ void MacroActionAudioEdit::SourceChanged(const SourceSelection &source)
void MacroActionAudioEdit::ActionChanged(int idx) void MacroActionAudioEdit::ActionChanged(int idx)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_action = static_cast<MacroActionAudio::Action>( _entryData->_action = static_cast<MacroActionAudio::Action>(
_actions->itemData(idx).toInt()); _actions->itemData(idx).toInt());
SetWidgetVisibility(); SetWidgetVisibility();
@@ -686,133 +682,81 @@ void MacroActionAudioEdit::ActionChanged(int idx)
void MacroActionAudioEdit::SyncOffsetChanged(const NumberVariable<int> &value) void MacroActionAudioEdit::SyncOffsetChanged(const NumberVariable<int> &value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_syncOffset = value; _entryData->_syncOffset = value;
} }
void MacroActionAudioEdit::MonitorTypeChanged(int value) void MacroActionAudioEdit::MonitorTypeChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_monitorType = static_cast<obs_monitoring_type>(value); _entryData->_monitorType = static_cast<obs_monitoring_type>(value);
} }
void MacroActionAudioEdit::BalanceChanged(const NumberVariable<double> &value) void MacroActionAudioEdit::BalanceChanged(const NumberVariable<double> &value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_balance = value; _entryData->_balance = value;
} }
void MacroActionAudioEdit::TrackChanged(const NumberVariable<int> &value) void MacroActionAudioEdit::TrackChanged(const NumberVariable<int> &value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_track = value; _entryData->_track = value;
} }
void MacroActionAudioEdit::VolumeDBChanged(const NumberVariable<double> &value) void MacroActionAudioEdit::VolumeDBChanged(const NumberVariable<double> &value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_volumeDB = value; _entryData->_volumeDB = value;
} }
void MacroActionAudioEdit::PercentDBClicked() void MacroActionAudioEdit::PercentDBClicked()
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_useDb = !_entryData->_useDb; _entryData->_useDb = !_entryData->_useDb;
SetWidgetVisibility(); SetWidgetVisibility();
} }
void MacroActionAudioEdit::VolumeChanged(const NumberVariable<int> &value) void MacroActionAudioEdit::VolumeChanged(const NumberVariable<int> &value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_volume = value; _entryData->_volume = value;
} }
void MacroActionAudioEdit::FadeChanged(int value) void MacroActionAudioEdit::FadeChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_fade = value; _entryData->_fade = value;
SetWidgetVisibility(); SetWidgetVisibility();
} }
void MacroActionAudioEdit::DurationChanged(const Duration &dur) void MacroActionAudioEdit::DurationChanged(const Duration &dur)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_duration = dur; _entryData->_duration = dur;
} }
void MacroActionAudioEdit::RateChanged(const NumberVariable<double> &value) void MacroActionAudioEdit::RateChanged(const NumberVariable<double> &value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_rate = value; _entryData->_rate = value;
} }
void MacroActionAudioEdit::WaitChanged(int value) void MacroActionAudioEdit::WaitChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_wait = value; _entryData->_wait = value;
} }
void MacroActionAudioEdit::AbortActiveFadeChanged(int value) void MacroActionAudioEdit::AbortActiveFadeChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_abortActiveFade = value; _entryData->_abortActiveFade = value;
} }
void MacroActionAudioEdit::FadeTypeChanged(int value) void MacroActionAudioEdit::FadeTypeChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_fadeType = static_cast<MacroActionAudio::FadeType>(value); _entryData->_fadeType = static_cast<MacroActionAudio::FadeType>(value);
SetWidgetVisibility(); SetWidgetVisibility();
} }

View File

@@ -214,11 +214,7 @@ MacroActionClipboardEdit::MacroActionClipboardEdit(
void MacroActionClipboardEdit::ActionChanged(int index) void MacroActionClipboardEdit::ActionChanged(int index)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_action = static_cast<MacroActionClipboard::Action>( _entryData->_action = static_cast<MacroActionClipboard::Action>(
_actions->itemData(index).toInt()); _actions->itemData(index).toInt());
@@ -227,21 +223,13 @@ void MacroActionClipboardEdit::ActionChanged(int index)
void MacroActionClipboardEdit::TextChanged() void MacroActionClipboardEdit::TextChanged()
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_text = _text->text().toStdString(); _entryData->_text = _text->text().toStdString();
} }
void MacroActionClipboardEdit::UrlChanged() void MacroActionClipboardEdit::UrlChanged()
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_url = _url->text().toStdString(); _entryData->_url = _url->text().toStdString();
} }

View File

@@ -153,11 +153,7 @@ void MacroActionFileEdit::UpdateEntryData()
void MacroActionFileEdit::PathChanged(const QString &text) void MacroActionFileEdit::PathChanged(const QString &text)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_file = text.toUtf8().constData(); _entryData->_file = text.toUtf8().constData();
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));
@@ -165,11 +161,7 @@ void MacroActionFileEdit::PathChanged(const QString &text)
void MacroActionFileEdit::TextChanged() void MacroActionFileEdit::TextChanged()
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_text = _text->toPlainText().toStdString(); _entryData->_text = _text->toPlainText().toStdString();
adjustSize(); adjustSize();
@@ -178,11 +170,7 @@ void MacroActionFileEdit::TextChanged()
void MacroActionFileEdit::ActionChanged(int value) void MacroActionFileEdit::ActionChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_action = static_cast<MacroActionFile::Action>(value); _entryData->_action = static_cast<MacroActionFile::Action>(value);
} }

View File

@@ -3,6 +3,7 @@
#include "json-helpers.hpp" #include "json-helpers.hpp"
#include "source-settings-helpers.hpp" #include "source-settings-helpers.hpp"
#include "selection-helpers.hpp" #include "selection-helpers.hpp"
#include "ui-helpers.hpp"
namespace advss { namespace advss {
@@ -26,10 +27,13 @@ const static std::map<MacroActionFilter::Action, std::string> actionTypes = {
"AdvSceneSwitcher.action.filter.type.pressSettingsButton"}, "AdvSceneSwitcher.action.filter.type.pressSettingsButton"},
}; };
const static std::map<MacroActionFilter::SettingsInputMethod, std::string> const static std::vector<
std::pair<MacroActionFilter::SettingsInputMethod, std::string>>
inputMethods = { inputMethods = {
{MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL, {MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL,
"AdvSceneSwitcher.action.filter.inputMethod.individualManual"}, "AdvSceneSwitcher.action.filter.inputMethod.individualManual"},
{MacroActionFilter::SettingsInputMethod::INDIVIDUAL_LIST_ENTRY,
"AdvSceneSwitcher.action.filter.inputMethod.individualListEntryManual"},
{MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR, {MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR,
"AdvSceneSwitcher.action.filter.inputMethod.individualTempvar"}, "AdvSceneSwitcher.action.filter.inputMethod.individualTempvar"},
{MacroActionFilter::SettingsInputMethod::JSON_STRING, {MacroActionFilter::SettingsInputMethod::JSON_STRING,
@@ -59,6 +63,10 @@ static void performActionHelper(
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL: case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL:
SetSourceSetting(source, setting, manualSettingValue); SetSourceSetting(source, setting, manualSettingValue);
break; break;
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_LIST_ENTRY:
SetSourceSettingListEntryValueByName(
source, setting, manualSettingValue);
break;
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR: { case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR: {
auto var = tempVar.GetTempVariable(macro); auto var = tempVar.GetTempVariable(macro);
if (!var) { if (!var) {
@@ -185,8 +193,8 @@ void MacroActionFilter::ResolveVariablesToFixedValues()
static inline void populateActionSelection(QComboBox *list) static inline void populateActionSelection(QComboBox *list)
{ {
for (auto entry : actionTypes) { for (const auto &[_, name] : actionTypes) {
list->addItem(obs_module_text(entry.second.c_str())); list->addItem(obs_module_text(name.c_str()));
} }
} }
@@ -199,10 +207,17 @@ static inline void populateSettingsInputMethods(QComboBox *list)
} }
} }
static QStringList getFilterSourcesList()
{
auto sources = GetSourcesWithFilterNames();
sources.sort();
return sources;
}
MacroActionFilterEdit::MacroActionFilterEdit( MacroActionFilterEdit::MacroActionFilterEdit(
QWidget *parent, std::shared_ptr<MacroActionFilter> entryData) QWidget *parent, std::shared_ptr<MacroActionFilter> entryData)
: QWidget(parent), : QWidget(parent),
_sources(new SourceSelectionWidget(this, QStringList(), true)), _sources(new SourceSelectionWidget(this, getFilterSourcesList, true)),
_filters(new FilterSelectionWidget(this, _sources, true)), _filters(new FilterSelectionWidget(this, _sources, true)),
_actions(new QComboBox()), _actions(new QComboBox()),
_getSettings(new QPushButton(obs_module_text( _getSettings(new QPushButton(obs_module_text(
@@ -220,9 +235,6 @@ MacroActionFilterEdit::MacroActionFilterEdit(
_filters->setSizeAdjustPolicy(QComboBox::AdjustToContents); _filters->setSizeAdjustPolicy(QComboBox::AdjustToContents);
populateActionSelection(_actions); populateActionSelection(_actions);
auto sources = GetSourcesWithFilterNames();
sources.sort();
_sources->SetSourceNameList(sources);
_refreshSettingSelection->setToolTip(obs_module_text( _refreshSettingSelection->setToolTip(obs_module_text(
"AdvSceneSwitcher.action.filter.refresh.tooltip")); "AdvSceneSwitcher.action.filter.refresh.tooltip"));
@@ -369,6 +381,16 @@ void MacroActionFilterEdit::GetSettingsClicked()
.value_or("")); .value_or(""));
break; break;
} }
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_LIST_ENTRY: {
const auto filters =
_entryData->_filter.GetFilters(_entryData->_source);
_manualSettingValue->setPlainText(
GetSourceSettingListEntryName(
filters.empty() ? nullptr : filters.at(0),
_entryData->_setting)
.value_or(""));
break;
}
case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR: case MacroActionFilter::SettingsInputMethod::INDIVIDUAL_TEMPVAR:
break; break;
case MacroActionFilter::SettingsInputMethod::JSON_STRING: { case MacroActionFilter::SettingsInputMethod::JSON_STRING: {
@@ -411,6 +433,7 @@ void MacroActionFilterEdit::SelectionChanged(const SourceSetting &setting)
{ {
GUARD_LOADING_AND_LOCK(); GUARD_LOADING_AND_LOCK();
_entryData->_setting = setting; _entryData->_setting = setting;
SetWidgetVisibility();
} }
void MacroActionFilterEdit::ManualSettingsValueChanged() void MacroActionFilterEdit::ManualSettingsValueChanged()
@@ -436,6 +459,22 @@ void MacroActionFilterEdit::ButtonChanged(const SourceSettingButton &button)
_entryData->_button = button; _entryData->_button = button;
} }
static QString GetIndividualListEntryName()
{
static const auto matchesInput =
[](const std::pair<MacroActionFilter::SettingsInputMethod,
std::string> &p) {
return p.first ==
MacroActionFilter::SettingsInputMethod::
INDIVIDUAL_LIST_ENTRY;
};
static const QString listValueText(
obs_module_text(std::find_if(inputMethods.begin(),
inputMethods.end(), matchesInput)
->second.c_str()));
return listValueText;
}
void MacroActionFilterEdit::SetWidgetVisibility() void MacroActionFilterEdit::SetWidgetVisibility()
{ {
SetLayoutVisible(_settingsLayout, SetLayoutVisible(_settingsLayout,
@@ -460,9 +499,16 @@ void MacroActionFilterEdit::SetWidgetVisibility()
MacroActionFilter::SettingsInputMethod:: MacroActionFilter::SettingsInputMethod::
INDIVIDUAL_TEMPVAR); INDIVIDUAL_TEMPVAR);
SetRowVisibleByValue(_settingsInputMethods,
GetIndividualListEntryName(),
_entryData->_setting.IsList());
if (_entryData->_action == MacroActionFilter::Action::SETTINGS && if (_entryData->_action == MacroActionFilter::Action::SETTINGS &&
_entryData->_settingsInputMethod == (_entryData->_settingsInputMethod ==
MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL) { MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL ||
_entryData->_settingsInputMethod ==
MacroActionFilter::SettingsInputMethod::
INDIVIDUAL_LIST_ENTRY)) {
RemoveStretchIfPresent(_settingsLayout); RemoveStretchIfPresent(_settingsLayout);
_manualSettingValue->show(); _manualSettingValue->show();
} else { } else {
@@ -471,8 +517,12 @@ void MacroActionFilterEdit::SetWidgetVisibility()
} }
_refreshSettingSelection->setVisible( _refreshSettingSelection->setVisible(
_entryData->_settingsInputMethod == (_entryData->_settingsInputMethod ==
MacroActionFilter::SettingsInputMethod::INDIVIDUAL_MANUAL && MacroActionFilter::SettingsInputMethod::
INDIVIDUAL_MANUAL ||
_entryData->_settingsInputMethod ==
MacroActionFilter::SettingsInputMethod::
INDIVIDUAL_LIST_ENTRY) &&
(_entryData->_source.GetType() == (_entryData->_source.GetType() ==
SourceSelection::Type::VARIABLE || SourceSelection::Type::VARIABLE ||
_entryData->_filter.GetType() == _entryData->_filter.GetType() ==

View File

@@ -36,6 +36,7 @@ public:
INDIVIDUAL_MANUAL, INDIVIDUAL_MANUAL,
INDIVIDUAL_TEMPVAR, INDIVIDUAL_TEMPVAR,
JSON_STRING, JSON_STRING,
INDIVIDUAL_LIST_ENTRY,
}; };
SettingsInputMethod _settingsInputMethod = SettingsInputMethod _settingsInputMethod =
SettingsInputMethod::INDIVIDUAL_MANUAL; SettingsInputMethod::INDIVIDUAL_MANUAL;

View File

@@ -788,133 +788,82 @@ void MacroActionHotkeyEdit::UpdateEntryData()
void MacroActionHotkeyEdit::LShiftChanged(int state) void MacroActionHotkeyEdit::LShiftChanged(int state)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_leftShift = state; _entryData->_leftShift = state;
} }
void MacroActionHotkeyEdit::RShiftChanged(int state) void MacroActionHotkeyEdit::RShiftChanged(int state)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_rightShift = state; _entryData->_rightShift = state;
} }
void MacroActionHotkeyEdit::LCtrlChanged(int state) void MacroActionHotkeyEdit::LCtrlChanged(int state)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_leftCtrl = state; _entryData->_leftCtrl = state;
} }
void MacroActionHotkeyEdit::RCtrlChanged(int state) void MacroActionHotkeyEdit::RCtrlChanged(int state)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_rightCtrl = state; _entryData->_rightCtrl = state;
} }
void MacroActionHotkeyEdit::LAltChanged(int state) void MacroActionHotkeyEdit::LAltChanged(int state)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_leftAlt = state; _entryData->_leftAlt = state;
} }
void MacroActionHotkeyEdit::RAltChanged(int state) void MacroActionHotkeyEdit::RAltChanged(int state)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_rightAlt = state; _entryData->_rightAlt = state;
} }
void MacroActionHotkeyEdit::LMetaChanged(int state) void MacroActionHotkeyEdit::LMetaChanged(int state)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_leftMeta = state; _entryData->_leftMeta = state;
} }
void MacroActionHotkeyEdit::RMetaChanged(int state) void MacroActionHotkeyEdit::RMetaChanged(int state)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_rightMeta = state; _entryData->_rightMeta = state;
} }
void MacroActionHotkeyEdit::DurationChanged(const Duration &dur) void MacroActionHotkeyEdit::DurationChanged(const Duration &dur)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_duration = dur; _entryData->_duration = dur;
} }
void MacroActionHotkeyEdit::OnlySendToOBSChanged(int state) void MacroActionHotkeyEdit::OnlySendToOBSChanged(int state)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_onlySendToObs = state; _entryData->_onlySendToObs = state;
SetWidgetVisibility(); SetWidgetVisibility();
} }
void MacroActionHotkeyEdit::KeyChanged(int key) void MacroActionHotkeyEdit::KeyChanged(int key)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_key = static_cast<HotkeyType>(key); _entryData->_key = static_cast<HotkeyType>(key);
} }
void MacroActionHotkeyEdit::ActionChanged(int value) void MacroActionHotkeyEdit::ActionChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_action = static_cast<MacroActionHotkey::Action>(value); _entryData->_action = static_cast<MacroActionHotkey::Action>(value);
SetWidgetVisibility(); SetWidgetVisibility();
} }
void MacroActionHotkeyEdit::HotkeyTypeChanged(int value) void MacroActionHotkeyEdit::HotkeyTypeChanged(int value)
{ {
if (_loading || !_entryData) {
return;
}
{ {
auto lock = LockContext(); GUARD_LOADING_AND_LOCK();
_entryData->_hotkeyType = _entryData->_hotkeyType =
static_cast<obs_hotkey_registerer_type>(value); static_cast<obs_hotkey_registerer_type>(value);
} }
@@ -923,11 +872,7 @@ void MacroActionHotkeyEdit::HotkeyTypeChanged(int value)
void MacroActionHotkeyEdit::OBSHotkeyChanged(int idx) void MacroActionHotkeyEdit::OBSHotkeyChanged(int idx)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
if (idx == -1) { if (idx == -1) {
_entryData->_hotkeyName = ""; _entryData->_hotkeyName = "";
return; return;

View File

@@ -238,54 +238,34 @@ void MacroActionHttpEdit::UpdateEntryData()
void MacroActionHttpEdit::URLChanged() void MacroActionHttpEdit::URLChanged()
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_url = _url->text().toStdString(); _entryData->_url = _url->text().toStdString();
emit(HeaderInfoChanged(_url->text())); emit(HeaderInfoChanged(_url->text()));
} }
void MacroActionHttpEdit::MethodChanged(int value) void MacroActionHttpEdit::MethodChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_method = static_cast<MacroActionHttp::Method>(value); _entryData->_method = static_cast<MacroActionHttp::Method>(value);
SetWidgetVisibility(); SetWidgetVisibility();
} }
void MacroActionHttpEdit::TimeoutChanged(const Duration &dur) void MacroActionHttpEdit::TimeoutChanged(const Duration &dur)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_timeout = dur; _entryData->_timeout = dur;
} }
void MacroActionHttpEdit::SetHeadersChanged(int value) void MacroActionHttpEdit::SetHeadersChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_setHeaders = value; _entryData->_setHeaders = value;
SetWidgetVisibility(); SetWidgetVisibility();
} }
void MacroActionHttpEdit::HeadersChanged(const StringList &headers) void MacroActionHttpEdit::HeadersChanged(const StringList &headers)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_headers = headers; _entryData->_headers = headers;
adjustSize(); adjustSize();
updateGeometry(); updateGeometry();
@@ -302,11 +282,7 @@ void MacroActionHttpEdit::SetWidgetVisibility()
void MacroActionHttpEdit::DataChanged() void MacroActionHttpEdit::DataChanged()
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_data = _data->toPlainText().toUtf8().constData(); _entryData->_data = _data->toPlainText().toUtf8().constData();
adjustSize(); adjustSize();

View File

@@ -75,11 +75,7 @@ void MacroActionLogEdit::UpdateEntryData()
void MacroActionLogEdit::LogMessageChanged() void MacroActionLogEdit::LogMessageChanged()
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_logMessage = _logMessage->toPlainText().toStdString(); _entryData->_logMessage = _logMessage->toPlainText().toStdString();
adjustSize(); adjustSize();

View File

@@ -219,6 +219,13 @@ static inline void populateSelectionTypeSelection(QComboBox *list)
} }
} }
static QStringList getMediaSourcesList()
{
auto sources = GetMediaSourceNames();
sources.sort();
return sources;
}
MacroActionMediaEdit::MacroActionMediaEdit( MacroActionMediaEdit::MacroActionMediaEdit(
QWidget *parent, std::shared_ptr<MacroActionMedia> entryData) QWidget *parent, std::shared_ptr<MacroActionMedia> entryData)
: QWidget(parent), : QWidget(parent),
@@ -229,15 +236,12 @@ MacroActionMediaEdit::MacroActionMediaEdit(
0, 100, 0, 100,
obs_module_text( obs_module_text(
"AdvSceneSwitcher.action.media.seek.percentage.label"))), "AdvSceneSwitcher.action.media.seek.percentage.label"))),
_sources(new SourceSelectionWidget(this, QStringList(), true)), _sources(new SourceSelectionWidget(this, getMediaSourcesList, true)),
_sceneItems(new SceneItemSelectionWidget(parent, false)), _sceneItems(new SceneItemSelectionWidget(parent, false)),
_scenes(new SceneSelectionWidget(this, true, false, true, true, true)) _scenes(new SceneSelectionWidget(this, true, false, true, true, true))
{ {
populateActionSelection(_actions); populateActionSelection(_actions);
populateSelectionTypeSelection(_selectionTypes); populateSelectionTypeSelection(_selectionTypes);
auto sources = GetMediaSourceNames();
sources.sort();
_sources->SetSourceNameList(sources);
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this, QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionChanged(int))); SLOT(ActionChanged(int)));
@@ -282,22 +286,14 @@ MacroActionMediaEdit::MacroActionMediaEdit(
void MacroActionMediaEdit::ActionChanged(int value) void MacroActionMediaEdit::ActionChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_action = static_cast<MacroActionMedia::Action>(value); _entryData->_action = static_cast<MacroActionMedia::Action>(value);
SetWidgetVisibility(); SetWidgetVisibility();
} }
void MacroActionMediaEdit::SelectionTypeChanged(int value) void MacroActionMediaEdit::SelectionTypeChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_selection = _entryData->_selection =
static_cast<MacroActionMedia::SelectionType>(value); static_cast<MacroActionMedia::SelectionType>(value);
SetWidgetVisibility(); SetWidgetVisibility();
@@ -305,32 +301,20 @@ void MacroActionMediaEdit::SelectionTypeChanged(int value)
void MacroActionMediaEdit::SeekDurationChanged(const Duration &seekDuration) void MacroActionMediaEdit::SeekDurationChanged(const Duration &seekDuration)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_seekDuration = seekDuration; _entryData->_seekDuration = seekDuration;
} }
void MacroActionMediaEdit::SeekPercentageChanged( void MacroActionMediaEdit::SeekPercentageChanged(
const NumberVariable<double> &seekPercentage) const NumberVariable<double> &seekPercentage)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_seekPercentage = seekPercentage; _entryData->_seekPercentage = seekPercentage;
} }
void MacroActionMediaEdit::SourceChanged(const SourceSelection &source) void MacroActionMediaEdit::SourceChanged(const SourceSelection &source)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_mediaSource = source; _entryData->_mediaSource = source;
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));
@@ -338,11 +322,7 @@ void MacroActionMediaEdit::SourceChanged(const SourceSelection &source)
void MacroActionMediaEdit::SourceChanged(const SceneItemSelection &item) void MacroActionMediaEdit::SourceChanged(const SceneItemSelection &item)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_sceneItem = item; _entryData->_sceneItem = item;
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));
@@ -352,11 +332,7 @@ void MacroActionMediaEdit::SourceChanged(const SceneItemSelection &item)
void MacroActionMediaEdit::SceneChanged(const SceneSelection &scene) void MacroActionMediaEdit::SceneChanged(const SceneSelection &scene)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_scene = scene; _entryData->_scene = scene;
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));

View File

@@ -0,0 +1,387 @@
#include "macro-action-obs-settings.hpp"
#include "layout-helpers.hpp"
#include "profile-helpers.hpp"
#include "ui-helpers.hpp"
#include <obs-frontend-api.h>
#include <util/config-file.h>
namespace advss {
const std::string MacroActionOBSSettings::id = "obs_settings";
bool MacroActionOBSSettings::_registered = MacroActionFactory::Register(
MacroActionOBSSettings::id,
{MacroActionOBSSettings::Create, MacroActionOBSSettingsEdit::Create,
"AdvSceneSwitcher.action.obsSetting"});
const static std::map<MacroActionOBSSettings::Action, std::string> actionTypes = {
{MacroActionOBSSettings::Action::FPS_TYPE,
"AdvSceneSwitcher.action.obsSetting.action.setFPSType"},
{MacroActionOBSSettings::Action::FPS_COMMON_VALUE,
"AdvSceneSwitcher.action.obsSetting.action.setFPSCommonValue"},
{MacroActionOBSSettings::Action::FPS_INT_VALUE,
"AdvSceneSwitcher.action.obsSetting.action.setFPSIntegerValue"},
{MacroActionOBSSettings::Action::FPS_NUM_VALUE,
"AdvSceneSwitcher.action.obsSetting.action.setFPSFractionNumeratorValue"},
{MacroActionOBSSettings::Action::FPS_DEN_VALUE,
"AdvSceneSwitcher.action.obsSetting.action.setFPSFractionDenominatorValue"},
{MacroActionOBSSettings::Action::BASE_CANVAS_X_VALUE,
"AdvSceneSwitcher.action.obsSetting.action.setBaseCanvasX"},
{MacroActionOBSSettings::Action::BASE_CANVAS_Y_VALUE,
"AdvSceneSwitcher.action.obsSetting.action.setBaseCanvasY"},
{MacroActionOBSSettings::Action::OUTPUT_X_VALUE,
"AdvSceneSwitcher.action.obsSetting.action.setOutputCanvasX"},
{MacroActionOBSSettings::Action::OUTPUT_Y_VALUE,
"AdvSceneSwitcher.action.obsSetting.action.setOutputCanvasY"},
};
template<typename Func, typename... Args>
static void setConfigValueHelper(Func func, Args... args)
{
auto config = obs_frontend_get_profile_config();
func(config, args...);
if (config_save(config) != CONFIG_SUCCESS) {
blog(LOG_WARNING, "failed to save config!");
}
}
template<typename Func, typename... Args>
static auto getConfigValueHelper(Func func, Func defaultFunc, Args... args)
-> std::optional<std::invoke_result_t<Func, config_t *, Args...>>
{
using Ret = std::invoke_result_t<Func, config_t *, Args...>;
auto config = obs_frontend_get_profile_config();
if (config_has_user_value(config, args...)) {
return func(config, args...);
}
if (config_has_default_value(config, args...)) {
return defaultFunc(config, args...);
}
return std::optional<Ret>{};
}
bool MacroActionOBSSettings::PerformAction()
{
switch (_action) {
case Action::FPS_TYPE:
setConfigValueHelper(config_set_uint, "Video", "FPSType",
static_cast<int>(_fpsType));
obs_frontend_reset_video();
break;
case Action::FPS_COMMON_VALUE:
setConfigValueHelper(config_set_string, "Video", "FPSCommon",
_fpsStringValue.c_str());
obs_frontend_reset_video();
break;
case Action::FPS_INT_VALUE:
setConfigValueHelper(config_set_uint, "Video", "FPSInt",
static_cast<int>(_fpsIntValue));
obs_frontend_reset_video();
break;
case Action::FPS_NUM_VALUE:
setConfigValueHelper(config_set_uint, "Video", "FPSNum",
static_cast<int>(_fpsIntValue));
obs_frontend_reset_video();
break;
case Action::FPS_DEN_VALUE:
setConfigValueHelper(config_set_uint, "Video", "FPSDen",
static_cast<int>(_fpsIntValue));
obs_frontend_reset_video();
break;
case Action::BASE_CANVAS_X_VALUE:
setConfigValueHelper(config_set_uint, "Video", "BaseCX",
static_cast<int>(_canvasSizeValue));
obs_frontend_reset_video();
break;
case Action::BASE_CANVAS_Y_VALUE:
setConfigValueHelper(config_set_uint, "Video", "BaseCY",
static_cast<int>(_canvasSizeValue));
obs_frontend_reset_video();
break;
case Action::OUTPUT_X_VALUE:
setConfigValueHelper(config_set_uint, "Video", "OutputCX",
static_cast<int>(_canvasSizeValue));
obs_frontend_reset_video();
break;
case Action::OUTPUT_Y_VALUE:
setConfigValueHelper(config_set_uint, "Video", "OutputCY",
static_cast<int>(_canvasSizeValue));
obs_frontend_reset_video();
break;
default:
break;
}
return true;
}
void MacroActionOBSSettings::LogAction() const
{
auto it = actionTypes.find(_action);
if (it != actionTypes.end()) {
ablog(LOG_INFO, "performed action \"%s\"", it->second.c_str());
} else {
blog(LOG_WARNING, "ignored unknown obs setting action %d",
static_cast<int>(_action));
}
}
bool MacroActionOBSSettings::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
obs_data_set_int(obj, "action", static_cast<int>(_action));
_fpsIntValue.Save(obj, "fpsIntValue");
_fpsStringValue.Save(obj, "fpsStringValue");
_canvasSizeValue.Save(obj, "canvasSizeValue");
return true;
}
bool MacroActionOBSSettings::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
_fpsIntValue.Load(obj, "fpsIntValue");
_fpsStringValue.Load(obj, "fpsStringValue");
_canvasSizeValue.Load(obj, "canvasSizeValue");
return true;
}
std::shared_ptr<MacroAction> MacroActionOBSSettings::Create(Macro *m)
{
return std::make_shared<MacroActionOBSSettings>(m);
}
std::shared_ptr<MacroAction> MacroActionOBSSettings::Copy() const
{
return std::make_shared<MacroActionOBSSettings>(*this);
}
void MacroActionOBSSettings::ResolveVariablesToFixedValues()
{
_fpsIntValue.ResolveVariables();
_canvasSizeValue.ResolveVariables();
}
static void populateActionSelection(QComboBox *list)
{
for (const auto &[value, name] : actionTypes) {
list->addItem(obs_module_text(name.c_str()),
static_cast<int>(value));
}
}
static void populateFPSTypeSelection(QComboBox *list)
{
static const std::map<MacroActionOBSSettings::FPSType, std::string>
types = {
{MacroActionOBSSettings::FPSType::COMMON,
"Basic.Settings.Video.FPSCommon"},
{MacroActionOBSSettings::FPSType::INTEGER,
"Basic.Settings.Video.FPSInteger"},
{MacroActionOBSSettings::FPSType::FRACTION,
"Basic.Settings.Video.FPSFraction"},
};
for (const auto &[value, name] : types) {
list->addItem(obs_module_text(name.c_str()),
static_cast<int>(value));
}
}
MacroActionOBSSettingsEdit::MacroActionOBSSettingsEdit(
QWidget *parent, std::shared_ptr<MacroActionOBSSettings> entryData)
: QWidget(parent),
_actions(new QComboBox(this)),
_fpsType(new QComboBox(this)),
_fpsIntValue(new VariableSpinBox(this)),
_fpsStringValue(new VariableLineEdit(this)),
_canvasSizeValue(new VariableSpinBox(this)),
_getCurrentValue(new QPushButton(obs_module_text(
"AdvSceneSwitcher.action.obsSetting.getCurrentValue")))
{
populateActionSelection(_actions);
populateFPSTypeSelection(_fpsType);
_fpsIntValue->setMaximum(1000);
_canvasSizeValue->setMaximum(100000);
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionChanged(int)));
QWidget::connect(_fpsType, SIGNAL(currentIndexChanged(int)), this,
SLOT(FPSTypeChanged(int)));
QWidget::connect(
_fpsIntValue,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this, SLOT(FPSIntValueChanged(const NumberVariable<int> &)));
QWidget::connect(_fpsStringValue, SIGNAL(editingFinished()), this,
SLOT(FPSStringValueChanged()));
QWidget::connect(
_canvasSizeValue,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this,
SLOT(CanvasSizeValueChanged(const NumberVariable<int> &)));
QWidget::connect(_getCurrentValue, SIGNAL(clicked()), this,
SLOT(GetCurrentValueClicked()));
auto layout = new QHBoxLayout();
PlaceWidgets(
obs_module_text("AdvSceneSwitcher.action.obsSettings.layout"),
layout,
{{"{{actions}}", _actions},
{"{{fpsType}}", _fpsType},
{"{{fpsIntValue}}", _fpsIntValue},
{"{{fpsStringValue}}", _fpsStringValue},
{"{{canvasSizeValue}}", _canvasSizeValue},
{"{{getCurrentValue}}", _getCurrentValue}});
setLayout(layout);
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
void MacroActionOBSSettingsEdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
_actions->setCurrentIndex(
_actions->findData(static_cast<int>(_entryData->_action)));
_fpsType->setCurrentIndex(
_actions->findData(static_cast<int>(_entryData->_fpsType)));
_fpsIntValue->SetValue(_entryData->_fpsIntValue);
_fpsStringValue->setText(_entryData->_fpsStringValue);
_canvasSizeValue->SetValue(_entryData->_canvasSizeValue);
SetWidgetVisibility();
}
void MacroActionOBSSettingsEdit::FPSTypeChanged(int idx)
{
GUARD_LOADING_AND_LOCK();
_entryData->_fpsType = static_cast<MacroActionOBSSettings::FPSType>(
_fpsType->itemData(idx).toInt());
SetWidgetVisibility();
}
void MacroActionOBSSettingsEdit::FPSIntValueChanged(
const NumberVariable<int> &value)
{
GUARD_LOADING_AND_LOCK();
_entryData->_fpsIntValue = value;
}
void MacroActionOBSSettingsEdit::FPSStringValueChanged()
{
GUARD_LOADING_AND_LOCK();
_entryData->_fpsStringValue = _fpsStringValue->text().toStdString();
}
void MacroActionOBSSettingsEdit::CanvasSizeValueChanged(
const NumberVariable<int> &value)
{
GUARD_LOADING_AND_LOCK();
_entryData->_canvasSizeValue = value;
}
void MacroActionOBSSettingsEdit::GetCurrentValueClicked()
{
const auto setSpinVideoValue = [this](VariableSpinBox *spin,
const char *name) {
auto value = getConfigValueHelper(config_get_uint,
config_get_default_uint,
"Video", name);
if (!value) {
return;
}
spin->SetFixedValue(static_cast<int>(*value));
};
const auto setFpsValue = [&](const char *name) {
setSpinVideoValue(_fpsIntValue, name);
};
const auto setCanvasValue = [&](const char *name) {
setSpinVideoValue(_canvasSizeValue, name);
};
switch (_entryData->_action) {
case MacroActionOBSSettings::Action::FPS_COMMON_VALUE: {
auto value = getConfigValueHelper(config_get_string,
config_get_default_string,
"Video", "FPSCommon");
if (!value) {
break;
}
_fpsStringValue->setText(QString(*value));
break;
}
case MacroActionOBSSettings::Action::FPS_INT_VALUE:
setFpsValue("FPSInt");
break;
case MacroActionOBSSettings::Action::FPS_NUM_VALUE:
setFpsValue("FPSNum");
break;
case MacroActionOBSSettings::Action::FPS_DEN_VALUE:
setFpsValue("FPSDen");
break;
case MacroActionOBSSettings::Action::BASE_CANVAS_X_VALUE:
setCanvasValue("BaseCX");
break;
case MacroActionOBSSettings::Action::BASE_CANVAS_Y_VALUE:
setCanvasValue("BaseCY");
break;
case MacroActionOBSSettings::Action::OUTPUT_X_VALUE:
setCanvasValue("OutputCX");
break;
case MacroActionOBSSettings::Action::OUTPUT_Y_VALUE:
setCanvasValue("OutputCY");
break;
default:
break;
}
}
void MacroActionOBSSettingsEdit::SetWidgetVisibility()
{
if (!_entryData) {
return;
}
const bool isFPSSelection =
_entryData->_action ==
MacroActionOBSSettings::Action::FPS_TYPE ||
_entryData->_action ==
MacroActionOBSSettings::Action::FPS_COMMON_VALUE ||
_entryData->_action ==
MacroActionOBSSettings::Action::FPS_INT_VALUE ||
_entryData->_action ==
MacroActionOBSSettings::Action::FPS_DEN_VALUE ||
_entryData->_action ==
MacroActionOBSSettings::Action::FPS_NUM_VALUE;
_fpsType->setVisible(_entryData->_action ==
MacroActionOBSSettings::Action::FPS_TYPE);
_fpsIntValue->setVisible(
_entryData->_action ==
MacroActionOBSSettings::Action::FPS_INT_VALUE ||
_entryData->_action ==
MacroActionOBSSettings::Action::FPS_NUM_VALUE ||
_entryData->_action ==
MacroActionOBSSettings::Action::FPS_DEN_VALUE);
_fpsStringValue->setVisible(
_entryData->_action ==
MacroActionOBSSettings::Action::FPS_COMMON_VALUE);
_canvasSizeValue->setVisible(!isFPSSelection);
_getCurrentValue->setVisible(_entryData->_action !=
MacroActionOBSSettings::Action::FPS_TYPE);
}
void MacroActionOBSSettingsEdit::ActionChanged(int idx)
{
GUARD_LOADING_AND_LOCK();
_entryData->_action = static_cast<MacroActionOBSSettings::Action>(
_actions->itemData(idx).toInt());
SetWidgetVisibility();
}
} // namespace advss

View File

@@ -0,0 +1,90 @@
#pragma once
#include "macro-action-edit.hpp"
#include "variable-spinbox.hpp"
#include "variable-line-edit.hpp"
#include <QComboBox>
#include <QHBoxLayout>
#include <chrono>
namespace advss {
class MacroActionOBSSettings : public MacroAction {
public:
MacroActionOBSSettings(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction() const;
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
void ResolveVariablesToFixedValues();
enum class Action {
FPS_TYPE,
FPS_COMMON_VALUE,
FPS_INT_VALUE,
FPS_NUM_VALUE,
FPS_DEN_VALUE,
BASE_CANVAS_X_VALUE,
BASE_CANVAS_Y_VALUE,
OUTPUT_X_VALUE,
OUTPUT_Y_VALUE,
};
Action _action = Action::FPS_COMMON_VALUE;
enum class FPSType {
COMMON,
INTEGER,
FRACTION,
};
FPSType _fpsType = FPSType::INTEGER;
IntVariable _fpsIntValue = 30;
StringVariable _fpsStringValue = "24 NTSC";
IntVariable _canvasSizeValue = 1920;
private:
static bool _registered;
static const std::string id;
};
class MacroActionOBSSettingsEdit : public QWidget {
Q_OBJECT
public:
MacroActionOBSSettingsEdit(
QWidget *parent,
std::shared_ptr<MacroActionOBSSettings> entryData = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionOBSSettingsEdit(
parent,
std::dynamic_pointer_cast<MacroActionOBSSettings>(
action));
}
private slots:
void ActionChanged(int);
void FPSTypeChanged(int);
void FPSIntValueChanged(const NumberVariable<int> &);
void FPSStringValueChanged();
void CanvasSizeValueChanged(const NumberVariable<int> &);
void GetCurrentValueClicked();
private:
void SetWidgetVisibility();
QComboBox *_actions;
QComboBox *_fpsType;
VariableSpinBox *_fpsIntValue;
VariableLineEdit *_fpsStringValue;
VariableSpinBox *_canvasSizeValue;
QPushButton *_getCurrentValue;
std::shared_ptr<MacroActionOBSSettings> _entryData;
bool _loading = true;
};
} // namespace advss

View File

@@ -296,41 +296,25 @@ void MacroActionOSCEdit::UpdateEntryData()
void MacroActionOSCEdit::IpChanged() void MacroActionOSCEdit::IpChanged()
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->SetIP(_ip->text().toStdString()); _entryData->SetIP(_ip->text().toStdString());
} }
void MacroActionOSCEdit::ProtocolChanged(int value) void MacroActionOSCEdit::ProtocolChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->SetProtocol(static_cast<MacroActionOSC::Protocol>(value)); _entryData->SetProtocol(static_cast<MacroActionOSC::Protocol>(value));
} }
void MacroActionOSCEdit::PortChanged(const NumberVariable<int> &value) void MacroActionOSCEdit::PortChanged(const NumberVariable<int> &value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->SetPortNr(value); _entryData->SetPortNr(value);
} }
void MacroActionOSCEdit::MessageChanged(const OSCMessage &m) void MacroActionOSCEdit::MessageChanged(const OSCMessage &m)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_message = m; _entryData->_message = m;
adjustSize(); adjustSize();

View File

@@ -300,12 +300,8 @@ void MacroActionPluginStateEdit::UpdateEntryData()
void MacroActionPluginStateEdit::ActionChanged(int value) void MacroActionPluginStateEdit::ActionChanged(int value)
{ {
if (_loading || !_entryData) {
return;
}
{ {
auto lock = LockContext(); GUARD_LOADING_AND_LOCK();
_entryData->_action = static_cast<PluginStateAction>(value); _entryData->_action = static_cast<PluginStateAction>(value);
SetWidgetVisibility(); SetWidgetVisibility();
} }
@@ -316,32 +312,20 @@ void MacroActionPluginStateEdit::ActionChanged(int value)
void MacroActionPluginStateEdit::ValueChanged(int value) void MacroActionPluginStateEdit::ValueChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_value = value; _entryData->_value = value;
SetWidgetVisibility(); SetWidgetVisibility();
} }
void MacroActionPluginStateEdit::SceneChanged(const QString &text) void MacroActionPluginStateEdit::SceneChanged(const QString &text)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_scene = GetWeakSourceByQString(text); _entryData->_scene = GetWeakSourceByQString(text);
} }
void MacroActionPluginStateEdit::PathChanged(const QString &text) void MacroActionPluginStateEdit::PathChanged(const QString &text)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_settingsPath = text.toStdString(); _entryData->_settingsPath = text.toStdString();
} }

View File

@@ -1,6 +1,5 @@
#include "macro-action-profile.hpp" #include "macro-action-profile.hpp"
#include "layout-helpers.hpp" #include "layout-helpers.hpp"
#include "profile-helpers.hpp"
#include <obs-frontend-api.h> #include <obs-frontend-api.h>
@@ -55,20 +54,16 @@ std::shared_ptr<MacroAction> MacroActionProfile::Copy() const
MacroActionProfileEdit::MacroActionProfileEdit( MacroActionProfileEdit::MacroActionProfileEdit(
QWidget *parent, std::shared_ptr<MacroActionProfile> entryData) QWidget *parent, std::shared_ptr<MacroActionProfile> entryData)
: QWidget(parent) : QWidget(parent),
_profiles(new ProfileSelectionWidget(this))
{ {
_profiles = new QComboBox();
PopulateProfileSelection(_profiles);
QWidget::connect(_profiles, SIGNAL(currentTextChanged(const QString &)), QWidget::connect(_profiles, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(ProfileChanged(const QString &))); this, SLOT(ProfileChanged(const QString &)));
QHBoxLayout *mainLayout = new QHBoxLayout; auto layout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{profiles}}", _profiles},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.profile.entry"), PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.profile.entry"),
mainLayout, widgetPlaceholders); layout, {{"{{profiles}}", _profiles}});
setLayout(mainLayout); setLayout(layout);
_entryData = entryData; _entryData = entryData;
UpdateEntryData(); UpdateEntryData();
@@ -86,11 +81,7 @@ void MacroActionProfileEdit::UpdateEntryData()
void MacroActionProfileEdit::ProfileChanged(const QString &text) void MacroActionProfileEdit::ProfileChanged(const QString &text)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_profile = text.toStdString(); _entryData->_profile = text.toStdString();
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "macro-action-edit.hpp" #include "macro-action-edit.hpp"
#include "profile-helpers.hpp"
#include <QComboBox>
namespace advss { namespace advss {
@@ -45,11 +44,10 @@ private slots:
signals: signals:
void HeaderInfoChanged(const QString &); void HeaderInfoChanged(const QString &);
protected:
QComboBox *_profiles;
std::shared_ptr<MacroActionProfile> _entryData;
private: private:
ProfileSelectionWidget *_profiles;
std::shared_ptr<MacroActionProfile> _entryData;
bool _loading = true; bool _loading = true;
}; };

View File

@@ -1,6 +1,5 @@
#include "macro-action-projector.hpp" #include "macro-action-projector.hpp"
#include "layout-helpers.hpp" #include "layout-helpers.hpp"
#include "monitor-helpers.hpp"
#include "selection-helpers.hpp" #include "selection-helpers.hpp"
#include "source-helpers.hpp" #include "source-helpers.hpp"
@@ -230,6 +229,13 @@ static void populateWindowTypes(QComboBox *list)
"AdvSceneSwitcher.action.projector.fullscreen")); "AdvSceneSwitcher.action.projector.fullscreen"));
} }
static QStringList getSourcesList()
{
auto sources = GetSourceNames();
sources.sort();
return sources;
}
MacroActionProjectorEdit::MacroActionProjectorEdit( MacroActionProjectorEdit::MacroActionProjectorEdit(
QWidget *parent, std::shared_ptr<MacroActionProjector> entryData) QWidget *parent, std::shared_ptr<MacroActionProjector> entryData)
: QWidget(parent), : QWidget(parent),
@@ -238,8 +244,8 @@ MacroActionProjectorEdit::MacroActionProjectorEdit(
_windowTypes(new QComboBox()), _windowTypes(new QComboBox()),
_scenes(new SceneSelectionWidget(window(), true, false, true, true, _scenes(new SceneSelectionWidget(window(), true, false, true, true,
true)), true)),
_sources(new SourceSelectionWidget(window(), QStringList(), true)), _sources(new SourceSelectionWidget(window(), getSourcesList, true)),
_monitors(new QComboBox()), _monitors(new MonitorSelectionWidget(this)),
_projectorWindowName(new VariableLineEdit(this)), _projectorWindowName(new VariableLineEdit(this)),
_regex(new RegexConfigWidget(this)), _regex(new RegexConfigWidget(this)),
_layout(new QHBoxLayout(this)) _layout(new QHBoxLayout(this))
@@ -247,12 +253,11 @@ MacroActionProjectorEdit::MacroActionProjectorEdit(
populateActionSelection(_actions); populateActionSelection(_actions);
populateWindowTypes(_windowTypes); populateWindowTypes(_windowTypes);
populateSelectionTypes(_types); populateSelectionTypes(_types);
auto sources = GetSourceNames();
sources.sort();
_sources->SetSourceNameList(sources);
_monitors->addItems(GetMonitorNames()); _monitors->addItems(GetMonitorNames());
_monitors->setPlaceholderText( _monitors->setPlaceholderText(
obs_module_text("AdvSceneSwitcher.selectDisplay")); obs_module_text("AdvSceneSwitcher.selectDisplay"));
_monitors->SetAllowUnmatchedSelection(false);
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this, QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionChanged(int))); SLOT(ActionChanged(int)));

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "macro-action-edit.hpp" #include "macro-action-edit.hpp"
#include "monitor-helpers.hpp"
#include "regex-config.hpp" #include "regex-config.hpp"
#include "scene-selection.hpp" #include "scene-selection.hpp"
#include "source-selection.hpp" #include "source-selection.hpp"
@@ -88,7 +89,7 @@ private:
QComboBox *_windowTypes; QComboBox *_windowTypes;
SceneSelectionWidget *_scenes; SceneSelectionWidget *_scenes;
SourceSelectionWidget *_sources; SourceSelectionWidget *_sources;
QComboBox *_monitors; MonitorSelectionWidget *_monitors;
VariableLineEdit *_projectorWindowName; VariableLineEdit *_projectorWindowName;
RegexConfigWidget *_regex; RegexConfigWidget *_regex;
QHBoxLayout *_layout; QHBoxLayout *_layout;

View File

@@ -157,11 +157,7 @@ void MacroActionRandomEdit::MacroRemove(const QString &)
void MacroActionRandomEdit::Add(const std::string &name) void MacroActionRandomEdit::Add(const std::string &name)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
MacroRef macro(name); MacroRef macro(name);
_entryData->_macros.push_back(macro); _entryData->_macros.push_back(macro);
_allowRepeat->setVisible(ShouldShowAllowRepeat()); _allowRepeat->setVisible(ShouldShowAllowRepeat());
@@ -170,11 +166,7 @@ void MacroActionRandomEdit::Add(const std::string &name)
void MacroActionRandomEdit::Remove(int idx) void MacroActionRandomEdit::Remove(int idx)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_macros.erase(std::next(_entryData->_macros.begin(), idx)); _entryData->_macros.erase(std::next(_entryData->_macros.begin(), idx));
_allowRepeat->setVisible(ShouldShowAllowRepeat()); _allowRepeat->setVisible(ShouldShowAllowRepeat());
adjustSize(); adjustSize();
@@ -182,23 +174,15 @@ void MacroActionRandomEdit::Remove(int idx)
void MacroActionRandomEdit::Replace(int idx, const std::string &name) void MacroActionRandomEdit::Replace(int idx, const std::string &name)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
MacroRef macro(name); MacroRef macro(name);
auto lock = LockContext();
_entryData->_macros[idx] = macro; _entryData->_macros[idx] = macro;
adjustSize(); adjustSize();
} }
void MacroActionRandomEdit::AllowRepeatChanged(int value) void MacroActionRandomEdit::AllowRepeatChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_allowRepeat = value; _entryData->_allowRepeat = value;
} }

View File

@@ -199,21 +199,13 @@ static bool isPauseAction(MacroActionRecord::Action a)
void MacroActionRecordEdit::FolderChanged(const QString &folder) void MacroActionRecordEdit::FolderChanged(const QString &folder)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_folder = folder.toStdString(); _entryData->_folder = folder.toStdString();
} }
void MacroActionRecordEdit::FormatStringChanged() void MacroActionRecordEdit::FormatStringChanged()
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_fileFormat = _recordFileFormat->text().toStdString(); _entryData->_fileFormat = _recordFileFormat->text().toStdString();
} }
@@ -230,11 +222,7 @@ void MacroActionRecordEdit::SetWidgetVisibility()
void MacroActionRecordEdit::ActionChanged(int value) void MacroActionRecordEdit::ActionChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_action = static_cast<MacroActionRecord::Action>(value); _entryData->_action = static_cast<MacroActionRecord::Action>(value);
SetWidgetVisibility(); SetWidgetVisibility();
} }

View File

@@ -121,11 +121,7 @@ void MacroActionSceneCollectionEdit::UpdateEntryData()
void MacroActionSceneCollectionEdit::SceneCollectionChanged(const QString &text) void MacroActionSceneCollectionEdit::SceneCollectionChanged(const QString &text)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_sceneCollection = text.toStdString(); _entryData->_sceneCollection = text.toStdString();
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));

View File

@@ -156,21 +156,13 @@ void MacroActionSceneLockEdit::UpdateEntryData()
void MacroActionSceneLockEdit::SceneChanged(const SceneSelection &s) void MacroActionSceneLockEdit::SceneChanged(const SceneSelection &s)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_scene = s; _entryData->_scene = s;
} }
void MacroActionSceneLockEdit::SourceChanged(const SceneItemSelection &item) void MacroActionSceneLockEdit::SourceChanged(const SceneItemSelection &item)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_source = item; _entryData->_source = item;
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));
@@ -180,11 +172,7 @@ void MacroActionSceneLockEdit::SourceChanged(const SceneItemSelection &item)
void MacroActionSceneLockEdit::ActionChanged(int value) void MacroActionSceneLockEdit::ActionChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_action = static_cast<MacroActionSceneLock::Action>(value); _entryData->_action = static_cast<MacroActionSceneLock::Action>(value);
} }

View File

@@ -273,31 +273,19 @@ MacroActionSwitchSceneEdit::MacroActionSwitchSceneEdit(
void MacroActionSwitchSceneEdit::DurationChanged(const Duration &dur) void MacroActionSwitchSceneEdit::DurationChanged(const Duration &dur)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_duration = dur; _entryData->_duration = dur;
} }
void MacroActionSwitchSceneEdit::BlockUntilTransitionDoneChanged(int state) void MacroActionSwitchSceneEdit::BlockUntilTransitionDoneChanged(int state)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_blockUntilTransitionDone = state; _entryData->_blockUntilTransitionDone = state;
} }
void MacroActionSwitchSceneEdit::SceneTypeChanged(int value) void MacroActionSwitchSceneEdit::SceneTypeChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_sceneType = _entryData->_sceneType =
static_cast<MacroActionSwitchScene::SceneType>(value); static_cast<MacroActionSwitchScene::SceneType>(value);
SetWidgetVisibility(); SetWidgetVisibility();
@@ -351,11 +339,7 @@ void MacroActionSwitchSceneEdit::SetWidgetVisibility()
void MacroActionSwitchSceneEdit::SceneChanged(const SceneSelection &s) void MacroActionSwitchSceneEdit::SceneChanged(const SceneSelection &s)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_scene = s; _entryData->_scene = s;
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));
@@ -363,11 +347,7 @@ void MacroActionSwitchSceneEdit::SceneChanged(const SceneSelection &s)
void MacroActionSwitchSceneEdit::TransitionChanged(const TransitionSelection &t) void MacroActionSwitchSceneEdit::TransitionChanged(const TransitionSelection &t)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_transition = t; _entryData->_transition = t;
SetWidgetVisibility(); SetWidgetVisibility();
} }

View File

@@ -170,22 +170,14 @@ void MacroActionSceneVisibilityEdit::UpdateEntryData()
void MacroActionSceneVisibilityEdit::SceneChanged(const SceneSelection &s) void MacroActionSceneVisibilityEdit::SceneChanged(const SceneSelection &s)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_scene = s; _entryData->_scene = s;
} }
void MacroActionSceneVisibilityEdit::SourceChanged( void MacroActionSceneVisibilityEdit::SourceChanged(
const SceneItemSelection &item) const SceneItemSelection &item)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_source = item; _entryData->_source = item;
emit HeaderInfoChanged( emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc())); QString::fromStdString(_entryData->GetShortDesc()));
@@ -195,11 +187,7 @@ void MacroActionSceneVisibilityEdit::SourceChanged(
void MacroActionSceneVisibilityEdit::ActionChanged(int value) void MacroActionSceneVisibilityEdit::ActionChanged(int value)
{ {
if (_loading || !_entryData) { GUARD_LOADING_AND_LOCK();
return;
}
auto lock = LockContext();
_entryData->_action = _entryData->_action =
static_cast<MacroActionSceneVisibility::Action>(value); static_cast<MacroActionSceneVisibility::Action>(value);
} }

View File

@@ -193,12 +193,19 @@ static void populateTargetTypeSelection(QComboBox *list)
list->addItem(obs_module_text("AdvSceneSwitcher.OBSVideoOutput")); list->addItem(obs_module_text("AdvSceneSwitcher.OBSVideoOutput"));
} }
static QStringList getVideoSourcesList()
{
auto sources = GetVideoSourceNames();
sources.sort();
return sources;
}
MacroActionScreenshotEdit::MacroActionScreenshotEdit( MacroActionScreenshotEdit::MacroActionScreenshotEdit(
QWidget *parent, std::shared_ptr<MacroActionScreenshot> entryData) QWidget *parent, std::shared_ptr<MacroActionScreenshot> entryData)
: QWidget(parent), : QWidget(parent),
_scenes(new SceneSelectionWidget(this, true, false, true, true, _scenes(new SceneSelectionWidget(this, true, false, true, true,
true)), true)),
_sources(new SourceSelectionWidget(this, QStringList(), true)), _sources(new SourceSelectionWidget(this, getVideoSourcesList, true)),
_saveType(new QComboBox()), _saveType(new QComboBox()),
_targetType(new QComboBox()), _targetType(new QComboBox()),
_savePath(new FileSelection(FileSelection::Type::WRITE, this)), _savePath(new FileSelection(FileSelection::Type::WRITE, this)),
@@ -206,9 +213,6 @@ MacroActionScreenshotEdit::MacroActionScreenshotEdit(
{ {
setToolTip(obs_module_text( setToolTip(obs_module_text(
"AdvSceneSwitcher.action.screenshot.blackscreenNote")); "AdvSceneSwitcher.action.screenshot.blackscreenNote"));
auto sources = GetVideoSourceNames();
sources.sort();
_sources->SetSourceNameList(sources);
populateSaveTypeSelection(_saveType); populateSaveTypeSelection(_saveType);
populateTargetTypeSelection(_targetType); populateTargetTypeSelection(_targetType);

Some files were not shown because too many files have changed in this diff Show More