mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-09-07 17:16:00 -05:00
Compare commits
70 Commits
studio-mod
...
1.32.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f35ef558ee | ||
|
|
d7ff9088f8 | ||
|
|
7048925d6e | ||
|
|
fcb3ea50d3 | ||
|
|
87c45e2b32 | ||
|
|
eb5046a9d6 | ||
|
|
58c05f3f6e | ||
|
|
0b284da3de | ||
|
|
03fe7016e4 | ||
|
|
2ea89912a3 | ||
|
|
78d2efa083 | ||
|
|
149fce1c2b | ||
|
|
2dd9120265 | ||
|
|
3a9f315b67 | ||
|
|
6ba01dca39 | ||
|
|
ad1f1effeb | ||
|
|
0a53a8649f | ||
|
|
7ea721f9f1 | ||
|
|
718a899a98 | ||
|
|
4c493451f4 | ||
|
|
a8d483f5a7 | ||
|
|
dc786a5313 | ||
|
|
628a4d896c | ||
|
|
74a9681c8e | ||
|
|
faf52c38bb | ||
|
|
bad1a548fb | ||
|
|
f706416df5 | ||
|
|
c344c88acd | ||
|
|
2cd9e61717 | ||
|
|
6314de8f37 | ||
|
|
6bfcabc4af | ||
|
|
69711d973a | ||
|
|
225913b44d | ||
|
|
7c6d657fdd | ||
|
|
12e38274f5 | ||
|
|
5d49e8825b | ||
|
|
21c34356ed | ||
|
|
266e470509 | ||
|
|
de20c93b14 | ||
|
|
b0d877db8c | ||
|
|
caf9e59475 | ||
|
|
5f6982b5bb | ||
|
|
ce399cc647 | ||
|
|
03f67534c7 | ||
|
|
246667e65e | ||
|
|
68fe7716e7 | ||
|
|
98cc710b4a | ||
|
|
c602c30c54 | ||
|
|
cc1b89fe1d | ||
|
|
1de4ef7ec2 | ||
|
|
e29060fdea | ||
|
|
a0e6e6f528 | ||
|
|
e30d5845fa | ||
|
|
d12911cd02 | ||
|
|
b8ecc40e8c | ||
|
|
8ec4849b1d | ||
|
|
e6e9f3a831 | ||
|
|
555f7c1381 | ||
|
|
f0f8b0fd92 | ||
|
|
661e83162f | ||
|
|
4606f80a9d | ||
|
|
9c109742fb | ||
|
|
b8b0682aaf | ||
|
|
f93175db77 | ||
|
|
8f92ba3ffa | ||
|
|
0d56de11d1 | ||
|
|
e1020a1909 | ||
|
|
8b0bd4193b | ||
|
|
d55bb6bc86 | ||
|
|
0583331bfd |
@@ -6,18 +6,18 @@ You have the option to ...
|
|||||||
|
|
||||||
Both methods require [CMake](https://cmake.org/download/).
|
Both methods require [CMake](https://cmake.org/download/).
|
||||||
|
|
||||||
The plugin can be compiled for OBS 27 and above, although using the latest version of OBS is recommended to support all features.
|
The plugin can be compiled for OBS 31 and above, although using the latest version of OBS is recommended to support all features.
|
||||||
|
|
||||||
## Compiling in tree (recommended for development)
|
## Compiling in tree (recommended for development)
|
||||||
This section assumes that you have a working [OBS Studio development environment](https://obsproject.com/wiki/Building-OBS-Studio).
|
This section assumes that you have a working [OBS Studio development environment](https://obsproject.com/wiki/Building-OBS-Studio).
|
||||||
|
|
||||||
Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/UI/frontend-plugins/:
|
Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/plugins:
|
||||||
```
|
```
|
||||||
cd obs-studio/UI/frontend-plugins/
|
cd obs-studio/plugins
|
||||||
git clone --recursive https://github.com/WarmUpTill/SceneSwitcher.git
|
git clone --recursive https://github.com/WarmUpTill/SceneSwitcher.git
|
||||||
```
|
```
|
||||||
|
|
||||||
Then modify the obs-studio/UI/frontend-plugins/CMakeLists.txt Example and add an entry for the scene switcher:
|
Then modify the obs-studio/plugins/CMakeLists.txt and add an entry for the scene switcher:
|
||||||
```
|
```
|
||||||
add_subdirectory(SceneSwitcher)
|
add_subdirectory(SceneSwitcher)
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -146,6 +146,8 @@ target_sources(
|
|||||||
lib/macro/macro-ref.hpp
|
lib/macro/macro-ref.hpp
|
||||||
lib/macro/macro-run-button.cpp
|
lib/macro/macro-run-button.cpp
|
||||||
lib/macro/macro-run-button.hpp
|
lib/macro/macro-run-button.hpp
|
||||||
|
lib/macro/macro-search.cpp
|
||||||
|
lib/macro/macro-search.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
|
||||||
@@ -164,6 +166,7 @@ target_sources(
|
|||||||
lib/macro/macro-tab.cpp
|
lib/macro/macro-tab.cpp
|
||||||
lib/macro/macro-tree.cpp
|
lib/macro/macro-tree.cpp
|
||||||
lib/macro/macro-tree.hpp
|
lib/macro/macro-tree.hpp
|
||||||
|
lib/macro/macro-websocket-trigger.cpp
|
||||||
lib/macro/macro.cpp
|
lib/macro/macro.cpp
|
||||||
lib/macro/macro.hpp)
|
lib/macro/macro.hpp)
|
||||||
|
|
||||||
@@ -182,6 +185,8 @@ target_sources(
|
|||||||
lib/utils/canvas-helpers.hpp
|
lib/utils/canvas-helpers.hpp
|
||||||
lib/utils/condition-logic.cpp
|
lib/utils/condition-logic.cpp
|
||||||
lib/utils/condition-logic.hpp
|
lib/utils/condition-logic.hpp
|
||||||
|
lib/utils/crash-handler.cpp
|
||||||
|
lib/utils/crash-handler.hpp
|
||||||
lib/utils/curl-helper.cpp
|
lib/utils/curl-helper.cpp
|
||||||
lib/utils/curl-helper.hpp
|
lib/utils/curl-helper.hpp
|
||||||
lib/utils/cursor-shape-changer.cpp
|
lib/utils/cursor-shape-changer.cpp
|
||||||
|
|||||||
@@ -180,24 +180,46 @@ function(_check_dependencies)
|
|||||||
set(url ${url}/${version}/${file})
|
set(url ${url}/${version}/${file})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(MAX_DOWNLOAD_RETRIES 3)
|
||||||
|
set(RETRY_DELAY 60) # seconds
|
||||||
|
|
||||||
if(NOT EXISTS "${dependencies_dir}/${file}")
|
if(NOT EXISTS "${dependencies_dir}/${file}")
|
||||||
message(STATUS "Downloading ${url}")
|
message(STATUS "Downloading ${url}")
|
||||||
file(
|
|
||||||
DOWNLOAD "${url}" "${dependencies_dir}/${file}"
|
|
||||||
STATUS download_status
|
|
||||||
EXPECTED_HASH SHA256=${hash})
|
|
||||||
|
|
||||||
list(GET download_status 0 error_code)
|
set(download_success FALSE)
|
||||||
list(GET download_status 1 error_message)
|
|
||||||
if(error_code GREATER 0)
|
foreach(i RANGE 1 ${MAX_DOWNLOAD_RETRIES})
|
||||||
message(STATUS "Downloading ${url} - Failure")
|
message(STATUS "Attempt ${i}/${MAX_DOWNLOAD_RETRIES} for ${url}")
|
||||||
|
|
||||||
|
file(
|
||||||
|
DOWNLOAD "${url}" "${dependencies_dir}/${file}"
|
||||||
|
STATUS download_status
|
||||||
|
EXPECTED_HASH SHA256=${hash})
|
||||||
|
|
||||||
|
list(GET download_status 0 error_code)
|
||||||
|
list(GET download_status 1 error_message)
|
||||||
|
|
||||||
|
if(error_code EQUAL 0)
|
||||||
|
message(STATUS "Downloading ${url} - success on attempt ${i}")
|
||||||
|
set(download_success TRUE)
|
||||||
|
break()
|
||||||
|
else()
|
||||||
|
message(WARNING "Download failed (attempt ${i}): ${error_message}")
|
||||||
|
file(REMOVE "${dependencies_dir}/${file}")
|
||||||
|
|
||||||
|
if(NOT i EQUAL MAX_DOWNLOAD_RETRIES)
|
||||||
|
message(STATUS "Retrying in ${RETRY_DELAY} seconds...")
|
||||||
|
execute_process(COMMAND ${CMAKE_COMMAND} -E sleep ${RETRY_DELAY})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(NOT download_success)
|
||||||
message(
|
message(
|
||||||
FATAL_ERROR
|
FATAL_ERROR
|
||||||
"Unable to download ${url}, failed with error: ${error_message}")
|
"Unable to download ${url} after ${MAX_DOWNLOAD_RETRIES} attempts")
|
||||||
file(REMOVE "${dependencies_dir}/${file}")
|
|
||||||
else()
|
|
||||||
message(STATUS "Downloading ${url} - done")
|
|
||||||
endif()
|
endif()
|
||||||
|
message(STATUS "Downloading ${url} - done")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT EXISTS "${dependencies_dir}/${destination}")
|
if(NOT EXISTS "${dependencies_dir}/${destination}")
|
||||||
|
|||||||
@@ -291,14 +291,14 @@ AdvSceneSwitcher.condition.replay.state.started="Replay Buffer gestartet"
|
|||||||
AdvSceneSwitcher.condition.replay.state.saved="Replay Buffer gespeichert"
|
AdvSceneSwitcher.condition.replay.state.saved="Replay Buffer gespeichert"
|
||||||
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
||||||
AdvSceneSwitcher.condition.date="Datum"
|
AdvSceneSwitcher.condition.date="Datum"
|
||||||
AdvSceneSwitcher.condition.date.anyDay="Beliebiger Tag"
|
AdvSceneSwitcher.day.any="Beliebiger Tag"
|
||||||
AdvSceneSwitcher.condition.date.monday="Montag"
|
AdvSceneSwitcher.day.monday="Montag"
|
||||||
AdvSceneSwitcher.condition.date.tuesday="Dienstag"
|
AdvSceneSwitcher.day.tuesday="Dienstag"
|
||||||
AdvSceneSwitcher.condition.date.wednesday="Mittwoch"
|
AdvSceneSwitcher.day.wednesday="Mittwoch"
|
||||||
AdvSceneSwitcher.condition.date.thursday="Donnerstag"
|
AdvSceneSwitcher.day.thursday="Donnerstag"
|
||||||
AdvSceneSwitcher.condition.date.friday="Freitag"
|
AdvSceneSwitcher.day.friday="Freitag"
|
||||||
AdvSceneSwitcher.condition.date.saturday="Samstag"
|
AdvSceneSwitcher.day.saturday="Samstag"
|
||||||
AdvSceneSwitcher.condition.date.sunday="Sonntag"
|
AdvSceneSwitcher.day.sunday="Sonntag"
|
||||||
AdvSceneSwitcher.condition.date.state.at="Am"
|
AdvSceneSwitcher.condition.date.state.at="Am"
|
||||||
AdvSceneSwitcher.condition.date.state.after="Nach"
|
AdvSceneSwitcher.condition.date.state.after="Nach"
|
||||||
AdvSceneSwitcher.condition.date.state.before="Vor"
|
AdvSceneSwitcher.condition.date.state.before="Vor"
|
||||||
@@ -309,12 +309,13 @@ AdvSceneSwitcher.condition.date.ignoreDate="Wenn diese Option nicht aktiviert is
|
|||||||
AdvSceneSwitcher.condition.date.ignoreTime="Wenn diese Option nicht aktiviert ist, wird die Zeitkomponente ignoriert"
|
AdvSceneSwitcher.condition.date.ignoreTime="Wenn diese Option nicht aktiviert ist, wird die Zeitkomponente ignoriert"
|
||||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="Erweiterte Einstellungen anzeigen"
|
AdvSceneSwitcher.condition.date.showAdvancedSettings="Erweiterte Einstellungen anzeigen"
|
||||||
AdvSceneSwitcher.condition.date.showSimpleSettings="Einfache Einstellungen anzeigen"
|
AdvSceneSwitcher.condition.date.showSimpleSettings="Einfache Einstellungen anzeigen"
|
||||||
AdvSceneSwitcher.condition.date.entry.simple="Am {{dayOfWeek}} {{weekCondition}} {{ignoreWeekTime}}{{weekTime}}"
|
AdvSceneSwitcher.condition.date.layout.simple.day="Am{{dayOfWeek}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
|
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}} Wiederholen alle {{duration}} bei Datumsübereinstimmung"
|
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.pattern="Aktuelles Datum \"{{currentDate}}\" entspricht dem Muster {{pattern}}"
|
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}} Wiederholen alle {{duration}} bei Datumsübereinstimmung"
|
||||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Nächster Treffer bei: %1"
|
AdvSceneSwitcher.condition.date.layout.pattern="Aktuelles Datum \"{{currentDate}}\" entspricht dem Muster {{pattern}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} Bei Wiederholung ausgewähltes Datum auf Wiederholungsdatum aktualisieren"
|
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Nächster Treffer bei: %1"
|
||||||
|
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}} Bei Wiederholung ausgewähltes Datum auf Wiederholungsdatum aktualisieren"
|
||||||
AdvSceneSwitcher.condition.sceneTransform="Szenenelement transformieren"
|
AdvSceneSwitcher.condition.sceneTransform="Szenenelement transformieren"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Transformation erhalten"
|
AdvSceneSwitcher.condition.sceneTransform.getTransform="Transformation erhalten"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.condition.match="entspricht Transformation"
|
AdvSceneSwitcher.condition.sceneTransform.condition.match="entspricht Transformation"
|
||||||
@@ -429,7 +430,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Verstecken"
|
|||||||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Umschalten"
|
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Umschalten"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Quelle"
|
AdvSceneSwitcher.action.sceneVisibility.type.source="Quelle"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Beliebig"
|
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Beliebig"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.entry="Auf{{scenes}}{{actions}}{{sources}}"
|
AdvSceneSwitcher.action.sceneVisibility.layout="Auf{{scenes}}{{actions}}{{sources}}"
|
||||||
AdvSceneSwitcher.action.filter="Filter"
|
AdvSceneSwitcher.action.filter="Filter"
|
||||||
AdvSceneSwitcher.action.filter.type.enable="Aktivieren"
|
AdvSceneSwitcher.action.filter.type.enable="Aktivieren"
|
||||||
AdvSceneSwitcher.action.filter.type.disable="Deaktivieren"
|
AdvSceneSwitcher.action.filter.type.disable="Deaktivieren"
|
||||||
|
|||||||
@@ -43,7 +43,9 @@ 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.generalBehavior.alwaysShowMacroSearch="Always show macro search"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.alwaysShowFeatureTabs="Always show all feature tabs"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.alwaysShowFeatureTabs.tooltip="Show tabs that are normally hidden until first used in a macro (e.g. Action Queues, Variables, Twitch, Websockets)."
|
||||||
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)"
|
||||||
@@ -74,6 +76,7 @@ AdvSceneSwitcher.generalTab.setTransitionBy="When changing transitions:"
|
|||||||
AdvSceneSwitcher.generalTab.transitionOverride="Set transition overrides"
|
AdvSceneSwitcher.generalTab.transitionOverride="Set transition overrides"
|
||||||
AdvSceneSwitcher.generalTab.adjustActiveTransitionType="Change active transition type"
|
AdvSceneSwitcher.generalTab.adjustActiveTransitionType="Change active transition type"
|
||||||
AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="At least one option must be enabled:\n\n - Use transition overrides\n\n - Change active transition type"
|
AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="At least one option must be enabled:\n\n - Use transition overrides\n\n - Change active transition type"
|
||||||
|
AdvSceneSwitcher.generalTab.uiBehavior="UI settings"
|
||||||
|
|
||||||
# Variables Tab
|
# Variables Tab
|
||||||
AdvSceneSwitcher.variableTab.title="Variables"
|
AdvSceneSwitcher.variableTab.title="Variables"
|
||||||
@@ -91,6 +94,12 @@ AdvSceneSwitcher.variableTab.lastUsed.text.never="Never"
|
|||||||
AdvSceneSwitcher.variableTab.lastChanged.header="Last changed"
|
AdvSceneSwitcher.variableTab.lastChanged.header="Last changed"
|
||||||
AdvSceneSwitcher.variableTab.lastChanged.text.none="No change since launch"
|
AdvSceneSwitcher.variableTab.lastChanged.text.none="No change since launch"
|
||||||
AdvSceneSwitcher.variableTab.lastChanged.tooltip="Times changed: %1\n\nPrevious value: %2"
|
AdvSceneSwitcher.variableTab.lastChanged.tooltip="Times changed: %1\n\nPrevious value: %2"
|
||||||
|
AdvSceneSwitcher.variableTab.search.placeholder="Search ..."
|
||||||
|
AdvSceneSwitcher.variableTab.search.all="All columns"
|
||||||
|
AdvSceneSwitcher.variableTab.search.name="Name column"
|
||||||
|
AdvSceneSwitcher.variableTab.search.value="Value column"
|
||||||
|
AdvSceneSwitcher.variableTab.addDock="Add dock"
|
||||||
|
AdvSceneSwitcher.variableTab.clear="Clear"
|
||||||
|
|
||||||
# Action Queue Tab
|
# Action Queue Tab
|
||||||
AdvSceneSwitcher.actionQueueTab.title="Action Queues"
|
AdvSceneSwitcher.actionQueueTab.title="Action Queues"
|
||||||
@@ -151,6 +160,8 @@ AdvSceneSwitcher.macroTab.title="Macro"
|
|||||||
AdvSceneSwitcher.macroTab.macros="Macros"
|
AdvSceneSwitcher.macroTab.macros="Macros"
|
||||||
AdvSceneSwitcher.macroTab.priorityWarning="Note: It is recommended to configure macros to be the highest priority functionality.\nThis setting can be changed on the General tab."
|
AdvSceneSwitcher.macroTab.priorityWarning="Note: It is recommended to configure macros to be the highest priority functionality.\nThis setting can be changed on the General tab."
|
||||||
AdvSceneSwitcher.macroTab.help="Macros allow you to execute a string of actions depending on multiple conditions.\n\nClick on the highlighted plus symbol to add a new Macro."
|
AdvSceneSwitcher.macroTab.help="Macros allow you to execute a string of actions depending on multiple conditions.\n\nClick on the highlighted plus symbol to add a new Macro."
|
||||||
|
AdvSceneSwitcher.macroTab.macroLastExecutedTooltip="Was last executed %1 seconds ago."
|
||||||
|
AdvSceneSwitcher.macroTab.macroNotYetExecutedTooltip="Was not yet executed."
|
||||||
AdvSceneSwitcher.macroTab.editConditionHelp="This section allows you to define macro conditions.\n\nSelect an existing or add a new macro on the left.\nThen click the plus button below to add a new condition."
|
AdvSceneSwitcher.macroTab.editConditionHelp="This section allows you to define macro conditions.\n\nSelect an existing or add a new macro on the left.\nThen click the plus button below to add a new condition."
|
||||||
AdvSceneSwitcher.macroTab.editActionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are met.\n\nSelect an existing or add a new macro on the left.\nThen click the plus button below to add a new action."
|
AdvSceneSwitcher.macroTab.editActionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are met.\n\nSelect an existing or add a new macro on the left.\nThen click the plus button below to add a new action."
|
||||||
AdvSceneSwitcher.macroTab.editElseActionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are *not* met.\n\nSelect an existing or add a new macro on the left.\nThen click the plus button below to add a new action."
|
AdvSceneSwitcher.macroTab.editElseActionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are *not* met.\n\nSelect an existing or add a new macro on the left.\nThen click the plus button below to add a new action."
|
||||||
@@ -270,6 +281,13 @@ AdvSceneSwitcher.macroTab.tooltip.elseActionUpButton="Move selected action up in
|
|||||||
AdvSceneSwitcher.macroTab.tooltip.elseActionDownButton="Move selected action down in the else section"
|
AdvSceneSwitcher.macroTab.tooltip.elseActionDownButton="Move selected action down in the else section"
|
||||||
AdvSceneSwitcher.macroTab.tooltip.elseActionBottomButton="Move selected action to the bottom in the else section"
|
AdvSceneSwitcher.macroTab.tooltip.elseActionBottomButton="Move selected action to the bottom in the else section"
|
||||||
AdvSceneSwitcher.macroTab.tooltip.openMacroSettingsButton="Open macro settings"
|
AdvSceneSwitcher.macroTab.tooltip.openMacroSettingsButton="Open macro settings"
|
||||||
|
AdvSceneSwitcher.macroTab.search.placeholder="Search ..."
|
||||||
|
AdvSceneSwitcher.macroTab.search.showSettings="Show search settings"
|
||||||
|
AdvSceneSwitcher.macroTab.search.name="Name"
|
||||||
|
AdvSceneSwitcher.macroTab.search.allSegments="Segment type"
|
||||||
|
AdvSceneSwitcher.macroTab.search.conditions="Condition type"
|
||||||
|
AdvSceneSwitcher.macroTab.search.actions="Action type"
|
||||||
|
AdvSceneSwitcher.macroTab.search.label="Segment label"
|
||||||
|
|
||||||
AdvSceneSwitcher.macroDock.pause="Pause"
|
AdvSceneSwitcher.macroDock.pause="Pause"
|
||||||
AdvSceneSwitcher.macroDock.unpause="Unpause"
|
AdvSceneSwitcher.macroDock.unpause="Unpause"
|
||||||
@@ -571,14 +589,6 @@ AdvSceneSwitcher.condition.replay.state.started="Replay buffer started"
|
|||||||
AdvSceneSwitcher.condition.replay.state.saved="Replay buffer saved"
|
AdvSceneSwitcher.condition.replay.state.saved="Replay buffer saved"
|
||||||
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
||||||
AdvSceneSwitcher.condition.date="Date"
|
AdvSceneSwitcher.condition.date="Date"
|
||||||
AdvSceneSwitcher.condition.date.anyDay="Any day"
|
|
||||||
AdvSceneSwitcher.condition.date.monday="Monday"
|
|
||||||
AdvSceneSwitcher.condition.date.tuesday="Tuesday"
|
|
||||||
AdvSceneSwitcher.condition.date.wednesday="Wednesday"
|
|
||||||
AdvSceneSwitcher.condition.date.thursday="Thursday"
|
|
||||||
AdvSceneSwitcher.condition.date.friday="Friday"
|
|
||||||
AdvSceneSwitcher.condition.date.saturday="Saturday"
|
|
||||||
AdvSceneSwitcher.condition.date.sunday="Sunday"
|
|
||||||
AdvSceneSwitcher.condition.date.state.at="At"
|
AdvSceneSwitcher.condition.date.state.at="At"
|
||||||
AdvSceneSwitcher.condition.date.state.after="After"
|
AdvSceneSwitcher.condition.date.state.after="After"
|
||||||
AdvSceneSwitcher.condition.date.state.before="Before"
|
AdvSceneSwitcher.condition.date.state.before="Before"
|
||||||
@@ -589,12 +599,13 @@ AdvSceneSwitcher.condition.date.ignoreDate="If unchecked the date component will
|
|||||||
AdvSceneSwitcher.condition.date.ignoreTime="If unchecked the time component will be ignored"
|
AdvSceneSwitcher.condition.date.ignoreTime="If unchecked the time component will be ignored"
|
||||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="Show advanced settings"
|
AdvSceneSwitcher.condition.date.showAdvancedSettings="Show advanced settings"
|
||||||
AdvSceneSwitcher.condition.date.showSimpleSettings="Show simple settings"
|
AdvSceneSwitcher.condition.date.showSimpleSettings="Show simple settings"
|
||||||
AdvSceneSwitcher.condition.date.entry.simple="On{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
|
AdvSceneSwitcher.condition.date.layout.simple.day="On{{dayOfWeek}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
|
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}}Repeat every{{duration}}on date match"
|
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.pattern="Current date \"{{currentDate}}\" matches pattern{{pattern}}"
|
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}}Repeat every{{duration}}on date match"
|
||||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Next match at: %1"
|
AdvSceneSwitcher.condition.date.layout.pattern="Current date \"{{currentDate}}\" matches pattern{{pattern}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}}On repeat update selected date to repeat date"
|
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Next match at: %1"
|
||||||
|
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}}On repeat update selected date to repeat date"
|
||||||
AdvSceneSwitcher.condition.sceneTransform="Scene item transform"
|
AdvSceneSwitcher.condition.sceneTransform="Scene item transform"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Get transform"
|
AdvSceneSwitcher.condition.sceneTransform.getTransform="Get transform"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="Get current value"
|
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="Get current value"
|
||||||
@@ -900,7 +911,9 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
|
|||||||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Toggle"
|
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Toggle"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
|
AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Any"
|
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Any"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.entry="On{{scenes}}{{actions}}{{sources}}"
|
AdvSceneSwitcher.action.sceneVisibility.layout="On{{scenes}}{{actions}}{{sources}}"
|
||||||
|
AdvSceneSwitcher.action.sceneVisibility.layout.transition="{{updateTransition}}Set transition to{{transitions}}"
|
||||||
|
AdvSceneSwitcher.action.sceneVisibility.layout.duration="{{updateDuration}}Set transition duration to{{duration}}seconds"
|
||||||
AdvSceneSwitcher.action.filter="Filter"
|
AdvSceneSwitcher.action.filter="Filter"
|
||||||
AdvSceneSwitcher.action.filter.type.enable="Enable"
|
AdvSceneSwitcher.action.filter.type.enable="Enable"
|
||||||
AdvSceneSwitcher.action.filter.type.disable="Disable"
|
AdvSceneSwitcher.action.filter.type.disable="Disable"
|
||||||
@@ -928,6 +941,9 @@ AdvSceneSwitcher.action.source.type.deinterlaceOrder="Set deinterlace field orde
|
|||||||
AdvSceneSwitcher.action.source.type.openInteractionDialog="Open interaction dialog"
|
AdvSceneSwitcher.action.source.type.openInteractionDialog="Open interaction dialog"
|
||||||
AdvSceneSwitcher.action.source.type.openFilterDialog="Open filter dialog"
|
AdvSceneSwitcher.action.source.type.openFilterDialog="Open filter dialog"
|
||||||
AdvSceneSwitcher.action.source.type.openPropertiesDialog="Open properties dialog"
|
AdvSceneSwitcher.action.source.type.openPropertiesDialog="Open properties dialog"
|
||||||
|
AdvSceneSwitcher.action.source.type.closeInteractionDialog="Close interaction dialog"
|
||||||
|
AdvSceneSwitcher.action.source.type.closeFilterDialog="Close filter dialog"
|
||||||
|
AdvSceneSwitcher.action.source.type.closePropertiesDialog="Close properties dialog"
|
||||||
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}{{refresh}}"
|
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}{{refresh}}"
|
||||||
AdvSceneSwitcher.action.source.entry.settings="{{settings}}{{settingsInputMethod}}{{settingValue}}{{tempVar}}"
|
AdvSceneSwitcher.action.source.entry.settings="{{settings}}{{settingsInputMethod}}{{settingValue}}{{tempVar}}"
|
||||||
AdvSceneSwitcher.action.source.warning="Warning: Enabling and disabling sources globally cannot be controlled by the OBS UI\nYou might be looking for \"Scene item visibility\""
|
AdvSceneSwitcher.action.source.warning="Warning: Enabling and disabling sources globally cannot be controlled by the OBS UI\nYou might be looking for \"Scene item visibility\""
|
||||||
@@ -949,6 +965,7 @@ AdvSceneSwitcher.action.source.inputMethod.individualTempvar="Set to macro prope
|
|||||||
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"
|
||||||
AdvSceneSwitcher.action.source.refresh.tooltip="Repopulate the source settings selection with the settings of the source which's name matches the variable value."
|
AdvSceneSwitcher.action.source.refresh.tooltip="Repopulate the source settings selection with the settings of the source which's name matches the variable value."
|
||||||
|
AdvSceneSwitcher.action.source.dialog.accept="Accept changes"
|
||||||
AdvSceneSwitcher.action.media="Media"
|
AdvSceneSwitcher.action.media="Media"
|
||||||
AdvSceneSwitcher.action.media.type.play="Play"
|
AdvSceneSwitcher.action.media.type.play="Play"
|
||||||
AdvSceneSwitcher.action.media.type.pause="Pause"
|
AdvSceneSwitcher.action.media.type.pause="Pause"
|
||||||
@@ -984,12 +1001,16 @@ AdvSceneSwitcher.action.macro.type.disableAction="Disable action"
|
|||||||
AdvSceneSwitcher.action.macro.type.enableAction="Enable action"
|
AdvSceneSwitcher.action.macro.type.enableAction="Enable action"
|
||||||
AdvSceneSwitcher.action.macro.type.toggleAction="Toggle action"
|
AdvSceneSwitcher.action.macro.type.toggleAction="Toggle action"
|
||||||
AdvSceneSwitcher.action.macro.type.nestedMacro="Nested macro"
|
AdvSceneSwitcher.action.macro.type.nestedMacro="Nested macro"
|
||||||
|
AdvSceneSwitcher.action.macro.actionSelectionType.index="at index"
|
||||||
|
AdvSceneSwitcher.action.macro.actionSelectionType.label="with label"
|
||||||
|
AdvSceneSwitcher.action.macro.actionSelectionType.id="of action type"
|
||||||
AdvSceneSwitcher.action.macro.type.nestedMacro.conditionHelp="This section allows you to define macro conditions.\n\nClick the plus button below to add a new condition."
|
AdvSceneSwitcher.action.macro.type.nestedMacro.conditionHelp="This section allows you to define macro conditions.\n\nClick the plus button below to add a new condition."
|
||||||
AdvSceneSwitcher.action.macro.type.nestedMacro.actionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are met.\n\nClick the plus button below to add a new action."
|
AdvSceneSwitcher.action.macro.type.nestedMacro.actionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are met.\n\nClick the plus button below to add a new action."
|
||||||
AdvSceneSwitcher.action.macro.type.nestedMacro.elseActionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are *not* met.\n\nClick the plus button below to add a new action."
|
AdvSceneSwitcher.action.macro.type.nestedMacro.elseActionHelp="This section allows you to define macro actions.\nThe actions in this section will be performed when the conditions are *not* met.\n\nClick the plus button below to add a new action."
|
||||||
AdvSceneSwitcher.action.macro.entry.run="{{actions}}{{actionTypes}}of{{macros}}"
|
AdvSceneSwitcher.action.macro.layout.run="{{actions}}{{actionSections}}of{{macros}}"
|
||||||
AdvSceneSwitcher.action.macro.entry.run.condition="{{conditionBehaviors}}of{{conditionMacros}}"
|
AdvSceneSwitcher.action.macro.layout.run.condition="{{conditionBehaviors}}of{{conditionMacros}}"
|
||||||
AdvSceneSwitcher.action.macro.entry.other="{{actions}}{{actionIndex}}{{macros}}"
|
AdvSceneSwitcher.action.macro.layout.actionState="{{actions}}{{actionSelectionType}}{{actionIndex}}{{label}}{{regex}}{{actionTypes}}in{{actionSections}}section of{{macros}}"
|
||||||
|
AdvSceneSwitcher.action.macro.layout.other="{{actions}}{{macros}}"
|
||||||
AdvSceneSwitcher.action.pluginState="Plugin state"
|
AdvSceneSwitcher.action.pluginState="Plugin state"
|
||||||
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
|
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
|
||||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Change the no-match behaviour:"
|
AdvSceneSwitcher.action.pluginState.type.noMatch="Change the no-match behaviour:"
|
||||||
@@ -1141,6 +1162,7 @@ AdvSceneSwitcher.action.http.entry.line2="Timeout:{{timeout}}seconds"
|
|||||||
AdvSceneSwitcher.action.variable="Variable"
|
AdvSceneSwitcher.action.variable="Variable"
|
||||||
AdvSceneSwitcher.action.variable.type.set="Set to value"
|
AdvSceneSwitcher.action.variable.type.set="Set to value"
|
||||||
AdvSceneSwitcher.action.variable.type.append="Append"
|
AdvSceneSwitcher.action.variable.type.append="Append"
|
||||||
|
AdvSceneSwitcher.action.variable.type.copy="Copy variable"
|
||||||
AdvSceneSwitcher.action.variable.type.appendVar="Append variable"
|
AdvSceneSwitcher.action.variable.type.appendVar="Append variable"
|
||||||
AdvSceneSwitcher.action.variable.type.increment="Increment"
|
AdvSceneSwitcher.action.variable.type.increment="Increment"
|
||||||
AdvSceneSwitcher.action.variable.type.decrement="Decrement"
|
AdvSceneSwitcher.action.variable.type.decrement="Decrement"
|
||||||
@@ -1167,6 +1189,8 @@ AdvSceneSwitcher.action.variable.type.swapValues="Swap variable values"
|
|||||||
AdvSceneSwitcher.action.variable.type.trim="Trim whitespace"
|
AdvSceneSwitcher.action.variable.type.trim="Trim whitespace"
|
||||||
AdvSceneSwitcher.action.variable.type.changeCase="Change case"
|
AdvSceneSwitcher.action.variable.type.changeCase="Change case"
|
||||||
AdvSceneSwitcher.action.variable.type.randomNumber="Generate random number"
|
AdvSceneSwitcher.action.variable.type.randomNumber="Generate random number"
|
||||||
|
AdvSceneSwitcher.action.variable.type.randomListValue="Select random value"
|
||||||
|
AdvSceneSwitcher.action.variable.type.allowRepeat="Allow repeat values"
|
||||||
AdvSceneSwitcher.action.variable.case.type.lowerCase="lowercase"
|
AdvSceneSwitcher.action.variable.case.type.lowerCase="lowercase"
|
||||||
AdvSceneSwitcher.action.variable.case.type.upperCase="UPPERCASE"
|
AdvSceneSwitcher.action.variable.case.type.upperCase="UPPERCASE"
|
||||||
AdvSceneSwitcher.action.variable.case.type.capitalized="Capitalized"
|
AdvSceneSwitcher.action.variable.case.type.capitalized="Capitalized"
|
||||||
@@ -1189,8 +1213,8 @@ AdvSceneSwitcher.action.variable.currentSegmentValue="Current value:"
|
|||||||
AdvSceneSwitcher.action.variable.layout.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}{{caseType}}{{jsonQuery}}{{jsonQueryHelp}}{{jsonIndex}}"
|
AdvSceneSwitcher.action.variable.layout.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}{{caseType}}{{jsonQuery}}{{jsonQueryHelp}}{{jsonIndex}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}of{{variables}}to length{{stringLength}}by adding{{paddingCharSelection}}to the{{direction}}"
|
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}of{{variables}}to length{{stringLength}}by adding{{paddingCharSelection}}to the{{direction}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}of{{variables}}to length{{stringLength}}by removing characters from the{{direction}}"
|
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}of{{variables}}to length{{stringLength}}by removing characters from the{{direction}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}"
|
AdvSceneSwitcher.action.variable.layout.substringIndex="Substring start:{{subStringStart}}Substring size:{{subStringSize}}{{subStringRegex}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
|
AdvSceneSwitcher.action.variable.layout.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:{{subStringRegex}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Use custom prompt{{inputPrompt}}"
|
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Use custom prompt{{inputPrompt}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Fill with placeholder{{inputPlaceholder}}"
|
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Fill with placeholder{{inputPlaceholder}}"
|
||||||
@@ -1233,12 +1257,14 @@ AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Disable chat's emote
|
|||||||
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Send chat message"
|
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Send chat message"
|
||||||
AdvSceneSwitcher.action.twitch.type.user.getInfo="Get user information"
|
AdvSceneSwitcher.action.twitch.type.user.getInfo="Get user information"
|
||||||
AdvSceneSwitcher.action.twitch.type.reward.getInfo="Get channel points reward information"
|
AdvSceneSwitcher.action.twitch.type.reward.getInfo="Get channel points reward information"
|
||||||
|
AdvSceneSwitcher.action.twitch.type.channel.getInfo="Get channel information"
|
||||||
AdvSceneSwitcher.action.twitch.reward.toggleControl="Toggle reward name / variable selection control"
|
AdvSceneSwitcher.action.twitch.reward.toggleControl="Toggle reward name / variable selection control"
|
||||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Cannot select category without selecting a Twitch account first!"
|
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Cannot select category without selecting a Twitch account first!"
|
||||||
AdvSceneSwitcher.action.twitch.entry.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
AdvSceneSwitcher.action.twitch.layout.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
||||||
AdvSceneSwitcher.action.twitch.entry.chat="Using account{{account}}{{actions}}on{{channel}}"
|
AdvSceneSwitcher.action.twitch.layout.chat="Using account{{account}}{{actions}}on{{channel}}"
|
||||||
AdvSceneSwitcher.action.twitch.entry.user.getInfo="Using account{{account}}{{actions}}for{{userInfoQueryType}}{{userLogin}}{{userId}}"
|
AdvSceneSwitcher.action.twitch.layout.channel.getInfo="Using account{{account}}{{actions}}of{{channel}}"
|
||||||
AdvSceneSwitcher.action.twitch.entry.reward.getInfo="Using account{{account}}{{actions}}for channel{{channel}}{{pointsReward}}{{rewardVariable}}{{toggleRewardSelection}}"
|
AdvSceneSwitcher.action.twitch.layout.user.getInfo="Using account{{account}}{{actions}}for{{userInfoQueryType}}{{userLogin}}{{userId}}"
|
||||||
|
AdvSceneSwitcher.action.twitch.layout.reward.getInfo="Using account{{account}}{{actions}}for channel{{channel}}{{pointsReward}}{{rewardVariable}}{{toggleRewardSelection}}"
|
||||||
AdvSceneSwitcher.action.twitch.title.title="Enter title"
|
AdvSceneSwitcher.action.twitch.title.title="Enter title"
|
||||||
AdvSceneSwitcher.action.twitch.marker.description="Describe marker"
|
AdvSceneSwitcher.action.twitch.marker.description="Describe marker"
|
||||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="Add a slight delay before capturing the clip"
|
AdvSceneSwitcher.action.twitch.clip.hasDelay="Add a slight delay before capturing the clip"
|
||||||
@@ -1363,6 +1389,8 @@ 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}}"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.crashDetected="OBS did not shut down cleanly (for example, due to a crash or freeze).\n\nThe Advanced Scene Switcher plugin would normally start automatically.\nWould you like to keep it stopped for now?"
|
||||||
|
|
||||||
AdvSceneSwitcher.close="Close"
|
AdvSceneSwitcher.close="Close"
|
||||||
AdvSceneSwitcher.browse="Browse"
|
AdvSceneSwitcher.browse="Browse"
|
||||||
|
|
||||||
@@ -1592,7 +1620,11 @@ AdvSceneSwitcher.twitchToken.moderator.chat.settings.manage="Manage channel's ch
|
|||||||
AdvSceneSwitcher.twitchToken.user.whispers.manage="Manage user's whispers."
|
AdvSceneSwitcher.twitchToken.user.whispers.manage="Manage user's whispers."
|
||||||
AdvSceneSwitcher.twitchToken.chat.read="View live stream chat messages."
|
AdvSceneSwitcher.twitchToken.chat.read="View live stream chat messages."
|
||||||
AdvSceneSwitcher.twitchToken.chat.edit="Send live stream chat messages."
|
AdvSceneSwitcher.twitchToken.chat.edit="Send live stream chat messages."
|
||||||
AdvSceneSwitcher.twitchToken.validateTimestamps="Validate timestamps of received Twitch event messages. (Recommended)"
|
AdvSceneSwitcher.twitchToken.validateTimestamps="Validate timestamps of received Twitch event messages."
|
||||||
|
AdvSceneSwitcher.twitchToken.validateTimestamps.tooltip="Verifies that incoming Twitch messages have valid timestamps to prevent replayed or spoofed messages.\nDisabling this won’t affect normal functionality, and you can try turning it off if you experience issues with the Twitch connection."
|
||||||
|
AdvSceneSwitcher.twitchToken.warnIfInvalid="Display warning if the token expired or is invalid."
|
||||||
|
AdvSceneSwitcher.twitchToken.warnIfInvalid.doNotShowAgain="Don't show again for this connection"
|
||||||
|
AdvSceneSwitcher.twitchToken.warnIfInvalid.message="The Twitch connection \"%1\" is invalid.\nOpen connection settings or ignore?"
|
||||||
|
|
||||||
AdvSceneSwitcher.twitch.selection.channel.open="Open channel"
|
AdvSceneSwitcher.twitch.selection.channel.open="Open channel"
|
||||||
AdvSceneSwitcher.twitch.selection.channel.open.tooltip.details="Open channel in external application handling the HTTPS protocol."
|
AdvSceneSwitcher.twitch.selection.channel.open.tooltip.details="Open channel in external application handling the HTTPS protocol."
|
||||||
@@ -2118,6 +2150,8 @@ AdvSceneSwitcher.tempVar.window.window="Window title"
|
|||||||
AdvSceneSwitcher.tempVar.window.window.description="The window title of the matching window."
|
AdvSceneSwitcher.tempVar.window.window.description="The window title of the matching window."
|
||||||
AdvSceneSwitcher.tempVar.window.windowClass="Window class"
|
AdvSceneSwitcher.tempVar.window.windowClass="Window class"
|
||||||
AdvSceneSwitcher.tempVar.window.windowClass.description="The window class of the matching window."
|
AdvSceneSwitcher.tempVar.window.windowClass.description="The window class of the matching window."
|
||||||
|
AdvSceneSwitcher.tempVar.window.windowText="Window text"
|
||||||
|
AdvSceneSwitcher.tempVar.window.windowText.description="Text contained within the window (won't work on all window types)."
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.timer.seconds="Seconds"
|
AdvSceneSwitcher.tempVar.timer.seconds="Seconds"
|
||||||
AdvSceneSwitcher.tempVar.timer.minutes="Minutes"
|
AdvSceneSwitcher.tempVar.timer.minutes="Minutes"
|
||||||
@@ -2159,6 +2193,8 @@ AdvSceneSwitcher.tempVar.run.process.none.description="When not waiting for the
|
|||||||
|
|
||||||
AdvSceneSwitcher.tempVar.recording.durationSeconds="Recording duration"
|
AdvSceneSwitcher.tempVar.recording.durationSeconds="Recording duration"
|
||||||
AdvSceneSwitcher.tempVar.recording.durationSeconds.description="Recording duration in seconds.\nThis value does not change while the recording is paused and will be reset to zero if the recording is stopped."
|
AdvSceneSwitcher.tempVar.recording.durationSeconds.description="Recording duration in seconds.\nThis value does not change while the recording is paused and will be reset to zero if the recording is stopped."
|
||||||
|
AdvSceneSwitcher.tempVar.recording.lastSavePath="Last save path"
|
||||||
|
AdvSceneSwitcher.tempVar.recording.lastSavePath.description="The file path of the last saved recording."
|
||||||
|
|
||||||
AdvSceneSwitcher.tempVar.video.patternCount="Pattern count"
|
AdvSceneSwitcher.tempVar.video.patternCount="Pattern count"
|
||||||
AdvSceneSwitcher.tempVar.video.patternCount.description="The number of times the given pattern has been found in a given video input frame."
|
AdvSceneSwitcher.tempVar.video.patternCount.description="The number of times the given pattern has been found in a given video input frame."
|
||||||
@@ -2308,6 +2344,9 @@ AdvSceneSwitcher.tempVar.mqtt.message="Message"
|
|||||||
AdvSceneSwitcher.tempVar.cursor.x="Cursor position (X)"
|
AdvSceneSwitcher.tempVar.cursor.x="Cursor position (X)"
|
||||||
AdvSceneSwitcher.tempVar.cursor.y="Cursor position (Y)"
|
AdvSceneSwitcher.tempVar.cursor.y="Cursor position (Y)"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.tempVar.replay.lastSavePath="Last save path"
|
||||||
|
AdvSceneSwitcher.tempVar.replay.lastSavePath.description="The file path of the last replay buffer saved."
|
||||||
|
|
||||||
AdvSceneSwitcher.selectScene="--select scene--"
|
AdvSceneSwitcher.selectScene="--select scene--"
|
||||||
AdvSceneSwitcher.selectCanvas="--select canvas--"
|
AdvSceneSwitcher.selectCanvas="--select canvas--"
|
||||||
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
||||||
@@ -2428,6 +2467,16 @@ AdvSceneSwitcher.clearBufferOnMatch="Clear message buffer when matching message
|
|||||||
AdvSceneSwitcher.script.settings="Settings"
|
AdvSceneSwitcher.script.settings="Settings"
|
||||||
AdvSceneSwitcher.script.timeout="Script timeout:{{timeout}}"
|
AdvSceneSwitcher.script.timeout="Script timeout:{{timeout}}"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.day.monday="Monday"
|
||||||
|
AdvSceneSwitcher.day.tuesday="Tuesday"
|
||||||
|
AdvSceneSwitcher.day.wednesday="Wednesday"
|
||||||
|
AdvSceneSwitcher.day.thursday="Thursday"
|
||||||
|
AdvSceneSwitcher.day.friday="Friday"
|
||||||
|
AdvSceneSwitcher.day.saturday="Saturday"
|
||||||
|
AdvSceneSwitcher.day.sunday="Sunday"
|
||||||
|
AdvSceneSwitcher.day.none="No day"
|
||||||
|
AdvSceneSwitcher.day.any="Any day"
|
||||||
|
|
||||||
# This secion is copied from the OBS locale files
|
# This secion is copied from the OBS locale files
|
||||||
|
|
||||||
# OBS commonly shared locale
|
# OBS commonly shared locale
|
||||||
|
|||||||
@@ -241,14 +241,14 @@ AdvSceneSwitcher.condition.replay.state.started="Búfer de reproducción iniciad
|
|||||||
AdvSceneSwitcher.condition.replay.state.saved="Búfer de reproducción guardado"
|
AdvSceneSwitcher.condition.replay.state.saved="Búfer de reproducción guardado"
|
||||||
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
||||||
AdvSceneSwitcher.condition.date="Fecha"
|
AdvSceneSwitcher.condition.date="Fecha"
|
||||||
AdvSceneSwitcher.condition.date.anyDay="Cualquier día"
|
AdvSceneSwitcher.day.any="Cualquier día"
|
||||||
AdvSceneSwitcher.condition.date.monday="Lunes"
|
AdvSceneSwitcher.day.monday="Lunes"
|
||||||
AdvSceneSwitcher.condition.date.tuesday="Martes"
|
AdvSceneSwitcher.day.tuesday="Martes"
|
||||||
AdvSceneSwitcher.condition.date.wednesday="Miércoles"
|
AdvSceneSwitcher.day.wednesday="Miércoles"
|
||||||
AdvSceneSwitcher.condition.date.thursday="Jueves"
|
AdvSceneSwitcher.day.thursday="Jueves"
|
||||||
AdvSceneSwitcher.condition.date.friday="Viernes"
|
AdvSceneSwitcher.day.friday="Viernes"
|
||||||
AdvSceneSwitcher.condition.date.saturday="Sábado"
|
AdvSceneSwitcher.day.saturday="Sábado"
|
||||||
AdvSceneSwitcher.condition.date.sunday="Domingo"
|
AdvSceneSwitcher.day.sunday="Domingo"
|
||||||
AdvSceneSwitcher.condition.date.state.at="A las"
|
AdvSceneSwitcher.condition.date.state.at="A las"
|
||||||
AdvSceneSwitcher.condition.date.state.after="Después"
|
AdvSceneSwitcher.condition.date.state.after="Después"
|
||||||
AdvSceneSwitcher.condition.date.state.before="Antes"
|
AdvSceneSwitcher.condition.date.state.before="Antes"
|
||||||
@@ -258,11 +258,12 @@ AdvSceneSwitcher.condition.date.ignoreDate="Si no se marca, se ignorará el comp
|
|||||||
AdvSceneSwitcher.condition.date.ignoreTime="Si no se marca, se ignorará el componente de tiempo"
|
AdvSceneSwitcher.condition.date.ignoreTime="Si no se marca, se ignorará el componente de tiempo"
|
||||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="Mostrar configuración avanzada"
|
AdvSceneSwitcher.condition.date.showAdvancedSettings="Mostrar configuración avanzada"
|
||||||
AdvSceneSwitcher.condition.date.showSimpleSettings="Mostrar configuración simple"
|
AdvSceneSwitcher.condition.date.showSimpleSettings="Mostrar configuración simple"
|
||||||
AdvSceneSwitcher.condition.date.entry.simple="El {{dayOfWeek}} {{weekCondition}} {{ignoreWeekTime}}{{weekTime}}"
|
AdvSceneSwitcher.condition.date.layout.simple.day="El{{dayOfWeek}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
|
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}} Repetir cada {{duration}} en la coincidencia de fechas"
|
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Próxima coincidencia en: %1"
|
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}} Repetir cada {{duration}} en la coincidencia de fechas"
|
||||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} Al repetir actualizar la fecha seleccionada para repetir la fecha"
|
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Próxima coincidencia en: %1"
|
||||||
|
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}} Al repetir actualizar la fecha seleccionada para repetir la fecha"
|
||||||
AdvSceneSwitcher.condition.sceneTransform="Transformar elemento de escena"
|
AdvSceneSwitcher.condition.sceneTransform="Transformar elemento de escena"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtener transformación"
|
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtener transformación"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.condition.match="coincide con la transformación"
|
AdvSceneSwitcher.condition.sceneTransform.condition.match="coincide con la transformación"
|
||||||
@@ -350,7 +351,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.show="Mostrar"
|
|||||||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
|
AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Fuente"
|
AdvSceneSwitcher.action.sceneVisibility.type.source="Fuente"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Cualquiera"
|
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Cualquiera"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.entry="En{{scenes}}{{actions}}{{sources}}"
|
AdvSceneSwitcher.action.sceneVisibility.layout="En{{scenes}}{{actions}}{{sources}}"
|
||||||
AdvSceneSwitcher.action.filter="Filtro"
|
AdvSceneSwitcher.action.filter="Filtro"
|
||||||
AdvSceneSwitcher.action.filter.type.enable="Habilitar"
|
AdvSceneSwitcher.action.filter.type.enable="Habilitar"
|
||||||
AdvSceneSwitcher.action.filter.type.disable="Deshabilitar"
|
AdvSceneSwitcher.action.filter.type.disable="Deshabilitar"
|
||||||
|
|||||||
@@ -356,14 +356,14 @@ AdvSceneSwitcher.condition.replay.state.stopped="Tampon de répétition arrêté
|
|||||||
AdvSceneSwitcher.condition.replay.state.started="Tampon de répétition démarré"
|
AdvSceneSwitcher.condition.replay.state.started="Tampon de répétition démarré"
|
||||||
AdvSceneSwitcher.condition.replay.state.saved="Tampon de répétition enregistré"
|
AdvSceneSwitcher.condition.replay.state.saved="Tampon de répétition enregistré"
|
||||||
AdvSceneSwitcher.condition.date="Date"
|
AdvSceneSwitcher.condition.date="Date"
|
||||||
AdvSceneSwitcher.condition.date.anyDay="N'importe quel jour"
|
AdvSceneSwitcher.day.any="N'importe quel jour"
|
||||||
AdvSceneSwitcher.condition.date.monday="Lundi"
|
AdvSceneSwitcher.day.monday="Lundi"
|
||||||
AdvSceneSwitcher.condition.date.tuesday="Mardi"
|
AdvSceneSwitcher.day.tuesday="Mardi"
|
||||||
AdvSceneSwitcher.condition.date.wednesday="Mercredi"
|
AdvSceneSwitcher.day.wednesday="Mercredi"
|
||||||
AdvSceneSwitcher.condition.date.thursday="Jeudi"
|
AdvSceneSwitcher.day.thursday="Jeudi"
|
||||||
AdvSceneSwitcher.condition.date.friday="Vendredi"
|
AdvSceneSwitcher.day.friday="Vendredi"
|
||||||
AdvSceneSwitcher.condition.date.saturday="Samedi"
|
AdvSceneSwitcher.day.saturday="Samedi"
|
||||||
AdvSceneSwitcher.condition.date.sunday="Dimanche"
|
AdvSceneSwitcher.day.sunday="Dimanche"
|
||||||
AdvSceneSwitcher.condition.date.state.at="À"
|
AdvSceneSwitcher.condition.date.state.at="À"
|
||||||
AdvSceneSwitcher.condition.date.state.after="Après"
|
AdvSceneSwitcher.condition.date.state.after="Après"
|
||||||
AdvSceneSwitcher.condition.date.state.before="Avant"
|
AdvSceneSwitcher.condition.date.state.before="Avant"
|
||||||
@@ -374,11 +374,12 @@ AdvSceneSwitcher.condition.date.ignoreDate="Si non cochée, la composante date s
|
|||||||
AdvSceneSwitcher.condition.date.ignoreTime="Si non cochée, la composante heure sera ignorée"
|
AdvSceneSwitcher.condition.date.ignoreTime="Si non cochée, la composante heure sera ignorée"
|
||||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="Afficher les paramètres avancés"
|
AdvSceneSwitcher.condition.date.showAdvancedSettings="Afficher les paramètres avancés"
|
||||||
AdvSceneSwitcher.condition.date.showSimpleSettings="Afficher les paramètres simples"
|
AdvSceneSwitcher.condition.date.showSimpleSettings="Afficher les paramètres simples"
|
||||||
AdvSceneSwitcher.condition.date.entry.simple="Le{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
|
AdvSceneSwitcher.condition.date.layout.simple.day="Le{{dayOfWeek}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}}Répéter toutes les{{duration}}lorsque la date correspond"
|
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.pattern="La date actuelle \"{{currentDate}}\" correspond au motif{{pattern}}"
|
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}}Répéter toutes les{{duration}}lorsque la date correspond"
|
||||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Prochaine correspondance à : %1"
|
AdvSceneSwitcher.condition.date.layout.pattern="La date actuelle \"{{currentDate}}\" correspond au motif{{pattern}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}}À la répétition, mettre à jour la date sélectionnée pour la date de répétition"
|
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Prochaine correspondance à : %1"
|
||||||
|
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}}À la répétition, mettre à jour la date sélectionnée pour la date de répétition"
|
||||||
AdvSceneSwitcher.condition.sceneTransform="Transformation de l'élément de la scène"
|
AdvSceneSwitcher.condition.sceneTransform="Transformation de l'élément de la scène"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtenir la transformation"
|
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obtenir la transformation"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.condition.match="correspond à la transformation"
|
AdvSceneSwitcher.condition.sceneTransform.condition.match="correspond à la transformation"
|
||||||
@@ -510,7 +511,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Masquer"
|
|||||||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Basculer"
|
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Basculer"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
|
AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="N'importe"
|
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="N'importe"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.entry="Sur{{scenes}}{{actions}}{{sources}}"
|
AdvSceneSwitcher.action.sceneVisibility.layout="Sur{{scenes}}{{actions}}{{sources}}"
|
||||||
AdvSceneSwitcher.action.filter="Filtre"
|
AdvSceneSwitcher.action.filter="Filtre"
|
||||||
AdvSceneSwitcher.action.filter.type.enable="Activer"
|
AdvSceneSwitcher.action.filter.type.enable="Activer"
|
||||||
AdvSceneSwitcher.action.filter.type.disable="Désactiver"
|
AdvSceneSwitcher.action.filter.type.disable="Désactiver"
|
||||||
@@ -701,8 +702,8 @@ AdvSceneSwitcher.action.variable.invalidSelection="Sélection invalide !"
|
|||||||
AdvSceneSwitcher.action.variable.actionNoVariableSupport="La récupération de valeurs de variables à partir d'actions %1 n'est pas prise en charge !"
|
AdvSceneSwitcher.action.variable.actionNoVariableSupport="La récupération de valeurs de variables à partir d'actions %1 n'est pas prise en charge !"
|
||||||
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="La récupération de valeurs de variables à partir de conditions %1 n'est pas prise en charge !"
|
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="La récupération de valeurs de variables à partir de conditions %1 n'est pas prise en charge !"
|
||||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Valeur actuelle :"
|
AdvSceneSwitcher.action.variable.currentSegmentValue="Valeur actuelle :"
|
||||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}"
|
AdvSceneSwitcher.action.variable.layout.substringIndex="Début de la sous-chaîne :{{subStringStart}}Taille de la sous-chaîne :{{subStringSize}}{{subStringRegex}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière :"
|
AdvSceneSwitcher.action.variable.layout.substringRegex="Attribuer la valeur du match{{regexMatchIdx}}en utilisant une expression régulière:{{subStringRegex}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Utiliser un message personnalisé{{inputPrompt}}"
|
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Utiliser un message personnalisé{{inputPrompt}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Remplir avec un indicateur de position{{inputPlaceholder}}"
|
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Remplir avec un indicateur de position{{inputPlaceholder}}"
|
||||||
AdvSceneSwitcher.action.projector="Projecteur"
|
AdvSceneSwitcher.action.projector="Projecteur"
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailure="プラグイ
|
|||||||
AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailureMessage="<html><body>次のプラグイン ライブラリの読み込みに失敗したため、一部の高機能シーンスイッチャーが利用できなくなる可能性があります:%1詳細については、OBS ログを確認してください。<br>このメッセージは、[全般] タブで無効にすることができます。 </body></html>"
|
AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailureMessage="<html><body>次のプラグイン ライブラリの読み込みに失敗したため、一部の高機能シーンスイッチャーが利用できなくなる可能性があります:%1詳細については、OBS ログを確認してください。<br>このメッセージは、[全般] タブで無効にすることができます。 </body></html>"
|
||||||
AdvSceneSwitcher.generalTab.generalBehavior.warnCorruptedInstallMessage="プラグインが正しくインストールできておらずクラッシュする可能性があります!\nプラグインが正しくインストールされているか確認してください!"
|
AdvSceneSwitcher.generalTab.generalBehavior.warnCorruptedInstallMessage="プラグインが正しくインストールできておらずクラッシュする可能性があります!\nプラグインが正しくインストールされているか確認してください!"
|
||||||
AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs="旧来型マクロ設定のタブを非表示にする(廃止予定タブ)"
|
AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs="旧来型マクロ設定のタブを非表示にする(廃止予定タブ)"
|
||||||
AdvSceneSwitcher.generalTab.generalBehavior.disableMacroWidgetCache="マクロウィジェットのキャッシングを無効にする"
|
|
||||||
AdvSceneSwitcher.generalTab.matchBehavior="マッチした場合の動作(廃止予定の設定項目)"
|
AdvSceneSwitcher.generalTab.matchBehavior="マッチした場合の動作(廃止予定の設定項目)"
|
||||||
AdvSceneSwitcher.generalTab.priority="優先順位"
|
AdvSceneSwitcher.generalTab.priority="優先順位"
|
||||||
AdvSceneSwitcher.generalTab.priority.description="切り替え方法の優先順位(優先順位が高いものが上)"
|
AdvSceneSwitcher.generalTab.priority.description="切り替え方法の優先順位(優先順位が高いものが上)"
|
||||||
@@ -556,14 +555,14 @@ AdvSceneSwitcher.condition.replay.state.started="リプレイバッファを開
|
|||||||
AdvSceneSwitcher.condition.replay.state.saved="リプレイバッファを保存"
|
AdvSceneSwitcher.condition.replay.state.saved="リプレイバッファを保存"
|
||||||
; AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
; AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
||||||
AdvSceneSwitcher.condition.date="日付条件"
|
AdvSceneSwitcher.condition.date="日付条件"
|
||||||
AdvSceneSwitcher.condition.date.anyDay="いつでも"
|
AdvSceneSwitcher.day.any="いつでも"
|
||||||
AdvSceneSwitcher.condition.date.monday="月曜日"
|
AdvSceneSwitcher.day.monday="月曜日"
|
||||||
AdvSceneSwitcher.condition.date.tuesday="火曜日"
|
AdvSceneSwitcher.day.tuesday="火曜日"
|
||||||
AdvSceneSwitcher.condition.date.wednesday="水曜日"
|
AdvSceneSwitcher.day.wednesday="水曜日"
|
||||||
AdvSceneSwitcher.condition.date.thursday="木曜日"
|
AdvSceneSwitcher.day.thursday="木曜日"
|
||||||
AdvSceneSwitcher.condition.date.friday="金曜日"
|
AdvSceneSwitcher.day.friday="金曜日"
|
||||||
AdvSceneSwitcher.condition.date.saturday="土曜日"
|
AdvSceneSwitcher.day.saturday="土曜日"
|
||||||
AdvSceneSwitcher.condition.date.sunday="日曜日"
|
AdvSceneSwitcher.day.sunday="日曜日"
|
||||||
; AdvSceneSwitcher.condition.date.state.at="At"
|
; AdvSceneSwitcher.condition.date.state.at="At"
|
||||||
AdvSceneSwitcher.condition.date.state.after="アフター"
|
AdvSceneSwitcher.condition.date.state.after="アフター"
|
||||||
AdvSceneSwitcher.condition.date.state.before="前"
|
AdvSceneSwitcher.condition.date.state.before="前"
|
||||||
@@ -574,12 +573,9 @@ AdvSceneSwitcher.condition.date.ignoreDate="チェックを外すと日付部分
|
|||||||
AdvSceneSwitcher.condition.date.ignoreTime="チェックを外すと時間要素は無視されます"
|
AdvSceneSwitcher.condition.date.ignoreTime="チェックを外すと時間要素は無視されます"
|
||||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="詳細設定を表示"
|
AdvSceneSwitcher.condition.date.showAdvancedSettings="詳細設定を表示"
|
||||||
AdvSceneSwitcher.condition.date.showSimpleSettings="簡単設定を表示"
|
AdvSceneSwitcher.condition.date.showSimpleSettings="簡単設定を表示"
|
||||||
; AdvSceneSwitcher.condition.date.entry.simple="On{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
|
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}}日付の一致ごとに{{duration}}繰り返します"
|
||||||
; AdvSceneSwitcher.condition.date.entry.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
|
AdvSceneSwitcher.condition.date.layout.pattern="現在の日付「{{currentDate}}」はパターン{{pattern}}と一致します"
|
||||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}}日付の一致ごとに{{duration}}繰り返します"
|
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}}繰り返しの場合、選択した日付を繰り返しの日付に更新します"
|
||||||
AdvSceneSwitcher.condition.date.entry.pattern="現在の日付「{{currentDate}}」はパターン{{pattern}}と一致します"
|
|
||||||
; AdvSceneSwitcher.condition.date.entry.nextMatchDate="Next match at: %1"
|
|
||||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}}繰り返しの場合、選択した日付を繰り返しの日付に更新します"
|
|
||||||
; AdvSceneSwitcher.condition.sceneTransform="Scene item transform"
|
; AdvSceneSwitcher.condition.sceneTransform="Scene item transform"
|
||||||
; AdvSceneSwitcher.condition.sceneTransform.getTransform="Get transform"
|
; AdvSceneSwitcher.condition.sceneTransform.getTransform="Get transform"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="現在の値を取得"
|
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="現在の値を取得"
|
||||||
@@ -871,7 +867,6 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="非表示"
|
|||||||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="切り替え"
|
AdvSceneSwitcher.action.sceneVisibility.type.toggle="切り替え"
|
||||||
; AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
|
; AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
|
||||||
; AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Any"
|
; AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Any"
|
||||||
; AdvSceneSwitcher.action.sceneVisibility.entry="On{{scenes}}{{actions}}{{sources}}"
|
|
||||||
AdvSceneSwitcher.action.filter="フィルタ"
|
AdvSceneSwitcher.action.filter="フィルタ"
|
||||||
AdvSceneSwitcher.action.filter.type.enable="有効にする"
|
AdvSceneSwitcher.action.filter.type.enable="有効にする"
|
||||||
AdvSceneSwitcher.action.filter.type.disable="無効化"
|
AdvSceneSwitcher.action.filter.type.disable="無効化"
|
||||||
@@ -1150,8 +1145,8 @@ AdvSceneSwitcher.action.variable.currentSegmentValue="現在値:"
|
|||||||
; AdvSceneSwitcher.action.variable.layout.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}"
|
; AdvSceneSwitcher.action.variable.layout.other="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}{{envVariableName}}{{scenes}}{{tempVars}}{{tempVarsHelp}}{{sceneItemIndex}}{{direction}}{{stringLength}}{{paddingCharSelection}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}の{{variables}}の長さを{{stringLength}}にするには、{{paddingCharSelection}}を{{direction}}に追加します。"
|
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}の{{variables}}の長さを{{stringLength}}にするには、{{paddingCharSelection}}を{{direction}}に追加します。"
|
||||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}の{{variables}}の長さを{{stringLength}}にするには、{{direction}}から文字を削除します。"
|
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}の{{variables}}の長さを{{stringLength}}にするには、{{direction}}から文字を削除します。"
|
||||||
AdvSceneSwitcher.action.variable.layout.substringIndex="部分文字列の開始:{{subStringStart}}部分文字列のサイズ:{{subStringSize}}"
|
AdvSceneSwitcher.action.variable.layout.substringIndex="部分文字列の開始:{{subStringStart}}部分文字列のサイズ:{{subStringSize}}{{subStringRegex}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.substringRegex="正規表現を使用して{{regexMatchIdx}}一致の値を割り当てます:"
|
AdvSceneSwitcher.action.variable.layout.substringRegex="正規表現を使用して{{regexMatchIdx}}一致の値を割り当てます:{{subStringRegex}}"
|
||||||
; AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
; AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}カスタム プロンプトを使用する{{inputPrompt}}"
|
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}カスタム プロンプトを使用する{{inputPrompt}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}プレースホルダーを入力{{inputPlaceholder}}"
|
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}プレースホルダーを入力{{inputPlaceholder}}"
|
||||||
@@ -1194,10 +1189,10 @@ AdvSceneSwitcher.action.twitch.type.user.getInfo="ユーザー情報を取得"
|
|||||||
AdvSceneSwitcher.action.twitch.type.reward.getInfo="チャンネルポイントリワード情報を取得"
|
AdvSceneSwitcher.action.twitch.type.reward.getInfo="チャンネルポイントリワード情報を取得"
|
||||||
AdvSceneSwitcher.action.twitch.reward.toggleControl="リワード名/変数選択コントロールの切り替え"
|
AdvSceneSwitcher.action.twitch.reward.toggleControl="リワード名/変数選択コントロールの切り替え"
|
||||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Twitchアカウントを選択しないとカテゴリを選択できません!"
|
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Twitchアカウントを選択しないとカテゴリを選択できません!"
|
||||||
; AdvSceneSwitcher.action.twitch.entry.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
|
; AdvSceneSwitcher.action.twitch.layout.default="On{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}"
|
||||||
AdvSceneSwitcher.action.twitch.entry.chat="{{channel}}でアカウント{{account}}{{actions}}を使用しています"
|
AdvSceneSwitcher.action.twitch.layout.chat="{{channel}}でアカウント{{account}}{{actions}}を使用しています"
|
||||||
AdvSceneSwitcher.action.twitch.entry.user.getInfo="{{userInfoQueryType}}{{userLogin}}{{userId}}でアカウント{{account}}{{actions}}を使用"
|
AdvSceneSwitcher.action.twitch.layout.user.getInfo="{{userInfoQueryType}}{{userLogin}}{{userId}}でアカウント{{account}}{{actions}}を使用"
|
||||||
AdvSceneSwitcher.action.twitch.entry.reward.getInfo="チャンネル{{channel}}{{pointsReward}}{{rewardVariable}}{{toggleRewardSelection}}でアカウント{{account}}{{actions}}を使用"
|
AdvSceneSwitcher.action.twitch.layout.reward.getInfo="チャンネル{{channel}}{{pointsReward}}{{rewardVariable}}{{toggleRewardSelection}}でアカウント{{account}}{{actions}}を使用"
|
||||||
AdvSceneSwitcher.action.twitch.title.title="タイトルを入力"
|
AdvSceneSwitcher.action.twitch.title.title="タイトルを入力"
|
||||||
AdvSceneSwitcher.action.twitch.marker.description="マーカーの説明"
|
AdvSceneSwitcher.action.twitch.marker.description="マーカーの説明"
|
||||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="クリップをキャプチャする前にわずかな遅延を追加します"
|
AdvSceneSwitcher.action.twitch.clip.hasDelay="クリップをキャプチャする前にわずかな遅延を追加します"
|
||||||
|
|||||||
@@ -502,14 +502,14 @@ AdvSceneSwitcher.condition.replay.state.started="Buffer de replay iniciado"
|
|||||||
AdvSceneSwitcher.condition.replay.state.saved="Buffer de replay salvo"
|
AdvSceneSwitcher.condition.replay.state.saved="Buffer de replay salvo"
|
||||||
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
||||||
AdvSceneSwitcher.condition.date="Data"
|
AdvSceneSwitcher.condition.date="Data"
|
||||||
AdvSceneSwitcher.condition.date.anyDay="Qualquer dia"
|
AdvSceneSwitcher.day.any="Qualquer dia"
|
||||||
AdvSceneSwitcher.condition.date.monday="Segunda-feira"
|
AdvSceneSwitcher.day.monday="Segunda-feira"
|
||||||
AdvSceneSwitcher.condition.date.tuesday="Terça-feira"
|
AdvSceneSwitcher.day.tuesday="Terça-feira"
|
||||||
AdvSceneSwitcher.condition.date.wednesday="Quarta-feira"
|
AdvSceneSwitcher.day.wednesday="Quarta-feira"
|
||||||
AdvSceneSwitcher.condition.date.thursday="Quinta-feira"
|
AdvSceneSwitcher.day.thursday="Quinta-feira"
|
||||||
AdvSceneSwitcher.condition.date.friday="Sexta-feira"
|
AdvSceneSwitcher.day.friday="Sexta-feira"
|
||||||
AdvSceneSwitcher.condition.date.saturday="Sábado"
|
AdvSceneSwitcher.day.saturday="Sábado"
|
||||||
AdvSceneSwitcher.condition.date.sunday="Domingo"
|
AdvSceneSwitcher.day.sunday="Domingo"
|
||||||
AdvSceneSwitcher.condition.date.state.at="Às"
|
AdvSceneSwitcher.condition.date.state.at="Às"
|
||||||
AdvSceneSwitcher.condition.date.state.after="Após"
|
AdvSceneSwitcher.condition.date.state.after="Após"
|
||||||
AdvSceneSwitcher.condition.date.state.before="Antes"
|
AdvSceneSwitcher.condition.date.state.before="Antes"
|
||||||
@@ -520,12 +520,13 @@ AdvSceneSwitcher.condition.date.ignoreDate="Se desmarcado, o componente de data
|
|||||||
AdvSceneSwitcher.condition.date.ignoreTime="Se desmarcado, o componente de tempo será ignorado"
|
AdvSceneSwitcher.condition.date.ignoreTime="Se desmarcado, o componente de tempo será ignorado"
|
||||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="Mostrar configurações avançadas"
|
AdvSceneSwitcher.condition.date.showAdvancedSettings="Mostrar configurações avançadas"
|
||||||
AdvSceneSwitcher.condition.date.showSimpleSettings="Mostrar configurações simples"
|
AdvSceneSwitcher.condition.date.showSimpleSettings="Mostrar configurações simples"
|
||||||
AdvSceneSwitcher.condition.date.entry.simple="Em{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
|
AdvSceneSwitcher.condition.date.layout.simple.day="Em{{dayOfWeek}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
|
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}}Repetir a cada{{duration}}em correspondência de data"
|
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.pattern="Data atual \"{{currentDate}}\" corresponde ao padrão{{pattern}}"
|
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}}Repetir a cada{{duration}}em correspondência de data"
|
||||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Próxima correspondência em: %1"
|
AdvSceneSwitcher.condition.date.layout.pattern="Data atual \"{{currentDate}}\" corresponde ao padrão{{pattern}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}}Ao repetir, atualize a data selecionada para a data de repetição"
|
AdvSceneSwitcher.condition.date.layout.nextMatchDate="Próxima correspondência em: %1"
|
||||||
|
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}}Ao repetir, atualize a data selecionada para a data de repetição"
|
||||||
AdvSceneSwitcher.condition.sceneTransform="Transformação do item de cena"
|
AdvSceneSwitcher.condition.sceneTransform="Transformação do item de cena"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obter transformação"
|
AdvSceneSwitcher.condition.sceneTransform.getTransform="Obter transformação"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="Obter valor atual"
|
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="Obter valor atual"
|
||||||
@@ -781,7 +782,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
|
|||||||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Alternar"
|
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Alternar"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Fonte"
|
AdvSceneSwitcher.action.sceneVisibility.type.source="Fonte"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Qualquer"
|
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Qualquer"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.entry="Em{{scenes}}{{actions}}{{sources}}"
|
AdvSceneSwitcher.action.sceneVisibility.layout="Em{{scenes}}{{actions}}{{sources}}"
|
||||||
AdvSceneSwitcher.action.filter="Filtro"
|
AdvSceneSwitcher.action.filter="Filtro"
|
||||||
AdvSceneSwitcher.action.filter.type.enable="Habilitar"
|
AdvSceneSwitcher.action.filter.type.enable="Habilitar"
|
||||||
AdvSceneSwitcher.action.filter.type.disable="Desabilitar"
|
AdvSceneSwitcher.action.filter.type.disable="Desabilitar"
|
||||||
@@ -861,9 +862,9 @@ AdvSceneSwitcher.action.macro.type.stop="Parar ações"
|
|||||||
AdvSceneSwitcher.action.macro.type.disableAction="Desabilitar ação"
|
AdvSceneSwitcher.action.macro.type.disableAction="Desabilitar ação"
|
||||||
AdvSceneSwitcher.action.macro.type.enableAction="Habilitar ação"
|
AdvSceneSwitcher.action.macro.type.enableAction="Habilitar ação"
|
||||||
AdvSceneSwitcher.action.macro.type.toggleAction="Alternar ação"
|
AdvSceneSwitcher.action.macro.type.toggleAction="Alternar ação"
|
||||||
AdvSceneSwitcher.action.macro.entry.run="{{actions}}{{actionTypes}}de{{macros}}"
|
AdvSceneSwitcher.action.macro.layout.run="{{actions}}{{actionSections}}de{{macros}}"
|
||||||
AdvSceneSwitcher.action.macro.entry.run.condition="{{conditionBehaviors}}de{{conditionMacros}}"
|
AdvSceneSwitcher.action.macro.layout.run.condition="{{conditionBehaviors}}de{{conditionMacros}}"
|
||||||
AdvSceneSwitcher.action.macro.entry.other="{{actions}}{{actionIndex}}{{macros}}"
|
AdvSceneSwitcher.action.macro.layout.other="{{actions}}{{macros}}"
|
||||||
AdvSceneSwitcher.action.pluginState="Estado do plugin"
|
AdvSceneSwitcher.action.pluginState="Estado do plugin"
|
||||||
AdvSceneSwitcher.action.pluginState.type.stop="Parar o plugin Advanced Scene Switcher"
|
AdvSceneSwitcher.action.pluginState.type.stop="Parar o plugin Advanced Scene Switcher"
|
||||||
AdvSceneSwitcher.action.pluginState.type.noMatch="Alterar o comportamento em caso de não correspondência:"
|
AdvSceneSwitcher.action.pluginState.type.noMatch="Alterar o comportamento em caso de não correspondência:"
|
||||||
@@ -1030,8 +1031,8 @@ AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Obter valores de va
|
|||||||
AdvSceneSwitcher.action.variable.currentSegmentValue="Valor atual:"
|
AdvSceneSwitcher.action.variable.currentSegmentValue="Valor atual:"
|
||||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}de{{variables}}para comprimento{{stringLength}}adicionando{{paddingCharSelection}}ao{{direction}}"
|
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}de{{variables}}para comprimento{{stringLength}}adicionando{{paddingCharSelection}}ao{{direction}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}de{{variables}}para comprimento{{stringLength}}removendo caracteres da{{direction}}"
|
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}de{{variables}}para comprimento{{stringLength}}removendo caracteres da{{direction}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.substringIndex="Início da substring:{{subStringStart}}Tamanho da substring:{{subStringSize}}"
|
AdvSceneSwitcher.action.variable.layout.substringIndex="Início da substring:{{subStringStart}}Tamanho da substring:{{subStringSize}}{{subStringRegex}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:"
|
AdvSceneSwitcher.action.variable.layout.substringRegex="Atribuir valor do{{regexMatchIdx}}correspondência usando expressão regular:{{subStringRegex}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Usar prompt personalizado{{inputPrompt}}"
|
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}Usar prompt personalizado{{inputPrompt}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Preencher com placeholder{{inputPlaceholder}}"
|
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}Preencher com placeholder{{inputPlaceholder}}"
|
||||||
@@ -1065,8 +1066,8 @@ AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.enable="Habilitar modo apenas
|
|||||||
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Desabilitar modo apenas emotes no chat"
|
AdvSceneSwitcher.action.twitch.type.chat.emoteOnly.disable="Desabilitar modo apenas emotes no chat"
|
||||||
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Enviar mensagem de chat"
|
AdvSceneSwitcher.action.twitch.type.chat.sendMessage="Enviar mensagem de chat"
|
||||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Não é possível selecionar categoria sem selecionar uma conta Twitch primeiro!"
|
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="Não é possível selecionar categoria sem selecionar uma conta Twitch primeiro!"
|
||||||
AdvSceneSwitcher.action.twitch.entry.default="Em{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
AdvSceneSwitcher.action.twitch.layout.default="Em{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
||||||
AdvSceneSwitcher.action.twitch.entry.chat="Usando conta{{account}}{{actions}}em{{channel}}"
|
AdvSceneSwitcher.action.twitch.layout.chat="Usando conta{{account}}{{actions}}em{{channel}}"
|
||||||
AdvSceneSwitcher.action.twitch.title.title="Digite o título"
|
AdvSceneSwitcher.action.twitch.title.title="Digite o título"
|
||||||
AdvSceneSwitcher.action.twitch.marker.description="Descreva o marcador"
|
AdvSceneSwitcher.action.twitch.marker.description="Descreva o marcador"
|
||||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="Adicionar um leve atraso antes de capturar o clipe"
|
AdvSceneSwitcher.action.twitch.clip.hasDelay="Adicionar um leve atraso antes de capturar o clipe"
|
||||||
|
|||||||
@@ -281,7 +281,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.show="Göster"
|
|||||||
AdvSceneSwitcher.action.sceneVisibility.type.hide="Gizle"
|
AdvSceneSwitcher.action.sceneVisibility.type.hide="Gizle"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.source="Kayıt"
|
AdvSceneSwitcher.action.sceneVisibility.type.source="Kayıt"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Herhangi"
|
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Herhangi"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.entry="Açık{{scenes}}{{actions}}{{sources}}"
|
AdvSceneSwitcher.action.sceneVisibility.layout="Açık{{scenes}}{{actions}}{{sources}}"
|
||||||
AdvSceneSwitcher.action.filter="Filtrele"
|
AdvSceneSwitcher.action.filter="Filtrele"
|
||||||
AdvSceneSwitcher.action.filter.type.enable="Etkin"
|
AdvSceneSwitcher.action.filter.type.enable="Etkin"
|
||||||
AdvSceneSwitcher.action.filter.type.disable="Etkisiz"
|
AdvSceneSwitcher.action.filter.type.disable="Etkisiz"
|
||||||
|
|||||||
@@ -530,14 +530,14 @@ AdvSceneSwitcher.condition.replay.state.started="回放缓存已启动"
|
|||||||
AdvSceneSwitcher.condition.replay.state.saved="已保存回放缓存"
|
AdvSceneSwitcher.condition.replay.state.saved="已保存回放缓存"
|
||||||
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
AdvSceneSwitcher.condition.replay.entry="{{state}}"
|
||||||
AdvSceneSwitcher.condition.date="日期"
|
AdvSceneSwitcher.condition.date="日期"
|
||||||
AdvSceneSwitcher.condition.date.anyDay="每一天"
|
AdvSceneSwitcher.day.any="每一天"
|
||||||
AdvSceneSwitcher.condition.date.monday="周一"
|
AdvSceneSwitcher.day.monday="周一"
|
||||||
AdvSceneSwitcher.condition.date.tuesday="周二"
|
AdvSceneSwitcher.day.tuesday="周二"
|
||||||
AdvSceneSwitcher.condition.date.wednesday="周三"
|
AdvSceneSwitcher.day.wednesday="周三"
|
||||||
AdvSceneSwitcher.condition.date.thursday="周四"
|
AdvSceneSwitcher.day.thursday="周四"
|
||||||
AdvSceneSwitcher.condition.date.friday="周五"
|
AdvSceneSwitcher.day.friday="周五"
|
||||||
AdvSceneSwitcher.condition.date.saturday="周六"
|
AdvSceneSwitcher.day.saturday="周六"
|
||||||
AdvSceneSwitcher.condition.date.sunday="周日"
|
AdvSceneSwitcher.day.sunday="周日"
|
||||||
AdvSceneSwitcher.condition.date.state.at="现在"
|
AdvSceneSwitcher.condition.date.state.at="现在"
|
||||||
AdvSceneSwitcher.condition.date.state.after="之后"
|
AdvSceneSwitcher.condition.date.state.after="之后"
|
||||||
AdvSceneSwitcher.condition.date.state.before="之前"
|
AdvSceneSwitcher.condition.date.state.before="之前"
|
||||||
@@ -548,12 +548,13 @@ AdvSceneSwitcher.condition.date.ignoreDate="如果未选中,日期组件将被
|
|||||||
AdvSceneSwitcher.condition.date.ignoreTime="如果未选中,时间组件将被忽略"
|
AdvSceneSwitcher.condition.date.ignoreTime="如果未选中,时间组件将被忽略"
|
||||||
AdvSceneSwitcher.condition.date.showAdvancedSettings="显示高级设置"
|
AdvSceneSwitcher.condition.date.showAdvancedSettings="显示高级设置"
|
||||||
AdvSceneSwitcher.condition.date.showSimpleSettings="显示简单设置"
|
AdvSceneSwitcher.condition.date.showSimpleSettings="显示简单设置"
|
||||||
AdvSceneSwitcher.condition.date.entry.simple="{{dayOfWeek}}{{weekCondition}}{{ignoreWeekTime}}{{weekTime}}"
|
AdvSceneSwitcher.condition.date.layout.simple.day="{{dayOfWeek}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
|
AdvSceneSwitcher.condition.date.layout.simple.time="{{ignoreWeekTime}}{{weekCondition}}{{weekTime}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}} 每 {{duration}} 重复一次时间/日期匹配"
|
AdvSceneSwitcher.condition.date.layout.advanced="{{condition}}{{ignoreDate}}{{date}}{{ignoreTime}}{{time}}{{separator}}{{date2}}{{time2}}"
|
||||||
AdvSceneSwitcher.condition.date.entry.pattern="当前日期 \"{{currentDate}}\" 与 {{pattern}} 模式匹配 , 例子:2025 03 18 24 00 00 = .... .. .. .. .. .. ,难崩,我测试了一段时间才明白"
|
AdvSceneSwitcher.condition.date.layout.repeat="{{repeat}} 每 {{duration}} 重复一次时间/日期匹配"
|
||||||
AdvSceneSwitcher.condition.date.entry.nextMatchDate="下一次匹配 在: %1"
|
AdvSceneSwitcher.condition.date.layout.pattern="当前日期 \"{{currentDate}}\" 与 {{pattern}} 模式匹配 , 例子:2025 03 18 24 00 00 = .... .. .. .. .. .. ,难崩,我测试了一段时间才明白"
|
||||||
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} 在重复时将选定日期更新为重复日期"
|
AdvSceneSwitcher.condition.date.layout.nextMatchDate="下一次匹配 在: %1"
|
||||||
|
AdvSceneSwitcher.condition.date.layout.updateOnRepeat="{{updateOnRepeat}} 在重复时将选定日期更新为重复日期"
|
||||||
AdvSceneSwitcher.condition.sceneTransform="场景项目变换"
|
AdvSceneSwitcher.condition.sceneTransform="场景项目变换"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.getTransform="获取变换"
|
AdvSceneSwitcher.condition.sceneTransform.getTransform="获取变换"
|
||||||
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="获取当前值"
|
AdvSceneSwitcher.condition.sceneTransform.getCurrentValue="获取当前值"
|
||||||
@@ -840,7 +841,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="隐藏"
|
|||||||
AdvSceneSwitcher.action.sceneVisibility.type.toggle="切换可见性"
|
AdvSceneSwitcher.action.sceneVisibility.type.toggle="切换可见性"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.source="源"
|
AdvSceneSwitcher.action.sceneVisibility.type.source="源"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="任何"
|
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="任何"
|
||||||
AdvSceneSwitcher.action.sceneVisibility.entry="{{scenes}}{{actions}}{{sources}}"
|
AdvSceneSwitcher.action.sceneVisibility.layout="{{scenes}}{{actions}}{{sources}}"
|
||||||
AdvSceneSwitcher.action.filter="滤镜"
|
AdvSceneSwitcher.action.filter="滤镜"
|
||||||
AdvSceneSwitcher.action.filter.type.enable="开启"
|
AdvSceneSwitcher.action.filter.type.enable="开启"
|
||||||
AdvSceneSwitcher.action.filter.type.disable="关闭"
|
AdvSceneSwitcher.action.filter.type.disable="关闭"
|
||||||
@@ -920,9 +921,9 @@ AdvSceneSwitcher.action.macro.type.stop="停止操作"
|
|||||||
AdvSceneSwitcher.action.macro.type.disableAction="停用操作"
|
AdvSceneSwitcher.action.macro.type.disableAction="停用操作"
|
||||||
AdvSceneSwitcher.action.macro.type.enableAction="启用操作"
|
AdvSceneSwitcher.action.macro.type.enableAction="启用操作"
|
||||||
AdvSceneSwitcher.action.macro.type.toggleAction="切换操作开关"
|
AdvSceneSwitcher.action.macro.type.toggleAction="切换操作开关"
|
||||||
AdvSceneSwitcher.action.macro.entry.run="{{actions}}{{actionTypes}}{{macros}}"
|
AdvSceneSwitcher.action.macro.layout.run="{{actions}}{{actionSections}}{{macros}}"
|
||||||
AdvSceneSwitcher.action.macro.entry.run.condition="{{conditionBehaviors}}{{conditionMacros}}"
|
AdvSceneSwitcher.action.macro.layout.run.condition="{{conditionBehaviors}}{{conditionMacros}}"
|
||||||
AdvSceneSwitcher.action.macro.entry.other="{{actions}}{{actionIndex}}{{macros}}"
|
AdvSceneSwitcher.action.macro.layout.other="{{actions}}{{macros}}"
|
||||||
AdvSceneSwitcher.action.pluginState="插件状态"
|
AdvSceneSwitcher.action.pluginState="插件状态"
|
||||||
AdvSceneSwitcher.action.pluginState.type.stop="停止高级场景切换插件"
|
AdvSceneSwitcher.action.pluginState.type.stop="停止高级场景切换插件"
|
||||||
AdvSceneSwitcher.action.pluginState.type.noMatch="没有匹配项时:"
|
AdvSceneSwitcher.action.pluginState.type.noMatch="没有匹配项时:"
|
||||||
@@ -1100,8 +1101,8 @@ AdvSceneSwitcher.action.variable.conditionNoVariableSupport="不支持从 %1 条
|
|||||||
AdvSceneSwitcher.action.variable.currentSegmentValue="当前值:"
|
AdvSceneSwitcher.action.variable.currentSegmentValue="当前值:"
|
||||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}于{{variables}}的{{direction}}起,内容为{{paddingCharSelection}}将其变量值长度增加至{{stringLength}}."
|
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}于{{variables}}的{{direction}}起,内容为{{paddingCharSelection}}将其变量值长度增加至{{stringLength}}."
|
||||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}于{{variables}}的{{direction}}起,将变量长度缩减至{{stringLength}}"
|
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}于{{variables}}的{{direction}}起,将变量长度缩减至{{stringLength}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.substringIndex="截取字符串开始位置:{{subStringStart}} 截取字符串长度:{{subStringSize}}"
|
AdvSceneSwitcher.action.variable.layout.substringIndex="截取字符串开始位置:{{subStringStart}} 截取字符串长度:{{subStringSize}}{{subStringRegex}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
|
AdvSceneSwitcher.action.variable.layout.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:{{subStringRegex}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
AdvSceneSwitcher.action.variable.layout.findAndReplace="{{findStr}}{{findRegex}}{{replaceStr}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}使用自定义提示{{inputPrompt}}"
|
AdvSceneSwitcher.action.variable.layout.userInput.customPrompt="{{useCustomPrompt}}使用自定义提示{{inputPrompt}}"
|
||||||
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}用占位符填充{{inputPlaceholder}}"
|
AdvSceneSwitcher.action.variable.layout.userInput.placeholder="{{useInputPlaceholder}}用占位符填充{{inputPlaceholder}}"
|
||||||
@@ -1139,10 +1140,10 @@ AdvSceneSwitcher.action.twitch.type.user.getInfo="获取用户信息"
|
|||||||
AdvSceneSwitcher.action.twitch.type.reward.getInfo="获取频道积分奖励信息"
|
AdvSceneSwitcher.action.twitch.type.reward.getInfo="获取频道积分奖励信息"
|
||||||
AdvSceneSwitcher.action.twitch.reward.toggleControl="切换奖励名称/变量选择控制"
|
AdvSceneSwitcher.action.twitch.reward.toggleControl="切换奖励名称/变量选择控制"
|
||||||
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="在未选择 Twitch 帐户的情况下无法选择类别!"
|
AdvSceneSwitcher.action.twitch.categorySelectionDisabled="在未选择 Twitch 帐户的情况下无法选择类别!"
|
||||||
AdvSceneSwitcher.action.twitch.entry.default="{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
AdvSceneSwitcher.action.twitch.layout.default="{{account}}{{actions}}{{streamTitle}}{{category}}{{markerDescription}}{{clipHasDelay}}{{duration}}{{announcementColor}}{{channel}}{{pointsReward}}"
|
||||||
AdvSceneSwitcher.action.twitch.entry.chat="使用账户{{account}}{{actions}}{{channel}}"
|
AdvSceneSwitcher.action.twitch.layout.chat="使用账户{{account}}{{actions}}{{channel}}"
|
||||||
AdvSceneSwitcher.action.twitch.entry.user.getInfo="使用账户{{account}}{{actions}}{{userInfoQueryType}}{{userLogin}}{{userId}}"
|
AdvSceneSwitcher.action.twitch.layout.user.getInfo="使用账户{{account}}{{actions}}{{userInfoQueryType}}{{userLogin}}{{userId}}"
|
||||||
AdvSceneSwitcher.action.twitch.entry.reward.getInfo="使用账户{{account}}{{actions}} 频道{{channel}}{{pointsReward}}{{rewardVariable}}{{toggleRewardSelection}}"
|
AdvSceneSwitcher.action.twitch.layout.reward.getInfo="使用账户{{account}}{{actions}} 频道{{channel}}{{pointsReward}}{{rewardVariable}}{{toggleRewardSelection}}"
|
||||||
AdvSceneSwitcher.action.twitch.title.title="输入标题"
|
AdvSceneSwitcher.action.twitch.title.title="输入标题"
|
||||||
AdvSceneSwitcher.action.twitch.marker.description="标记描述"
|
AdvSceneSwitcher.action.twitch.marker.description="标记描述"
|
||||||
AdvSceneSwitcher.action.twitch.clip.hasDelay="在捕捉视频片段前稍加延迟"
|
AdvSceneSwitcher.action.twitch.clip.hasDelay="在捕捉视频片段前稍加延迟"
|
||||||
|
|||||||
@@ -68,365 +68,162 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>962</width>
|
<width>962</width>
|
||||||
<height>1057</height>
|
<height>1160</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_19">
|
<layout class="QVBoxLayout" name="verticalLayout_19">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_31">
|
<widget class="QGroupBox" name="statusBox">
|
||||||
<item>
|
<property name="title">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<string>AdvSceneSwitcher.generalTab.status</string>
|
||||||
<item>
|
</property>
|
||||||
<widget class="QGroupBox" name="statusBox">
|
<layout class="QGridLayout" name="gridLayout_4">
|
||||||
<property name="title">
|
<item row="0" column="0">
|
||||||
<string>AdvSceneSwitcher.generalTab.status</string>
|
<layout class="QGridLayout" name="statusLayout">
|
||||||
</property>
|
<item row="4" column="1">
|
||||||
<layout class="QGridLayout" name="gridLayout_4">
|
<widget class="QComboBox" name="autoStartEvent"/>
|
||||||
<item row="0" column="0">
|
</item>
|
||||||
<layout class="QGridLayout" name="statusLayout">
|
<item row="4" column="0">
|
||||||
<item row="4" column="1">
|
<widget class="QLabel" name="label_10">
|
||||||
<widget class="QComboBox" name="autoStartEvent"/>
|
<property name="text">
|
||||||
</item>
|
<string>AdvSceneSwitcher.generalTab.status.autoStart.startup</string>
|
||||||
<item row="4" column="0">
|
</property>
|
||||||
<widget class="QLabel" name="label_10">
|
</widget>
|
||||||
<property name="text">
|
</item>
|
||||||
<string>AdvSceneSwitcher.generalTab.status.autoStart.startup</string>
|
<item row="0" column="0">
|
||||||
</property>
|
<layout class="QVBoxLayout" name="verticalLayout_33">
|
||||||
</widget>
|
<item>
|
||||||
</item>
|
<widget class="QLabel" name="label_4">
|
||||||
<item row="0" column="0">
|
<property name="text">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_33">
|
<string>AdvSceneSwitcher.generalTab.status.checkInterval</string>
|
||||||
<item>
|
</property>
|
||||||
<widget class="QLabel" name="label_4">
|
</widget>
|
||||||
<property name="text">
|
</item>
|
||||||
<string>AdvSceneSwitcher.generalTab.status.checkInterval</string>
|
<item>
|
||||||
</property>
|
<widget class="QLabel" name="checkIntervalTooLowWarning">
|
||||||
</widget>
|
<property name="text">
|
||||||
</item>
|
<string/>
|
||||||
<item>
|
</property>
|
||||||
<widget class="QLabel" name="checkIntervalTooLowWarning">
|
</widget>
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
|
||||||
<widget class="QComboBox" name="startupBehavior"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QWidget" name="placeholder3" native="true"/>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QWidget" name="placeholder" native="true"/>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QLabel" name="label_64">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.status.onStartup</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="1">
|
|
||||||
<widget class="QWidget" name="placeholder2" native="true"/>
|
|
||||||
</item>
|
|
||||||
<item row="6" column="0">
|
|
||||||
<widget class="QLabel" name="label_13">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.status.hotkeytips</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QSpinBox" name="checkInterval">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>100</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="suffix">
|
|
||||||
<string notr="true">ms</string>
|
|
||||||
</property>
|
|
||||||
<property name="minimum">
|
|
||||||
<number>10</number>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<number>20000</number>
|
|
||||||
</property>
|
|
||||||
<property name="value">
|
|
||||||
<number>300</number>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="0">
|
|
||||||
<widget class="QCheckBox" name="autoStartSceneEnable">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.status.autoStart.scene</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="5" column="1">
|
|
||||||
<layout class="QHBoxLayout" name="autoStartSceneLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="advss::SceneSelectionWidget" name="autoStartScene" native="true"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="advss::VariableLineEdit" name="autoStartSceneName"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="advss::RegexConfigWidget" name="autoStartSceneNameRegex" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</item>
|
||||||
</item>
|
<item row="3" column="1">
|
||||||
<item>
|
<widget class="QComboBox" name="startupBehavior"/>
|
||||||
<widget class="QGroupBox" name="generalSettingsBox">
|
</item>
|
||||||
<property name="title">
|
<item row="1" column="1">
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior</string>
|
<widget class="QWidget" name="placeholder3" native="true"/>
|
||||||
</property>
|
</item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_32">
|
<item row="1" column="0">
|
||||||
|
<widget class="QWidget" name="placeholder" native="true"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_64">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.generalTab.status.onStartup</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QWidget" name="placeholder2" native="true"/>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0">
|
||||||
|
<widget class="QLabel" name="label_13">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.generalTab.status.hotkeytips</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QSpinBox" name="checkInterval">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string notr="true">ms</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>20000</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>300</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QCheckBox" name="autoStartSceneEnable">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.generalTab.status.autoStart.scene</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="autoStartSceneLayout">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_52">
|
<widget class="advss::SceneSelectionWidget" name="autoStartScene" native="true"/>
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label_21">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QComboBox" name="logLevel"/>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_49">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_50">
|
<widget class="advss::VariableLineEdit" name="autoStartSceneName"/>
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="saveWindowGeo">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_55">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<widget class="advss::RegexConfigWidget" name="autoStartSceneNameRegex" native="true"/>
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="showTrayNotifications">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_2">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_48">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="uiHintsDisable">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_52">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_11">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="disableComboBoxFilter">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.comboBoxFilterDisable</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_13">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="disableMacroWidgetCache">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.disableMacroWidgetCache</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_26">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="warnPluginLoadFailure">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailure</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_19">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_24">
|
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="hideLegacyTabs">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<spacer name="horizontalSpacer_16">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</item>
|
||||||
</item>
|
</layout>
|
||||||
<item>
|
</item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_18">
|
</layout>
|
||||||
<item>
|
</widget>
|
||||||
<widget class="QGroupBox" name="saveLoadBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.saveOrLoadsettings</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_17">
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="exportSettings">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.saveOrLoadsettings.export</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="importSettings">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.generalTab.saveOrLoadsettings.import</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox_6">
|
<widget class="QGroupBox" name="saveLoadBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>AdvSceneSwitcher.generalTab.matchBehavior</string>
|
<string>AdvSceneSwitcher.generalTab.saveOrLoadsettings</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_37">
|
<layout class="QVBoxLayout" name="verticalLayout_17">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="cooldownLayout">
|
<widget class="QPushButton" name="exportSettings">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.generalTab.saveOrLoadsettings.export</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="importSettings">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.generalTab.saveOrLoadsettings.import</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="generalSettingsBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>AdvSceneSwitcher.generalTab.generalBehavior</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_32">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_52">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="enableCooldown">
|
<widget class="QLabel" name="label_21">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.cooldown</string>
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="advss::DurationSelection" name="cooldownTime" native="true"/>
|
<widget class="QComboBox" name="logLevel"/>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_21">
|
<spacer name="horizontalSpacer_49">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
@@ -441,80 +238,72 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<widget class="QCheckBox" name="showTrayNotifications">
|
||||||
<item row="0" column="2">
|
<property name="text">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_43">
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications</string>
|
||||||
<item>
|
</property>
|
||||||
<widget class="QRadioButton" name="noMatchDontSwitch">
|
</widget>
|
||||||
<property name="text">
|
</item>
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.dontSwitch</string>
|
<item>
|
||||||
</property>
|
<widget class="QCheckBox" name="warnPluginLoadFailure">
|
||||||
<property name="checked">
|
<property name="text">
|
||||||
<bool>true</bool>
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailure</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</widget>
|
||||||
<item row="2" column="2">
|
</item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_45">
|
<item>
|
||||||
<item>
|
<widget class="QGroupBox" name="groupBox_6">
|
||||||
<widget class="QRadioButton" name="noMatchRandomSwitch">
|
<property name="title">
|
||||||
<property name="text">
|
<string>AdvSceneSwitcher.generalTab.uiBehavior</string>
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom</string>
|
</property>
|
||||||
</property>
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
</widget>
|
<item>
|
||||||
</item>
|
<widget class="QCheckBox" name="saveWindowGeo">
|
||||||
</layout>
|
<property name="text">
|
||||||
</item>
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo</string>
|
||||||
<item row="1" column="2">
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
</widget>
|
||||||
<property name="leftMargin">
|
</item>
|
||||||
<number>0</number>
|
<item>
|
||||||
</property>
|
<widget class="QCheckBox" name="alwaysShowMacroSearch">
|
||||||
<property name="topMargin">
|
<property name="text">
|
||||||
<number>0</number>
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.alwaysShowMacroSearch</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="rightMargin">
|
</widget>
|
||||||
<number>0</number>
|
</item>
|
||||||
</property>
|
<item>
|
||||||
<property name="bottomMargin">
|
<widget class="QCheckBox" name="alwaysShowFeatureTabs">
|
||||||
<number>0</number>
|
<property name="toolTip">
|
||||||
</property>
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.alwaysShowFeatureTabs.tooltip</string>
|
||||||
<item>
|
</property>
|
||||||
<widget class="QRadioButton" name="noMatchSwitch">
|
<property name="text">
|
||||||
<property name="text">
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.alwaysShowFeatureTabs</string>
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo</string>
|
</property>
|
||||||
</property>
|
</widget>
|
||||||
</widget>
|
</item>
|
||||||
</item>
|
<item>
|
||||||
<item>
|
<widget class="QCheckBox" name="disableComboBoxFilter">
|
||||||
<widget class="advss::SceneSelectionWidget" name="noMatchSwitchScene">
|
<property name="text">
|
||||||
</widget>
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.comboBoxFilterDisable</string>
|
||||||
</item>
|
</property>
|
||||||
</layout>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item>
|
||||||
<layout class="QHBoxLayout" name="noMatchLayout">
|
<widget class="QCheckBox" name="uiHintsDisable">
|
||||||
<item>
|
<property name="text">
|
||||||
<widget class="QLabel" name="label_2">
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints</string>
|
||||||
<property name="sizePolicy">
|
</property>
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
</widget>
|
||||||
<horstretch>0</horstretch>
|
</item>
|
||||||
<verstretch>0</verstretch>
|
<item>
|
||||||
</sizepolicy>
|
<widget class="QCheckBox" name="hideLegacyTabs">
|
||||||
</property>
|
<property name="text">
|
||||||
<property name="text">
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs</string>
|
||||||
<string>AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch</string>
|
</property>
|
||||||
</property>
|
</widget>
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
@@ -562,6 +351,109 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="matchBehaviorBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>AdvSceneSwitcher.generalTab.matchBehavior</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_37">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="cooldownLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="enableCooldown">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.cooldown</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="advss::DurationSelection" name="cooldownTime" native="true"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_21">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QRadioButton" name="noMatchDontSwitch">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.dontSwitch</string>
|
||||||
|
</property>
|
||||||
|
<property name="checked">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QRadioButton" name="noMatchRandomSwitch">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchToRandom</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="noMatchSwitch">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch.switchTo</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="advss::SceneSelectionWidget" name="noMatchSwitchScene" native="true"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<layout class="QHBoxLayout" name="noMatchLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.generalTab.generalBehavior.onNoMatch</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="priorityBox">
|
<widget class="QGroupBox" name="priorityBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@@ -576,15 +468,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
<widget class="QListWidget" name="priorityList"/>
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_41">
|
|
||||||
<item>
|
|
||||||
<widget class="QListWidget" name="priorityList"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_32">
|
<layout class="QHBoxLayout" name="horizontalLayout_32">
|
||||||
@@ -721,6 +605,55 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="macroSearchLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="macroSearchText">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>AdvSceneSwitcher.macroTab.search.placeholder</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="macroSearchClear">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>AdvSceneSwitcher.variableTab.clear</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="macroSearchType"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="advss::RegexConfigWidget" name="macroSearchRegex" native="true"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="macroSearchShowSettings">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>AdvSceneSwitcher.macroTab.search.showSettings</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="advss::MacroTree" name="macros">
|
<widget class="advss::MacroTree" name="macros">
|
||||||
<property name="showDropIndicator" stdset="0">
|
<property name="showDropIndicator" stdset="0">
|
||||||
@@ -4164,12 +4097,7 @@
|
|||||||
<tabstop>autoStartSceneName</tabstop>
|
<tabstop>autoStartSceneName</tabstop>
|
||||||
<tabstop>autoStartSceneNameRegex</tabstop>
|
<tabstop>autoStartSceneNameRegex</tabstop>
|
||||||
<tabstop>logLevel</tabstop>
|
<tabstop>logLevel</tabstop>
|
||||||
<tabstop>saveWindowGeo</tabstop>
|
|
||||||
<tabstop>showTrayNotifications</tabstop>
|
|
||||||
<tabstop>uiHintsDisable</tabstop>
|
|
||||||
<tabstop>disableComboBoxFilter</tabstop>
|
|
||||||
<tabstop>warnPluginLoadFailure</tabstop>
|
<tabstop>warnPluginLoadFailure</tabstop>
|
||||||
<tabstop>hideLegacyTabs</tabstop>
|
|
||||||
<tabstop>exportSettings</tabstop>
|
<tabstop>exportSettings</tabstop>
|
||||||
<tabstop>importSettings</tabstop>
|
<tabstop>importSettings</tabstop>
|
||||||
<tabstop>noMatchDontSwitch</tabstop>
|
<tabstop>noMatchDontSwitch</tabstop>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "advanced-scene-switcher.hpp"
|
#include "advanced-scene-switcher.hpp"
|
||||||
#include "backup.hpp"
|
#include "backup.hpp"
|
||||||
|
#include "crash-handler.hpp"
|
||||||
#include "log-helper.hpp"
|
#include "log-helper.hpp"
|
||||||
#include "macro-helpers.hpp"
|
#include "macro-helpers.hpp"
|
||||||
#include "obs-module-helper.hpp"
|
#include "obs-module-helper.hpp"
|
||||||
@@ -191,25 +192,21 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||||||
|
|
||||||
switcher->m.lock();
|
switcher->m.lock();
|
||||||
if (switcher->VersionChanged(data, g_GIT_SHA1)) {
|
if (switcher->VersionChanged(data, g_GIT_SHA1)) {
|
||||||
auto json = obs_data_get_json(data);
|
AskForBackup(data);
|
||||||
static QString jsonQString = json ? json : "";
|
|
||||||
std::thread t([]() {
|
|
||||||
obs_queue_task(
|
|
||||||
OBS_TASK_UI,
|
|
||||||
[](void *) {
|
|
||||||
AskForBackup(jsonQString);
|
|
||||||
},
|
|
||||||
nullptr, false);
|
|
||||||
});
|
|
||||||
t.detach();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switcher->LoadSettings(data);
|
switcher->LoadSettings(data);
|
||||||
switcher->m.unlock();
|
switcher->m.unlock();
|
||||||
|
|
||||||
if (!switcher->stop) {
|
if (switcher->stop) {
|
||||||
switcher->Start();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ShouldSkipPluginStartOnUncleanShutdown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switcher->Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,7 +418,7 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
|
|||||||
|
|
||||||
static void ResetMacros()
|
static void ResetMacros()
|
||||||
{
|
{
|
||||||
for (auto &m : GetMacros()) {
|
for (auto &m : GetTopLevelMacros()) {
|
||||||
ResetMacroRunCount(m.get());
|
ResetMacroRunCount(m.get());
|
||||||
ResetMacroConditionTimers(m.get());
|
ResetMacroConditionTimers(m.get());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,6 @@ 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();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "filter-combo-box.hpp"
|
#include "filter-combo-box.hpp"
|
||||||
#include "layout-helpers.hpp"
|
#include "layout-helpers.hpp"
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
|
#include "macro-search.hpp"
|
||||||
#include "macro-settings.hpp"
|
#include "macro-settings.hpp"
|
||||||
#include "path-helpers.hpp"
|
#include "path-helpers.hpp"
|
||||||
#include "selection-helpers.hpp"
|
#include "selection-helpers.hpp"
|
||||||
@@ -185,16 +186,6 @@ 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) {
|
||||||
@@ -459,7 +450,7 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
|
|||||||
LoadHotkeys(obj);
|
LoadHotkeys(obj);
|
||||||
LoadUISettings(obj);
|
LoadUISettings(obj);
|
||||||
|
|
||||||
RunPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
|
|
||||||
// Reset on startup and scene collection change
|
// Reset on startup and scene collection change
|
||||||
ResetLastOpenedTab();
|
ResetLastOpenedTab();
|
||||||
@@ -531,8 +522,6 @@ 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);
|
||||||
|
|
||||||
@@ -602,8 +591,6 @@ 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);
|
||||||
@@ -927,9 +914,6 @@ 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);
|
||||||
|
|
||||||
@@ -1013,6 +997,19 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
|||||||
switcher->CheckAutoStart();
|
switcher->CheckAutoStart();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ui->alwaysShowMacroSearch->setChecked(
|
||||||
|
GetMacroSearchSettings().showAlways);
|
||||||
|
|
||||||
|
connect(ui->alwaysShowMacroSearch, &QCheckBox::stateChanged, this,
|
||||||
|
[this](int enabled) {
|
||||||
|
GetMacroSearchSettings().showAlways = enabled;
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CheckMacroSearchVisibility();
|
||||||
|
});
|
||||||
|
|
||||||
// Set up status control
|
// Set up status control
|
||||||
auto statusControl = new StatusControl(this, true);
|
auto statusControl = new StatusControl(this, true);
|
||||||
ui->statusLayout->addWidget(statusControl->StatusPrefixLabel(), 1, 0);
|
ui->statusLayout->addWidget(statusControl->StatusPrefixLabel(), 1, 0);
|
||||||
@@ -1032,6 +1029,8 @@ void AdvSceneSwitcher::SetupGeneralTab()
|
|||||||
setTabOrder(ui->importSettings, ui->cooldownTime);
|
setTabOrder(ui->importSettings, ui->cooldownTime);
|
||||||
setTabOrder(ui->cooldownTime, ui->noMatchDontSwitch);
|
setTabOrder(ui->cooldownTime, ui->noMatchDontSwitch);
|
||||||
|
|
||||||
|
SetupShowAllTabsCheckBox(ui->alwaysShowFeatureTabs, ui->tabWidget);
|
||||||
|
|
||||||
MinimizeSizeOfColumn(ui->statusLayout, 0);
|
MinimizeSizeOfColumn(ui->statusLayout, 0);
|
||||||
setWindowTitle(windowTitle() + " - " + g_GIT_TAG);
|
setWindowTitle(windowTitle() + " - " + g_GIT_TAG);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ static inline void populateActionSelection(QComboBox *list)
|
|||||||
}
|
}
|
||||||
|
|
||||||
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||||
std::shared_ptr<MacroAction> *entryData,
|
std::shared_ptr<MacroAction> *entryData)
|
||||||
const std::string &id)
|
|
||||||
: MacroSegmentEdit(parent),
|
: MacroSegmentEdit(parent),
|
||||||
_actionSelection(new FilterComboBox()),
|
_actionSelection(new FilterComboBox()),
|
||||||
_enable(new SwitchButton()),
|
_enable(new SwitchButton()),
|
||||||
@@ -117,7 +116,7 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
|||||||
*_entryData = MacroActionFactory::Create(id, macro);
|
*_entryData = MacroActionFactory::Create(id, macro);
|
||||||
(*_entryData)->SetIndex(idx);
|
(*_entryData)->SetIndex(idx);
|
||||||
(*_entryData)->PostLoad();
|
(*_entryData)->PostLoad();
|
||||||
RunPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
}
|
}
|
||||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||||
|
|||||||
@@ -13,10 +13,8 @@ class MacroActionEdit : public MacroSegmentEdit {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MacroActionEdit(
|
MacroActionEdit(QWidget *parent = nullptr,
|
||||||
QWidget *parent = nullptr,
|
std::shared_ptr<MacroAction> * = nullptr);
|
||||||
std::shared_ptr<MacroAction> * = nullptr,
|
|
||||||
const std::string &id = MacroAction::GetDefaultID().data());
|
|
||||||
void SetupWidgets(bool basicSetup = false);
|
void SetupWidgets(bool basicSetup = false);
|
||||||
void SetEntryData(std::shared_ptr<MacroAction> *);
|
void SetEntryData(std::shared_ptr<MacroAction> *);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "help-icon.hpp"
|
#include "help-icon.hpp"
|
||||||
#include "layout-helpers.hpp"
|
#include "layout-helpers.hpp"
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
|
#include "macro-action-factory.hpp"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -12,6 +13,74 @@ bool MacroActionMacro::_registered = MacroActionFactory::Register(
|
|||||||
{MacroActionMacro::Create, MacroActionMacroEdit::Create,
|
{MacroActionMacro::Create, MacroActionMacroEdit::Create,
|
||||||
"AdvSceneSwitcher.action.macro"});
|
"AdvSceneSwitcher.action.macro"});
|
||||||
|
|
||||||
|
void MacroActionMacro::AdjustActionState(Macro *macro) const
|
||||||
|
{
|
||||||
|
const auto ¯oActions = _useElseSection ? macro->ElseActions()
|
||||||
|
: macro->Actions();
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<MacroAction>> actionsToModify;
|
||||||
|
switch (_actionSelectionType) {
|
||||||
|
case SelectionType::INDEX: {
|
||||||
|
const bool isValidAction =
|
||||||
|
(_useElseSection &&
|
||||||
|
IsValidElseActionIndex(macro, _actionIndex - 1)) ||
|
||||||
|
(!_useElseSection &&
|
||||||
|
IsValidActionIndex(macro, _actionIndex - 1));
|
||||||
|
|
||||||
|
if (isValidAction) {
|
||||||
|
actionsToModify.emplace_back(
|
||||||
|
macroActions.at(_actionIndex - 1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SelectionType::LABEL:
|
||||||
|
for (const auto &action : macroActions) {
|
||||||
|
if (!action->GetUseCustomLabel()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto label = action->GetCustomLabel();
|
||||||
|
|
||||||
|
if (_regex.Enabled()) {
|
||||||
|
if (_regex.Matches(label, _label)) {
|
||||||
|
actionsToModify.emplace_back(action);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (label == std::string(_label)) {
|
||||||
|
actionsToModify.emplace_back(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SelectionType::ID:
|
||||||
|
for (const auto &action : macroActions) {
|
||||||
|
if (action->GetId() == _actionId) {
|
||||||
|
actionsToModify.emplace_back(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &action : actionsToModify) {
|
||||||
|
switch (_action) {
|
||||||
|
case Action::DISABLE_ACTION:
|
||||||
|
action->SetEnabled(false);
|
||||||
|
break;
|
||||||
|
case Action::ENABLE_ACTION:
|
||||||
|
action->SetEnabled(true);
|
||||||
|
break;
|
||||||
|
case Action::TOGGLE_ACTION:
|
||||||
|
action->SetEnabled(!action->Enabled());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroActionMacro::PerformAction()
|
bool MacroActionMacro::PerformAction()
|
||||||
{
|
{
|
||||||
if (_action == Action::NESTED_MACRO) {
|
if (_action == Action::NESTED_MACRO) {
|
||||||
@@ -24,47 +93,46 @@ bool MacroActionMacro::PerformAction()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_action) {
|
const auto performActionForMacro = [this](Macro *macro) {
|
||||||
case Action::PAUSE:
|
switch (_action) {
|
||||||
macro->SetPaused();
|
case Action::PAUSE:
|
||||||
break;
|
macro->SetPaused();
|
||||||
case Action::UNPAUSE:
|
break;
|
||||||
macro->SetPaused(false);
|
case Action::UNPAUSE:
|
||||||
break;
|
macro->SetPaused(false);
|
||||||
case Action::TOGGLE_PAUSE:
|
break;
|
||||||
macro->SetPaused(!macro->Paused());
|
case Action::TOGGLE_PAUSE:
|
||||||
break;
|
macro->SetPaused(!macro->Paused());
|
||||||
case Action::RESET_COUNTER:
|
break;
|
||||||
macro->ResetRunCount();
|
case Action::RESET_COUNTER:
|
||||||
break;
|
macro->ResetRunCount();
|
||||||
case Action::RUN_ACTIONS:
|
break;
|
||||||
RunActions(macro.get());
|
case Action::RUN_ACTIONS:
|
||||||
break;
|
RunActions(macro);
|
||||||
case Action::STOP:
|
break;
|
||||||
macro->Stop();
|
case Action::STOP:
|
||||||
break;
|
macro->Stop();
|
||||||
case Action::DISABLE_ACTION:
|
break;
|
||||||
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
|
case Action::DISABLE_ACTION:
|
||||||
false)) {
|
case Action::ENABLE_ACTION:
|
||||||
macro->Actions().at(_actionIndex - 1)->SetEnabled(false);
|
case Action::TOGGLE_ACTION:
|
||||||
|
AdjustActionState(macro);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
};
|
||||||
case Action::ENABLE_ACTION:
|
|
||||||
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
|
if (!IsGroupMacro(macro.get())) {
|
||||||
false)) {
|
performActionForMacro(macro.get());
|
||||||
macro->Actions().at(_actionIndex - 1)->SetEnabled(true);
|
return true;
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Action::TOGGLE_ACTION:
|
|
||||||
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
|
|
||||||
false)) {
|
|
||||||
auto action = macro->Actions().at(_actionIndex - 1);
|
|
||||||
action->SetEnabled(!action->Enabled());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto macros = GetGroupMacroEntries(macro.get());
|
||||||
|
for (const auto ¯o : macros) {
|
||||||
|
performActionForMacro(macro.get());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,9 +183,14 @@ void MacroActionMacro::LogAction() const
|
|||||||
bool MacroActionMacro::Save(obs_data_t *obj) const
|
bool MacroActionMacro::Save(obs_data_t *obj) const
|
||||||
{
|
{
|
||||||
MacroAction::Save(obj);
|
MacroAction::Save(obj);
|
||||||
_macro.Save(obj);
|
|
||||||
_actionIndex.Save(obj, "actionIndex");
|
|
||||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||||
|
_macro.Save(obj);
|
||||||
|
obs_data_set_int(obj, "actionSelectionType",
|
||||||
|
static_cast<int>(_actionSelectionType));
|
||||||
|
_actionIndex.Save(obj, "actionIndex");
|
||||||
|
_label.Save(obj, "label");
|
||||||
|
obs_data_set_string(obj, "actionId", _actionId.c_str());
|
||||||
|
_regex.Save(obj);
|
||||||
_runOptions.Save(obj);
|
_runOptions.Save(obj);
|
||||||
OBSDataAutoRelease nestedMacroData = obs_data_create();
|
OBSDataAutoRelease nestedMacroData = obs_data_create();
|
||||||
_nestedMacro->Save(nestedMacroData);
|
_nestedMacro->Save(nestedMacroData);
|
||||||
@@ -129,10 +202,15 @@ bool MacroActionMacro::Save(obs_data_t *obj) const
|
|||||||
bool MacroActionMacro::Load(obs_data_t *obj)
|
bool MacroActionMacro::Load(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
MacroAction::Load(obj);
|
MacroAction::Load(obj);
|
||||||
_macro.Load(obj);
|
|
||||||
_actionIndex.Load(obj, "actionIndex");
|
|
||||||
_action = static_cast<MacroActionMacro::Action>(
|
_action = static_cast<MacroActionMacro::Action>(
|
||||||
obs_data_get_int(obj, "action"));
|
obs_data_get_int(obj, "action"));
|
||||||
|
_macro.Load(obj);
|
||||||
|
_actionSelectionType = static_cast<SelectionType>(
|
||||||
|
obs_data_get_int(obj, "actionSelectionType"));
|
||||||
|
_actionIndex.Load(obj, "actionIndex");
|
||||||
|
_label.Load(obj, "label");
|
||||||
|
_actionId = obs_data_get_string(obj, "actionId");
|
||||||
|
_regex.Load(obj);
|
||||||
_runOptions.Load(obj);
|
_runOptions.Load(obj);
|
||||||
|
|
||||||
if (obs_data_has_user_value(obj, "nestedMacro")) {
|
if (obs_data_has_user_value(obj, "nestedMacro")) {
|
||||||
@@ -183,6 +261,7 @@ std::shared_ptr<MacroAction> MacroActionMacro::Copy() const
|
|||||||
void MacroActionMacro::ResolveVariablesToFixedValues()
|
void MacroActionMacro::ResolveVariablesToFixedValues()
|
||||||
{
|
{
|
||||||
_actionIndex.ResolveVariables();
|
_actionIndex.ResolveVariables();
|
||||||
|
_label.ResolveVariables();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void runActionsHelper(Macro *macro, bool runElseActions, bool setInputs,
|
static void runActionsHelper(Macro *macro, bool runElseActions, bool setInputs,
|
||||||
@@ -266,7 +345,7 @@ static void populateConditionBehaviorSelection(QComboBox *list)
|
|||||||
"AdvSceneSwitcher.action.macro.type.run.conditions.false"));
|
"AdvSceneSwitcher.action.macro.type.run.conditions.false"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void populateActionTypeSelection(QComboBox *list)
|
static void populateActionSectionSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
list->addItem(obs_module_text(
|
list->addItem(obs_module_text(
|
||||||
"AdvSceneSwitcher.action.macro.type.run.actionType.regular"));
|
"AdvSceneSwitcher.action.macro.type.run.actionType.regular"));
|
||||||
@@ -274,19 +353,47 @@ static void populateActionTypeSelection(QComboBox *list)
|
|||||||
"AdvSceneSwitcher.action.macro.type.run.actionType.else"));
|
"AdvSceneSwitcher.action.macro.type.run.actionType.else"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void populateActionTypes(QComboBox *list)
|
||||||
|
{
|
||||||
|
for (const auto &[id, info] : MacroActionFactory::GetActionTypes()) {
|
||||||
|
list->addItem(obs_module_text(info._name.c_str()),
|
||||||
|
QString::fromStdString(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void populateActionSelectionTypes(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.macro.actionSelectionType.index"),
|
||||||
|
static_cast<int>(MacroActionMacro::SelectionType::INDEX));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.macro.actionSelectionType.label"),
|
||||||
|
static_cast<int>(MacroActionMacro::SelectionType::LABEL));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.macro.actionSelectionType.id"),
|
||||||
|
static_cast<int>(MacroActionMacro::SelectionType::ID));
|
||||||
|
}
|
||||||
|
|
||||||
MacroActionMacroEdit::MacroActionMacroEdit(
|
MacroActionMacroEdit::MacroActionMacroEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroActionMacro> entryData)
|
QWidget *parent, std::shared_ptr<MacroActionMacro> entryData)
|
||||||
: ResizableWidget(parent),
|
: ResizableWidget(parent),
|
||||||
|
_actions(new QComboBox()),
|
||||||
_macros(new MacroSelection(parent)),
|
_macros(new MacroSelection(parent)),
|
||||||
|
_actionSelectionType(new QComboBox(this)),
|
||||||
_actionIndex(new MacroSegmentSelection(
|
_actionIndex(new MacroSegmentSelection(
|
||||||
this, MacroSegmentSelection::Type::ACTION)),
|
this, MacroSegmentSelection::Type::ACTION)),
|
||||||
_actions(new QComboBox()),
|
_label(new VariableLineEdit(this)),
|
||||||
|
_actionTypes(new FilterComboBox(this)),
|
||||||
|
_regex(new RegexConfigWidget(this)),
|
||||||
_conditionMacros(new MacroSelection(parent)),
|
_conditionMacros(new MacroSelection(parent)),
|
||||||
_conditionBehaviors(new QComboBox()),
|
_conditionBehaviors(new QComboBox()),
|
||||||
_reevaluateConditionState(new QCheckBox(
|
_reevaluateConditionState(new QCheckBox(
|
||||||
obs_module_text("AdvSceneSwitcher.action.macro.type.run."
|
obs_module_text("AdvSceneSwitcher.action.macro.type.run."
|
||||||
"updateConditionMatchState"))),
|
"updateConditionMatchState"))),
|
||||||
_actionTypes(new QComboBox()),
|
_actionSections(new QComboBox(this)),
|
||||||
_skipWhenPaused(new QCheckBox(obs_module_text(
|
_skipWhenPaused(new QCheckBox(obs_module_text(
|
||||||
"AdvSceneSwitcher.action.macro.type.run.skipWhenPaused"))),
|
"AdvSceneSwitcher.action.macro.type.run.skipWhenPaused"))),
|
||||||
_setInputs(new QCheckBox(obs_module_text(
|
_setInputs(new QCheckBox(obs_module_text(
|
||||||
@@ -305,24 +412,36 @@ MacroActionMacroEdit::MacroActionMacroEdit(
|
|||||||
{
|
{
|
||||||
populateActionSelection(_actions);
|
populateActionSelection(_actions);
|
||||||
populateConditionBehaviorSelection(_conditionBehaviors);
|
populateConditionBehaviorSelection(_conditionBehaviors);
|
||||||
populateActionTypeSelection(_actionTypes);
|
populateActionSectionSelection(_actionSections);
|
||||||
|
populateActionSelectionTypes(_actionSelectionType);
|
||||||
|
populateActionTypes(_actionTypes);
|
||||||
|
|
||||||
_conditionMacros->HideSelectedMacro();
|
_conditionMacros->HideSelectedMacro();
|
||||||
|
_conditionMacros->HideGroups();
|
||||||
|
|
||||||
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
|
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
|
||||||
this, SLOT(MacroChanged(const QString &)));
|
this, SLOT(MacroChanged(const QString &)));
|
||||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(ActionChanged(int)));
|
SLOT(ActionChanged(int)));
|
||||||
|
QWidget::connect(_actionSelectionType, SIGNAL(currentIndexChanged(int)),
|
||||||
|
this, SLOT(ActionSelectionTypeChanged(int)));
|
||||||
QWidget::connect(_actionIndex,
|
QWidget::connect(_actionIndex,
|
||||||
SIGNAL(SelectionChanged(const IntVariable &)), this,
|
SIGNAL(SelectionChanged(const IntVariable &)), this,
|
||||||
SLOT(ActionIndexChanged(const IntVariable &)));
|
SLOT(ActionIndexChanged(const IntVariable &)));
|
||||||
|
QWidget::connect(_label, SIGNAL(editingFinished()), this,
|
||||||
|
SLOT(LabelChanged()));
|
||||||
|
QWidget::connect(_actionTypes, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ActionTypeChanged(int)));
|
||||||
|
QWidget::connect(_regex,
|
||||||
|
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
|
||||||
|
SLOT(RegexChanged(const RegexConfig &)));
|
||||||
QWidget::connect(_conditionMacros,
|
QWidget::connect(_conditionMacros,
|
||||||
SIGNAL(currentTextChanged(const QString &)), this,
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
SLOT(ConditionMacroChanged(const QString &)));
|
SLOT(ConditionMacroChanged(const QString &)));
|
||||||
QWidget::connect(_conditionBehaviors, SIGNAL(currentIndexChanged(int)),
|
QWidget::connect(_conditionBehaviors, SIGNAL(currentIndexChanged(int)),
|
||||||
this, SLOT(ConditionBehaviorChanged(int)));
|
this, SLOT(ConditionBehaviorChanged(int)));
|
||||||
QWidget::connect(_actionTypes, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_actionSections, SIGNAL(currentIndexChanged(int)),
|
||||||
SLOT(ActionTypeChanged(int)));
|
this, SLOT(ActionSectionChanged(int)));
|
||||||
QWidget::connect(_skipWhenPaused, SIGNAL(stateChanged(int)), this,
|
QWidget::connect(_skipWhenPaused, SIGNAL(stateChanged(int)), this,
|
||||||
SLOT(SkipWhenPausedChanged(int)));
|
SLOT(SkipWhenPausedChanged(int)));
|
||||||
QWidget::connect(_setInputs, SIGNAL(stateChanged(int)), this,
|
QWidget::connect(_setInputs, SIGNAL(stateChanged(int)), this,
|
||||||
@@ -375,17 +494,24 @@ void MacroActionMacroEdit::UpdateEntryData()
|
|||||||
if (!_entryData) {
|
if (!_entryData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_actions->setCurrentIndex(
|
_actions->setCurrentIndex(
|
||||||
_actions->findData(static_cast<int>(_entryData->_action)));
|
_actions->findData(static_cast<int>(_entryData->_action)));
|
||||||
|
_actionSelectionType->setCurrentIndex(_actionSelectionType->findData(
|
||||||
|
static_cast<int>(_entryData->_actionSelectionType)));
|
||||||
_actionIndex->SetValue(_entryData->_actionIndex);
|
_actionIndex->SetValue(_entryData->_actionIndex);
|
||||||
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
|
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
|
||||||
|
_label->setText(_entryData->_label);
|
||||||
|
_actionTypes->setCurrentIndex(_actionTypes->findData(
|
||||||
|
QString::fromStdString(_entryData->_actionId)));
|
||||||
|
_regex->SetRegexConfig(_entryData->_regex);
|
||||||
_macros->SetCurrentMacro(_entryData->_macro);
|
_macros->SetCurrentMacro(_entryData->_macro);
|
||||||
_conditionMacros->SetCurrentMacro(_entryData->_runOptions.macro);
|
_conditionMacros->SetCurrentMacro(_entryData->_runOptions.macro);
|
||||||
_conditionBehaviors->setCurrentIndex(
|
_conditionBehaviors->setCurrentIndex(
|
||||||
static_cast<int>(_entryData->_runOptions.logic));
|
static_cast<int>(_entryData->_runOptions.logic));
|
||||||
_reevaluateConditionState->setChecked(
|
_reevaluateConditionState->setChecked(
|
||||||
_entryData->_runOptions.reevaluateConditionState);
|
_entryData->_runOptions.reevaluateConditionState);
|
||||||
_actionTypes->setCurrentIndex(
|
_actionSections->setCurrentIndex(
|
||||||
_entryData->_runOptions.runElseActions ? 1 : 0);
|
_entryData->_runOptions.runElseActions ? 1 : 0);
|
||||||
_skipWhenPaused->setChecked(_entryData->_runOptions.skipWhenPaused);
|
_skipWhenPaused->setChecked(_entryData->_runOptions.skipWhenPaused);
|
||||||
_setInputs->setChecked(_entryData->_runOptions.setInputs);
|
_setInputs->setChecked(_entryData->_runOptions.setInputs);
|
||||||
@@ -424,12 +550,40 @@ void MacroActionMacroEdit::ActionChanged(int idx)
|
|||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionMacroEdit::ActionSelectionTypeChanged(int idx)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_actionSelectionType =
|
||||||
|
static_cast<MacroActionMacro::SelectionType>(
|
||||||
|
_actionSelectionType->itemData(idx).toInt());
|
||||||
|
SetWidgetVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
void MacroActionMacroEdit::ActionIndexChanged(const IntVariable &value)
|
void MacroActionMacroEdit::ActionIndexChanged(const IntVariable &value)
|
||||||
{
|
{
|
||||||
GUARD_LOADING_AND_LOCK();
|
GUARD_LOADING_AND_LOCK();
|
||||||
_entryData->_actionIndex = value;
|
_entryData->_actionIndex = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionMacroEdit::LabelChanged()
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_label = _label->text().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMacroEdit::ActionTypeChanged(int idx)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_actionId =
|
||||||
|
_actionTypes->itemData(idx).toString().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMacroEdit::RegexChanged(const RegexConfig ®ex)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_regex = regex;
|
||||||
|
}
|
||||||
|
|
||||||
void MacroActionMacroEdit::ConditionMacroChanged(const QString &text)
|
void MacroActionMacroEdit::ConditionMacroChanged(const QString &text)
|
||||||
{
|
{
|
||||||
GUARD_LOADING_AND_LOCK();
|
GUARD_LOADING_AND_LOCK();
|
||||||
@@ -451,10 +605,13 @@ void MacroActionMacroEdit::ReevaluateConditionStateChanged(int value)
|
|||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionMacroEdit::ActionTypeChanged(int value)
|
void MacroActionMacroEdit::ActionSectionChanged(int useElse)
|
||||||
{
|
{
|
||||||
GUARD_LOADING_AND_LOCK();
|
GUARD_LOADING_AND_LOCK();
|
||||||
_entryData->_runOptions.runElseActions = value;
|
_entryData->_runOptions.runElseActions = useElse;
|
||||||
|
_entryData->_useElseSection = useElse;
|
||||||
|
_actionIndex->SetType(useElse ? MacroSegmentSelection::Type::ELSE_ACTION
|
||||||
|
: MacroSegmentSelection::Type::ACTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionMacroEdit::SkipWhenPausedChanged(int value)
|
void MacroActionMacroEdit::SkipWhenPausedChanged(int value)
|
||||||
@@ -483,7 +640,11 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
|||||||
_entryLayout->removeWidget(_actions);
|
_entryLayout->removeWidget(_actions);
|
||||||
_entryLayout->removeWidget(_actionIndex);
|
_entryLayout->removeWidget(_actionIndex);
|
||||||
_entryLayout->removeWidget(_macros);
|
_entryLayout->removeWidget(_macros);
|
||||||
|
_entryLayout->removeWidget(_actionSections);
|
||||||
|
_entryLayout->removeWidget(_label);
|
||||||
|
_entryLayout->removeWidget(_regex);
|
||||||
_entryLayout->removeWidget(_actionTypes);
|
_entryLayout->removeWidget(_actionTypes);
|
||||||
|
_entryLayout->removeWidget(_actionSelectionType);
|
||||||
_conditionLayout->removeWidget(_conditionBehaviors);
|
_conditionLayout->removeWidget(_conditionBehaviors);
|
||||||
_conditionLayout->removeWidget(_conditionMacros);
|
_conditionLayout->removeWidget(_conditionMacros);
|
||||||
|
|
||||||
@@ -494,19 +655,40 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
|||||||
{"{{actions}}", _actions},
|
{"{{actions}}", _actions},
|
||||||
{"{{actionIndex}}", _actionIndex},
|
{"{{actionIndex}}", _actionIndex},
|
||||||
{"{{macros}}", _macros},
|
{"{{macros}}", _macros},
|
||||||
{"{{actionTypes}}", _actionTypes},
|
{"{{actionSections}}", _actionSections},
|
||||||
{"{{conditionBehaviors}}", _conditionBehaviors},
|
{"{{conditionBehaviors}}", _conditionBehaviors},
|
||||||
{"{{conditionMacros}}", _conditionMacros},
|
{"{{conditionMacros}}", _conditionMacros},
|
||||||
|
{"{{actionSelectionType}}", _actionSelectionType},
|
||||||
|
{"{{label}}", _label},
|
||||||
|
{"{{regex}}", _regex},
|
||||||
|
{"{{actionTypes}}", _actionTypes},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PlaceWidgets(
|
const auto action = _entryData->_action;
|
||||||
obs_module_text(
|
const char *layoutText = "";
|
||||||
_entryData->_action ==
|
switch (action) {
|
||||||
MacroActionMacro::Action::RUN_ACTIONS
|
case MacroActionMacro::Action::PAUSE:
|
||||||
? "AdvSceneSwitcher.action.macro.entry.run"
|
case MacroActionMacro::Action::UNPAUSE:
|
||||||
: "AdvSceneSwitcher.action.macro.entry.other"),
|
case MacroActionMacro::Action::TOGGLE_PAUSE:
|
||||||
_entryLayout, placeholders);
|
case MacroActionMacro::Action::RESET_COUNTER:
|
||||||
|
case MacroActionMacro::Action::STOP:
|
||||||
|
case MacroActionMacro::Action::NESTED_MACRO:
|
||||||
|
layoutText = "AdvSceneSwitcher.action.macro.layout.other";
|
||||||
|
break;
|
||||||
|
case MacroActionMacro::Action::RUN_ACTIONS:
|
||||||
|
layoutText = "AdvSceneSwitcher.action.macro.layout.run";
|
||||||
|
break;
|
||||||
|
case MacroActionMacro::Action::DISABLE_ACTION:
|
||||||
|
case MacroActionMacro::Action::ENABLE_ACTION:
|
||||||
|
case MacroActionMacro::Action::TOGGLE_ACTION:
|
||||||
|
layoutText = "AdvSceneSwitcher.action.macro.layout.actionState";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlaceWidgets(obs_module_text(layoutText), _entryLayout, placeholders);
|
||||||
|
|
||||||
if (_entryData->_runOptions.logic ==
|
if (_entryData->_runOptions.logic ==
|
||||||
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS) {
|
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS) {
|
||||||
@@ -515,56 +697,63 @@ void MacroActionMacroEdit::SetWidgetVisibility()
|
|||||||
} else {
|
} else {
|
||||||
PlaceWidgets(
|
PlaceWidgets(
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.action.macro.entry.run.condition"),
|
"AdvSceneSwitcher.action.macro.layout.run.condition"),
|
||||||
_conditionLayout, placeholders);
|
_conditionLayout, placeholders);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_entryData->_action == MacroActionMacro::Action::RUN_ACTIONS ||
|
if (action == MacroActionMacro::Action::RUN_ACTIONS ||
|
||||||
_entryData->_action == MacroActionMacro::Action::STOP) {
|
action == MacroActionMacro::Action::STOP) {
|
||||||
_macros->HideSelectedMacro();
|
_macros->HideSelectedMacro();
|
||||||
} else {
|
} else {
|
||||||
_macros->ShowAllMacros();
|
_macros->ShowAllMacros();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto actionSelectionType = _entryData->_actionSelectionType;
|
||||||
const bool isModifyingActionState =
|
const bool isModifyingActionState =
|
||||||
_entryData->_action ==
|
action == MacroActionMacro::Action::DISABLE_ACTION ||
|
||||||
MacroActionMacro::Action::DISABLE_ACTION ||
|
action == MacroActionMacro::Action::ENABLE_ACTION ||
|
||||||
_entryData->_action ==
|
action == MacroActionMacro::Action::TOGGLE_ACTION;
|
||||||
MacroActionMacro::Action::ENABLE_ACTION ||
|
_actionSelectionType->setVisible(isModifyingActionState);
|
||||||
_entryData->_action == MacroActionMacro::Action::TOGGLE_ACTION;
|
_actionIndex->setVisible(
|
||||||
_actionIndex->setVisible(isModifyingActionState);
|
isModifyingActionState &&
|
||||||
|
actionSelectionType == MacroActionMacro::SelectionType::INDEX);
|
||||||
|
_label->setVisible(isModifyingActionState &&
|
||||||
|
actionSelectionType ==
|
||||||
|
MacroActionMacro::SelectionType::LABEL);
|
||||||
|
_regex->setVisible(isModifyingActionState &&
|
||||||
|
actionSelectionType ==
|
||||||
|
MacroActionMacro::SelectionType::LABEL);
|
||||||
|
_actionTypes->setVisible(isModifyingActionState &&
|
||||||
|
actionSelectionType ==
|
||||||
|
MacroActionMacro::SelectionType::ID);
|
||||||
|
|
||||||
SetLayoutVisible(_conditionLayout,
|
SetLayoutVisible(_conditionLayout,
|
||||||
_entryData->_action ==
|
action == MacroActionMacro::Action::RUN_ACTIONS);
|
||||||
MacroActionMacro::Action::RUN_ACTIONS);
|
|
||||||
const bool needsAdditionalConditionWidgets =
|
const bool needsAdditionalConditionWidgets =
|
||||||
_entryData->_action == MacroActionMacro::Action::RUN_ACTIONS &&
|
action == MacroActionMacro::Action::RUN_ACTIONS &&
|
||||||
_entryData->_runOptions.logic !=
|
_entryData->_runOptions.logic !=
|
||||||
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS;
|
MacroActionMacro::RunOptions::Logic::IGNORE_CONDITIONS;
|
||||||
_conditionMacros->setVisible(needsAdditionalConditionWidgets);
|
_conditionMacros->setVisible(needsAdditionalConditionWidgets);
|
||||||
SetLayoutVisible(_reevaluateConditionStateLayout,
|
SetLayoutVisible(_reevaluateConditionStateLayout,
|
||||||
needsAdditionalConditionWidgets);
|
needsAdditionalConditionWidgets);
|
||||||
SetLayoutVisible(_setInputsLayout,
|
SetLayoutVisible(_setInputsLayout,
|
||||||
_entryData->_action ==
|
action == MacroActionMacro::Action::RUN_ACTIONS);
|
||||||
MacroActionMacro::Action::RUN_ACTIONS);
|
_inputs->setVisible(action == MacroActionMacro::Action::RUN_ACTIONS &&
|
||||||
_inputs->setVisible(_entryData->_action ==
|
|
||||||
MacroActionMacro::Action::RUN_ACTIONS &&
|
|
||||||
_entryData->_runOptions.setInputs);
|
_entryData->_runOptions.setInputs);
|
||||||
HighlightMacroSettingsButton(
|
HighlightMacroSettingsButton(
|
||||||
_entryData->_action == MacroActionMacro::Action::RUN_ACTIONS &&
|
action == MacroActionMacro::Action::RUN_ACTIONS &&
|
||||||
_entryData->_runOptions.setInputs &&
|
_entryData->_runOptions.setInputs &&
|
||||||
!_inputs->HasInputsToSet());
|
!_inputs->HasInputsToSet());
|
||||||
_actionTypes->setVisible(_entryData->_action ==
|
_actionSections->setVisible(
|
||||||
MacroActionMacro::Action::RUN_ACTIONS);
|
action == MacroActionMacro::Action::RUN_ACTIONS ||
|
||||||
_skipWhenPaused->setVisible(_entryData->_action ==
|
isModifyingActionState);
|
||||||
|
_skipWhenPaused->setVisible(action ==
|
||||||
MacroActionMacro::Action::RUN_ACTIONS);
|
MacroActionMacro::Action::RUN_ACTIONS);
|
||||||
|
|
||||||
_nestedMacro->setVisible(_entryData->_action ==
|
_nestedMacro->setVisible(action ==
|
||||||
MacroActionMacro::Action::NESTED_MACRO);
|
MacroActionMacro::Action::NESTED_MACRO);
|
||||||
_macros->setVisible(_entryData->_action !=
|
_macros->setVisible(action != MacroActionMacro::Action::NESTED_MACRO);
|
||||||
MacroActionMacro::Action::NESTED_MACRO);
|
SetResizingEnabled(action == MacroActionMacro::Action::NESTED_MACRO);
|
||||||
SetResizingEnabled(_entryData->_action ==
|
|
||||||
MacroActionMacro::Action::NESTED_MACRO);
|
|
||||||
|
|
||||||
if (_nestedMacro->IsEmpty()) {
|
if (_nestedMacro->IsEmpty()) {
|
||||||
_nestedMacro->ShowAllMacroSections();
|
_nestedMacro->ShowAllMacroSections();
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
#include "macro-input.hpp"
|
#include "macro-input.hpp"
|
||||||
#include "macro-selection.hpp"
|
#include "macro-selection.hpp"
|
||||||
#include "macro-segment-selection.hpp"
|
#include "macro-segment-selection.hpp"
|
||||||
|
#include "regex-config.hpp"
|
||||||
#include "resizable-widget.hpp"
|
#include "resizable-widget.hpp"
|
||||||
|
#include "variable-line-edit.hpp"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
@@ -55,14 +57,23 @@ public:
|
|||||||
TOGGLE_PAUSE,
|
TOGGLE_PAUSE,
|
||||||
NESTED_MACRO,
|
NESTED_MACRO,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class SelectionType { INDEX, LABEL, ID };
|
||||||
|
|
||||||
Action _action = Action::NESTED_MACRO;
|
Action _action = Action::NESTED_MACRO;
|
||||||
|
SelectionType _actionSelectionType = SelectionType::INDEX;
|
||||||
|
bool _useElseSection = false;
|
||||||
IntVariable _actionIndex = 1;
|
IntVariable _actionIndex = 1;
|
||||||
|
StringVariable _label = "Custom label";
|
||||||
|
std::string _actionId;
|
||||||
|
RegexConfig _regex;
|
||||||
RunOptions _runOptions = {};
|
RunOptions _runOptions = {};
|
||||||
std::shared_ptr<Macro> _nestedMacro = std::make_shared<Macro>();
|
std::shared_ptr<Macro> _nestedMacro = std::make_shared<Macro>();
|
||||||
int _customWidgetHeight = 0;
|
int _customWidgetHeight = 0;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RunActions(Macro *actionMacro) const;
|
void RunActions(Macro *actionMacro) const;
|
||||||
|
void AdjustActionState(Macro *) const;
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const std::string id;
|
static const std::string id;
|
||||||
@@ -82,11 +93,15 @@ public:
|
|||||||
private slots:
|
private slots:
|
||||||
void MacroChanged(const QString &text);
|
void MacroChanged(const QString &text);
|
||||||
void ActionChanged(int value);
|
void ActionChanged(int value);
|
||||||
|
void ActionSelectionTypeChanged(int value);
|
||||||
void ActionIndexChanged(const IntVariable &value);
|
void ActionIndexChanged(const IntVariable &value);
|
||||||
|
void LabelChanged();
|
||||||
|
void ActionTypeChanged(int value);
|
||||||
|
void RegexChanged(const RegexConfig &);
|
||||||
void ConditionMacroChanged(const QString &text);
|
void ConditionMacroChanged(const QString &text);
|
||||||
void ConditionBehaviorChanged(int value);
|
void ConditionBehaviorChanged(int value);
|
||||||
void ReevaluateConditionStateChanged(int value);
|
void ReevaluateConditionStateChanged(int value);
|
||||||
void ActionTypeChanged(int value);
|
void ActionSectionChanged(int value);
|
||||||
void SkipWhenPausedChanged(int value);
|
void SkipWhenPausedChanged(int value);
|
||||||
void SetInputsChanged(int value);
|
void SetInputsChanged(int value);
|
||||||
void InputsChanged(const StringList &);
|
void InputsChanged(const StringList &);
|
||||||
@@ -98,13 +113,17 @@ private:
|
|||||||
void SetWidgetVisibility();
|
void SetWidgetVisibility();
|
||||||
void SetupMacroInput(Macro *) const;
|
void SetupMacroInput(Macro *) const;
|
||||||
|
|
||||||
MacroSelection *_macros;
|
|
||||||
MacroSegmentSelection *_actionIndex;
|
|
||||||
QComboBox *_actions;
|
QComboBox *_actions;
|
||||||
|
MacroSelection *_macros;
|
||||||
|
QComboBox *_actionSelectionType;
|
||||||
|
MacroSegmentSelection *_actionIndex;
|
||||||
|
VariableLineEdit *_label;
|
||||||
|
FilterComboBox *_actionTypes;
|
||||||
|
RegexConfigWidget *_regex;
|
||||||
MacroSelection *_conditionMacros;
|
MacroSelection *_conditionMacros;
|
||||||
QComboBox *_conditionBehaviors;
|
QComboBox *_conditionBehaviors;
|
||||||
QCheckBox *_reevaluateConditionState;
|
QCheckBox *_reevaluateConditionState;
|
||||||
QComboBox *_actionTypes;
|
QComboBox *_actionSections;
|
||||||
QCheckBox *_skipWhenPaused;
|
QCheckBox *_skipWhenPaused;
|
||||||
QCheckBox *_setInputs;
|
QCheckBox *_setInputs;
|
||||||
MacroInputEdit *_inputs;
|
MacroInputEdit *_inputs;
|
||||||
|
|||||||
@@ -219,6 +219,43 @@ void MacroActionVariable::GenerateRandomNumber(Variable *var)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionVariable::PickRandomValue(Variable *var)
|
||||||
|
{
|
||||||
|
static std::random_device rd;
|
||||||
|
static std::mt19937 gen(rd());
|
||||||
|
static const uint8_t maxIter = 255;
|
||||||
|
|
||||||
|
if (_randomValues.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_randomValues.size() == 1) {
|
||||||
|
const auto &value = _randomValues.at(0);
|
||||||
|
var->SetValue(value);
|
||||||
|
_lastRandomValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uniform_int_distribution<int> dis(0, _randomValues.size() - 1);
|
||||||
|
StringVariable value = _randomValues.at(dis(gen));
|
||||||
|
|
||||||
|
uint8_t iter = 0;
|
||||||
|
for (; !_allowRepeatValues && iter < maxIter &&
|
||||||
|
_lastRandomValue.has_value() &&
|
||||||
|
std::string(value) == _lastRandomValue.value();
|
||||||
|
iter++) {
|
||||||
|
value = _randomValues.at(dis(gen));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iter == maxIter) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"giving up picking non-repeat random value after %d tries",
|
||||||
|
maxIter);
|
||||||
|
}
|
||||||
|
|
||||||
|
var->SetValue(value);
|
||||||
|
_lastRandomValue = value;
|
||||||
|
}
|
||||||
|
|
||||||
struct AskForInputParams {
|
struct AskForInputParams {
|
||||||
AskForInputParams(const QString &prompt_, const QString &placeholder_)
|
AskForInputParams(const QString &prompt_, const QString &placeholder_)
|
||||||
: prompt(prompt_),
|
: prompt(prompt_),
|
||||||
@@ -286,6 +323,14 @@ bool MacroActionVariable::PerformAction()
|
|||||||
case Action::APPEND:
|
case Action::APPEND:
|
||||||
apppend(*var, _strValue);
|
apppend(*var, _strValue);
|
||||||
break;
|
break;
|
||||||
|
case Action::COPY_VAR: {
|
||||||
|
auto var2 = _variable2.lock();
|
||||||
|
if (!var2) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var->SetValue(var2->Value());
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Action::APPEND_VAR: {
|
case Action::APPEND_VAR: {
|
||||||
auto var2 = _variable2.lock();
|
auto var2 = _variable2.lock();
|
||||||
if (!var2) {
|
if (!var2) {
|
||||||
@@ -450,6 +495,9 @@ bool MacroActionVariable::PerformAction()
|
|||||||
case Action::RANDOM_NUMBER:
|
case Action::RANDOM_NUMBER:
|
||||||
GenerateRandomNumber(var.get());
|
GenerateRandomNumber(var.get());
|
||||||
return true;
|
return true;
|
||||||
|
case Action::RANDOM_LIST_VALUE:
|
||||||
|
PickRandomValue(var.get());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -490,6 +538,8 @@ bool MacroActionVariable::Save(obs_data_t *obj) const
|
|||||||
_randomNumberStart.Save(obj, "randomNumberStart");
|
_randomNumberStart.Save(obj, "randomNumberStart");
|
||||||
_randomNumberEnd.Save(obj, "randomNumberEnd");
|
_randomNumberEnd.Save(obj, "randomNumberEnd");
|
||||||
obs_data_set_bool(obj, "generateInteger", _generateInteger);
|
obs_data_set_bool(obj, "generateInteger", _generateInteger);
|
||||||
|
_randomValues.Save(obj, "randomValues", "value");
|
||||||
|
obs_data_set_bool(obj, "allowRepeatValues", _allowRepeatValues);
|
||||||
_jsonQuery.Save(obj, "jsonQuery");
|
_jsonQuery.Save(obj, "jsonQuery");
|
||||||
_jsonIndex.Save(obj, "jsonIndex");
|
_jsonIndex.Save(obj, "jsonIndex");
|
||||||
|
|
||||||
@@ -548,6 +598,8 @@ bool MacroActionVariable::Load(obs_data_t *obj)
|
|||||||
_randomNumberStart.Load(obj, "randomNumberStart");
|
_randomNumberStart.Load(obj, "randomNumberStart");
|
||||||
_randomNumberEnd.Load(obj, "randomNumberEnd");
|
_randomNumberEnd.Load(obj, "randomNumberEnd");
|
||||||
_generateInteger = obs_data_get_bool(obj, "generateInteger");
|
_generateInteger = obs_data_get_bool(obj, "generateInteger");
|
||||||
|
_randomValues.Load(obj, "randomValues", "value");
|
||||||
|
_allowRepeatValues = obs_data_get_bool(obj, "allowRepeatValues");
|
||||||
_jsonQuery.Load(obj, "jsonQuery");
|
_jsonQuery.Load(obj, "jsonQuery");
|
||||||
_jsonIndex.Load(obj, "jsonIndex");
|
_jsonIndex.Load(obj, "jsonIndex");
|
||||||
|
|
||||||
@@ -670,6 +722,8 @@ static inline void populateActionSelection(QComboBox *list)
|
|||||||
actions = {
|
actions = {
|
||||||
{MacroActionVariable::Action::SET_VALUE,
|
{MacroActionVariable::Action::SET_VALUE,
|
||||||
"AdvSceneSwitcher.action.variable.type.set"},
|
"AdvSceneSwitcher.action.variable.type.set"},
|
||||||
|
{MacroActionVariable::Action::COPY_VAR,
|
||||||
|
"AdvSceneSwitcher.action.variable.type.copy"},
|
||||||
{MacroActionVariable::Action::APPEND,
|
{MacroActionVariable::Action::APPEND,
|
||||||
"AdvSceneSwitcher.action.variable.type.append"},
|
"AdvSceneSwitcher.action.variable.type.append"},
|
||||||
{MacroActionVariable::Action::PAD,
|
{MacroActionVariable::Action::PAD,
|
||||||
@@ -714,6 +768,8 @@ static inline void populateActionSelection(QComboBox *list)
|
|||||||
"AdvSceneSwitcher.action.variable.type.roundToInt"},
|
"AdvSceneSwitcher.action.variable.type.roundToInt"},
|
||||||
{MacroActionVariable::Action::RANDOM_NUMBER,
|
{MacroActionVariable::Action::RANDOM_NUMBER,
|
||||||
"AdvSceneSwitcher.action.variable.type.randomNumber"},
|
"AdvSceneSwitcher.action.variable.type.randomNumber"},
|
||||||
|
{MacroActionVariable::Action::RANDOM_LIST_VALUE,
|
||||||
|
"AdvSceneSwitcher.action.variable.type.randomListValue"},
|
||||||
{true, ""}, // Separator
|
{true, ""}, // Separator
|
||||||
|
|
||||||
{MacroActionVariable::Action::USER_INPUT,
|
{MacroActionVariable::Action::USER_INPUT,
|
||||||
@@ -791,11 +847,10 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
_segmentValueStatus(new QLabel()),
|
_segmentValueStatus(new QLabel()),
|
||||||
_segmentValue(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
_segmentValue(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
||||||
_substringLayout(new QVBoxLayout()),
|
_substringLayout(new QVBoxLayout()),
|
||||||
_subStringIndexEntryLayout(new QHBoxLayout()),
|
_subStringControlsLayout(new QHBoxLayout()),
|
||||||
_subStringRegexEntryLayout(new QHBoxLayout()),
|
|
||||||
_subStringStart(new VariableSpinBox(this)),
|
_subStringStart(new VariableSpinBox(this)),
|
||||||
_subStringSize(new VariableSpinBox(this)),
|
_subStringSize(new VariableSpinBox(this)),
|
||||||
_substringRegex(new RegexConfigWidget(parent)),
|
_subStringRegex(new RegexConfigWidget(parent)),
|
||||||
_regexPattern(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
_regexPattern(new ResizingPlainTextEdit(this, 10, 1, 1)),
|
||||||
_regexMatchIdx(new VariableSpinBox(this)),
|
_regexMatchIdx(new VariableSpinBox(this)),
|
||||||
_findReplaceLayout(new QHBoxLayout()),
|
_findReplaceLayout(new QHBoxLayout()),
|
||||||
@@ -827,7 +882,13 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.action.variable.generateInteger"),
|
"AdvSceneSwitcher.action.variable.generateInteger"),
|
||||||
this)),
|
this)),
|
||||||
_randomLayout(new QVBoxLayout()),
|
_randomNumberLayout(new QVBoxLayout()),
|
||||||
|
_randomValues(new StringListEdit(this)),
|
||||||
|
_allowRepeatValues(new QCheckBox(
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.variable.type.allowRepeat"),
|
||||||
|
this)),
|
||||||
|
_randomValueLayout(new QVBoxLayout()),
|
||||||
_jsonQuery(new VariableLineEdit(this)),
|
_jsonQuery(new VariableLineEdit(this)),
|
||||||
_jsonQueryHelp(new HelpIcon(
|
_jsonQueryHelp(new HelpIcon(
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
@@ -863,6 +924,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
_randomNumberStart->setMaximum(9999999999);
|
_randomNumberStart->setMaximum(9999999999);
|
||||||
_randomNumberEnd->setMinimum(-9999999999);
|
_randomNumberEnd->setMinimum(-9999999999);
|
||||||
_randomNumberEnd->setMaximum(9999999999);
|
_randomNumberEnd->setMaximum(9999999999);
|
||||||
|
_randomValues->SetMaxStringSize(99999999);
|
||||||
_jsonIndex->setMaximum(999);
|
_jsonIndex->setMaximum(999);
|
||||||
|
|
||||||
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
QWidget::connect(_variables, SIGNAL(SelectionChanged(const QString &)),
|
||||||
@@ -891,7 +953,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
_subStringSize,
|
_subStringSize,
|
||||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||||
this, SLOT(SubStringSizeChanged(const NumberVariable<int> &)));
|
this, SLOT(SubStringSizeChanged(const NumberVariable<int> &)));
|
||||||
QWidget::connect(_substringRegex,
|
QWidget::connect(_subStringRegex,
|
||||||
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
|
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
|
||||||
SLOT(SubStringRegexChanged(const RegexConfig &)));
|
SLOT(SubStringRegexChanged(const RegexConfig &)));
|
||||||
QWidget::connect(_regexPattern, SIGNAL(textChanged()), this,
|
QWidget::connect(_regexPattern, SIGNAL(textChanged()), this,
|
||||||
@@ -951,6 +1013,11 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
SLOT(RandomNumberEndChanged(const NumberVariable<double> &)));
|
SLOT(RandomNumberEndChanged(const NumberVariable<double> &)));
|
||||||
QWidget::connect(_generateInteger, SIGNAL(stateChanged(int)), this,
|
QWidget::connect(_generateInteger, SIGNAL(stateChanged(int)), this,
|
||||||
SLOT(GenerateIntegerChanged(int)));
|
SLOT(GenerateIntegerChanged(int)));
|
||||||
|
QWidget::connect(_randomValues,
|
||||||
|
SIGNAL(StringListChanged(const StringList &)), this,
|
||||||
|
SLOT(RandomValueListChanged(const StringList &)));
|
||||||
|
QWidget::connect(_allowRepeatValues, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(AllowRepeatValuesChanged(int)));
|
||||||
QWidget::connect(_jsonQuery, SIGNAL(editingFinished()), this,
|
QWidget::connect(_jsonQuery, SIGNAL(editingFinished()), this,
|
||||||
SLOT(JsonQueryChanged()));
|
SLOT(JsonQueryChanged()));
|
||||||
QWidget::connect(
|
QWidget::connect(
|
||||||
@@ -965,9 +1032,6 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
{"{{strValue}}", _strValue},
|
{"{{strValue}}", _strValue},
|
||||||
{"{{numValue}}", _numValue},
|
{"{{numValue}}", _numValue},
|
||||||
{"{{segmentIndex}}", _segmentIdx},
|
{"{{segmentIndex}}", _segmentIdx},
|
||||||
{"{{subStringStart}}", _subStringStart},
|
|
||||||
{"{{subStringSize}}", _subStringSize},
|
|
||||||
{"{{regexMatchIdx}}", _regexMatchIdx},
|
|
||||||
{"{{findRegex}}", _findRegex},
|
{"{{findRegex}}", _findRegex},
|
||||||
{"{{findStr}}", _findStr},
|
{"{{findStr}}", _findStr},
|
||||||
{"{{replaceStr}}", _replaceStr},
|
{"{{replaceStr}}", _replaceStr},
|
||||||
@@ -999,12 +1063,7 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
PlaceWidgets(
|
PlaceWidgets(
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.action.variable.layout.substringIndex"),
|
"AdvSceneSwitcher.action.variable.layout.substringIndex"),
|
||||||
_subStringIndexEntryLayout, widgetPlaceholders);
|
_subStringControlsLayout, widgetPlaceholders);
|
||||||
|
|
||||||
PlaceWidgets(
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.action.variable.layout.substringRegex"),
|
|
||||||
_subStringRegexEntryLayout, widgetPlaceholders);
|
|
||||||
|
|
||||||
PlaceWidgets(
|
PlaceWidgets(
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
@@ -1025,15 +1084,17 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.action.variable.layout.randomNumber"),
|
"AdvSceneSwitcher.action.variable.layout.randomNumber"),
|
||||||
randomLayout, widgetPlaceholders);
|
randomLayout, widgetPlaceholders);
|
||||||
_randomLayout->addLayout(randomLayout);
|
_randomNumberLayout->addLayout(randomLayout);
|
||||||
_randomLayout->addWidget(_generateInteger);
|
_randomNumberLayout->addWidget(_generateInteger);
|
||||||
|
|
||||||
|
_randomValueLayout->addWidget(_randomValues);
|
||||||
|
_randomValueLayout->addWidget(_allowRepeatValues);
|
||||||
|
|
||||||
auto regexConfigLayout = new QHBoxLayout;
|
auto regexConfigLayout = new QHBoxLayout;
|
||||||
regexConfigLayout->addWidget(_substringRegex);
|
regexConfigLayout->addWidget(_subStringRegex);
|
||||||
regexConfigLayout->addStretch();
|
regexConfigLayout->addStretch();
|
||||||
|
|
||||||
_substringLayout->addLayout(_subStringIndexEntryLayout);
|
_substringLayout->addLayout(_subStringControlsLayout);
|
||||||
_substringLayout->addLayout(_subStringRegexEntryLayout);
|
|
||||||
_substringLayout->addWidget(_regexPattern);
|
_substringLayout->addWidget(_regexPattern);
|
||||||
_substringLayout->addLayout(regexConfigLayout);
|
_substringLayout->addLayout(regexConfigLayout);
|
||||||
|
|
||||||
@@ -1046,7 +1107,8 @@ MacroActionVariableEdit::MacroActionVariableEdit(
|
|||||||
layout->addWidget(_mathExpressionResult);
|
layout->addWidget(_mathExpressionResult);
|
||||||
layout->addLayout(_promptLayout);
|
layout->addLayout(_promptLayout);
|
||||||
layout->addLayout(_placeholderLayout);
|
layout->addLayout(_placeholderLayout);
|
||||||
layout->addLayout(_randomLayout);
|
layout->addLayout(_randomNumberLayout);
|
||||||
|
layout->addLayout(_randomValueLayout);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
@@ -1080,7 +1142,7 @@ void MacroActionVariableEdit::UpdateEntryData()
|
|||||||
: MacroSegmentSelection::Type::ACTION);
|
: MacroSegmentSelection::Type::ACTION);
|
||||||
_subStringStart->SetValue(_entryData->_subStringStart);
|
_subStringStart->SetValue(_entryData->_subStringStart);
|
||||||
_subStringSize->SetValue(_entryData->_subStringSize);
|
_subStringSize->SetValue(_entryData->_subStringSize);
|
||||||
_substringRegex->SetRegexConfig(_entryData->_subStringRegex);
|
_subStringRegex->SetRegexConfig(_entryData->_subStringRegex);
|
||||||
_findRegex->SetRegexConfig(_entryData->_findRegex);
|
_findRegex->SetRegexConfig(_entryData->_findRegex);
|
||||||
_regexPattern->setPlainText(
|
_regexPattern->setPlainText(
|
||||||
QString::fromStdString(_entryData->_regexPattern));
|
QString::fromStdString(_entryData->_regexPattern));
|
||||||
@@ -1105,6 +1167,8 @@ void MacroActionVariableEdit::UpdateEntryData()
|
|||||||
_randomNumberStart->SetValue(_entryData->_randomNumberStart);
|
_randomNumberStart->SetValue(_entryData->_randomNumberStart);
|
||||||
_randomNumberEnd->SetValue(_entryData->_randomNumberEnd);
|
_randomNumberEnd->SetValue(_entryData->_randomNumberEnd);
|
||||||
_generateInteger->setChecked(_entryData->_generateInteger);
|
_generateInteger->setChecked(_entryData->_generateInteger);
|
||||||
|
_allowRepeatValues->setChecked(_entryData->_allowRepeatValues);
|
||||||
|
_randomValues->SetStringList(_entryData->_randomValues);
|
||||||
_jsonQuery->setText(_entryData->_jsonQuery);
|
_jsonQuery->setText(_entryData->_jsonQuery);
|
||||||
_jsonIndex->SetValue(_entryData->_jsonIndex);
|
_jsonIndex->SetValue(_entryData->_jsonIndex);
|
||||||
|
|
||||||
@@ -1447,6 +1511,18 @@ void MacroActionVariableEdit::GenerateIntegerChanged(int value)
|
|||||||
_entryData->_generateInteger = value;
|
_entryData->_generateInteger = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionVariableEdit::RandomValueListChanged(const StringList &values)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_randomValues = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionVariableEdit::AllowRepeatValuesChanged(int value)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_allowRepeatValues = value;
|
||||||
|
}
|
||||||
|
|
||||||
void MacroActionVariableEdit::JsonQueryChanged()
|
void MacroActionVariableEdit::JsonQueryChanged()
|
||||||
{
|
{
|
||||||
GUARD_LOADING_AND_LOCK();
|
GUARD_LOADING_AND_LOCK();
|
||||||
@@ -1485,8 +1561,20 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
|||||||
{"{{jsonQuery}}", _jsonQuery},
|
{"{{jsonQuery}}", _jsonQuery},
|
||||||
{"{{jsonQueryHelp}}", _jsonQueryHelp},
|
{"{{jsonQueryHelp}}", _jsonQueryHelp},
|
||||||
{"{{jsonIndex}}", _jsonIndex},
|
{"{{jsonIndex}}", _jsonIndex},
|
||||||
|
{"{{subStringRegex}}", _subStringRegex},
|
||||||
|
{"{{subStringStart}}", _subStringStart},
|
||||||
|
{"{{subStringSize}}", _subStringSize},
|
||||||
|
{"{{regexMatchIdx}}", _regexMatchIdx},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
for (const auto &[_, widget] : widgetPlaceholders) {
|
||||||
|
_entryLayout->removeWidget(widget);
|
||||||
|
_subStringControlsLayout->removeWidget(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearLayout(_entryLayout);
|
||||||
|
ClearLayout(_subStringControlsLayout);
|
||||||
|
|
||||||
const char *layoutString = "";
|
const char *layoutString = "";
|
||||||
if (_entryData->_action == MacroActionVariable::Action::PAD) {
|
if (_entryData->_action == MacroActionVariable::Action::PAD) {
|
||||||
layoutString = obs_module_text(
|
layoutString = obs_module_text(
|
||||||
@@ -1500,11 +1588,6 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
|||||||
"AdvSceneSwitcher.action.variable.layout.other");
|
"AdvSceneSwitcher.action.variable.layout.other");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &[_, widget] : widgetPlaceholders) {
|
|
||||||
_entryLayout->removeWidget(widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClearLayout(_entryLayout);
|
|
||||||
PlaceWidgets(layoutString, _entryLayout, widgetPlaceholders);
|
PlaceWidgets(layoutString, _entryLayout, widgetPlaceholders);
|
||||||
|
|
||||||
if (_entryData->_action == MacroActionVariable::Action::SET_VALUE ||
|
if (_entryData->_action == MacroActionVariable::Action::SET_VALUE ||
|
||||||
@@ -1521,6 +1604,7 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
|||||||
}
|
}
|
||||||
|
|
||||||
_variables2->setVisible(
|
_variables2->setVisible(
|
||||||
|
_entryData->_action == MacroActionVariable::Action::COPY_VAR ||
|
||||||
_entryData->_action ==
|
_entryData->_action ==
|
||||||
MacroActionVariable::Action::APPEND_VAR ||
|
MacroActionVariable::Action::APPEND_VAR ||
|
||||||
_entryData->_action ==
|
_entryData->_action ==
|
||||||
@@ -1550,15 +1634,25 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
|||||||
MacroActionVariable::Action::SET_ACTION_VALUE ||
|
MacroActionVariable::Action::SET_ACTION_VALUE ||
|
||||||
_entryData->_action ==
|
_entryData->_action ==
|
||||||
MacroActionVariable::Action::SET_CONDITION_VALUE);
|
MacroActionVariable::Action::SET_CONDITION_VALUE);
|
||||||
|
|
||||||
|
bool showRegex = _entryData->_subStringRegex.Enabled();
|
||||||
|
layoutString =
|
||||||
|
showRegex
|
||||||
|
? "AdvSceneSwitcher.action.variable.layout.substringRegex"
|
||||||
|
: "AdvSceneSwitcher.action.variable.layout.substringIndex";
|
||||||
|
PlaceWidgets(obs_module_text(layoutString), _subStringControlsLayout,
|
||||||
|
widgetPlaceholders);
|
||||||
|
_subStringStart->setVisible(!showRegex);
|
||||||
|
_subStringSize->setVisible(!showRegex);
|
||||||
|
_regexMatchIdx->setVisible(showRegex);
|
||||||
|
|
||||||
SetLayoutVisible(_substringLayout,
|
SetLayoutVisible(_substringLayout,
|
||||||
_entryData->_action ==
|
_entryData->_action ==
|
||||||
MacroActionVariable::Action::SUBSTRING);
|
MacroActionVariable::Action::SUBSTRING);
|
||||||
if (_entryData->_action == MacroActionVariable::Action::SUBSTRING) {
|
_regexPattern->setVisible(
|
||||||
bool showRegex = _entryData->_subStringRegex.Enabled();
|
showRegex &&
|
||||||
SetLayoutVisible(_subStringIndexEntryLayout, !showRegex);
|
_entryData->_action == MacroActionVariable::Action::SUBSTRING);
|
||||||
SetLayoutVisible(_subStringRegexEntryLayout, showRegex);
|
|
||||||
_regexPattern->setVisible(showRegex);
|
|
||||||
}
|
|
||||||
SetLayoutVisible(_findReplaceLayout,
|
SetLayoutVisible(_findReplaceLayout,
|
||||||
_entryData->_action ==
|
_entryData->_action ==
|
||||||
MacroActionVariable::Action::FIND_AND_REPLACE);
|
MacroActionVariable::Action::FIND_AND_REPLACE);
|
||||||
@@ -1623,9 +1717,13 @@ void MacroActionVariableEdit::SetWidgetVisibility()
|
|||||||
MacroActionVariable::Action::PAD);
|
MacroActionVariable::Action::PAD);
|
||||||
_caseType->setVisible(_entryData->_action ==
|
_caseType->setVisible(_entryData->_action ==
|
||||||
MacroActionVariable::Action::CHANGE_CASE);
|
MacroActionVariable::Action::CHANGE_CASE);
|
||||||
SetLayoutVisible(_randomLayout,
|
SetLayoutVisible(_randomNumberLayout,
|
||||||
_entryData->_action ==
|
_entryData->_action ==
|
||||||
MacroActionVariable::Action::RANDOM_NUMBER);
|
MacroActionVariable::Action::RANDOM_NUMBER);
|
||||||
|
SetLayoutVisible(
|
||||||
|
_randomValueLayout,
|
||||||
|
_entryData->_action ==
|
||||||
|
MacroActionVariable::Action::RANDOM_LIST_VALUE);
|
||||||
_jsonQuery->setVisible(_entryData->_action ==
|
_jsonQuery->setVisible(_entryData->_action ==
|
||||||
MacroActionVariable::Action::QUERY_JSON);
|
MacroActionVariable::Action::QUERY_JSON);
|
||||||
_jsonQueryHelp->setVisible(_entryData->_action ==
|
_jsonQueryHelp->setVisible(_entryData->_action ==
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "resizing-text-edit.hpp"
|
#include "resizing-text-edit.hpp"
|
||||||
#include "scene-selection.hpp"
|
#include "scene-selection.hpp"
|
||||||
#include "single-char-selection.hpp"
|
#include "single-char-selection.hpp"
|
||||||
|
#include "string-list.hpp"
|
||||||
#include "variable-line-edit.hpp"
|
#include "variable-line-edit.hpp"
|
||||||
#include "variable-text-edit.hpp"
|
#include "variable-text-edit.hpp"
|
||||||
#include "variable-spinbox.hpp"
|
#include "variable-spinbox.hpp"
|
||||||
@@ -55,6 +56,8 @@ public:
|
|||||||
RANDOM_NUMBER,
|
RANDOM_NUMBER,
|
||||||
QUERY_JSON,
|
QUERY_JSON,
|
||||||
ARRAY_JSON,
|
ARRAY_JSON,
|
||||||
|
COPY_VAR,
|
||||||
|
RANDOM_LIST_VALUE,
|
||||||
};
|
};
|
||||||
|
|
||||||
Action _action = Action::SET_VALUE;
|
Action _action = Action::SET_VALUE;
|
||||||
@@ -106,6 +109,10 @@ public:
|
|||||||
DoubleVariable _randomNumberEnd = 100;
|
DoubleVariable _randomNumberEnd = 100;
|
||||||
bool _generateInteger = true;
|
bool _generateInteger = true;
|
||||||
|
|
||||||
|
StringList _randomValues = {"value1", "value2", "value3"};
|
||||||
|
bool _allowRepeatValues = true;
|
||||||
|
std::optional<std::string> _lastRandomValue;
|
||||||
|
|
||||||
StringVariable _jsonQuery = "$.some.nested.value";
|
StringVariable _jsonQuery = "$.some.nested.value";
|
||||||
IntVariable _jsonIndex = 0;
|
IntVariable _jsonIndex = 0;
|
||||||
|
|
||||||
@@ -118,6 +125,7 @@ private:
|
|||||||
void HandleCaseChange(Variable *);
|
void HandleCaseChange(Variable *);
|
||||||
void SetToSceneItemName(Variable *);
|
void SetToSceneItemName(Variable *);
|
||||||
void GenerateRandomNumber(Variable *);
|
void GenerateRandomNumber(Variable *);
|
||||||
|
void PickRandomValue(Variable *);
|
||||||
|
|
||||||
std::weak_ptr<MacroSegment> _macroSegment;
|
std::weak_ptr<MacroSegment> _macroSegment;
|
||||||
int _segmentIdxLoadValue = -1;
|
int _segmentIdxLoadValue = -1;
|
||||||
@@ -174,6 +182,8 @@ private slots:
|
|||||||
void RandomNumberStartChanged(const NumberVariable<double> &);
|
void RandomNumberStartChanged(const NumberVariable<double> &);
|
||||||
void RandomNumberEndChanged(const NumberVariable<double> &);
|
void RandomNumberEndChanged(const NumberVariable<double> &);
|
||||||
void GenerateIntegerChanged(int);
|
void GenerateIntegerChanged(int);
|
||||||
|
void RandomValueListChanged(const StringList &);
|
||||||
|
void AllowRepeatValuesChanged(int);
|
||||||
void JsonQueryChanged();
|
void JsonQueryChanged();
|
||||||
void JsonIndexChanged(const NumberVariable<int> &);
|
void JsonIndexChanged(const NumberVariable<int> &);
|
||||||
|
|
||||||
@@ -193,11 +203,10 @@ private:
|
|||||||
QLabel *_segmentValueStatus;
|
QLabel *_segmentValueStatus;
|
||||||
ResizingPlainTextEdit *_segmentValue;
|
ResizingPlainTextEdit *_segmentValue;
|
||||||
QVBoxLayout *_substringLayout;
|
QVBoxLayout *_substringLayout;
|
||||||
QHBoxLayout *_subStringIndexEntryLayout;
|
QHBoxLayout *_subStringControlsLayout;
|
||||||
QHBoxLayout *_subStringRegexEntryLayout;
|
|
||||||
VariableSpinBox *_subStringStart;
|
VariableSpinBox *_subStringStart;
|
||||||
VariableSpinBox *_subStringSize;
|
VariableSpinBox *_subStringSize;
|
||||||
RegexConfigWidget *_substringRegex;
|
RegexConfigWidget *_subStringRegex;
|
||||||
ResizingPlainTextEdit *_regexPattern;
|
ResizingPlainTextEdit *_regexPattern;
|
||||||
VariableSpinBox *_regexMatchIdx;
|
VariableSpinBox *_regexMatchIdx;
|
||||||
QHBoxLayout *_findReplaceLayout;
|
QHBoxLayout *_findReplaceLayout;
|
||||||
@@ -224,7 +233,10 @@ private:
|
|||||||
VariableDoubleSpinBox *_randomNumberStart;
|
VariableDoubleSpinBox *_randomNumberStart;
|
||||||
VariableDoubleSpinBox *_randomNumberEnd;
|
VariableDoubleSpinBox *_randomNumberEnd;
|
||||||
QCheckBox *_generateInteger;
|
QCheckBox *_generateInteger;
|
||||||
QVBoxLayout *_randomLayout;
|
QVBoxLayout *_randomNumberLayout;
|
||||||
|
StringListEdit *_randomValues;
|
||||||
|
QCheckBox *_allowRepeatValues;
|
||||||
|
QVBoxLayout *_randomValueLayout;
|
||||||
VariableLineEdit *_jsonQuery;
|
VariableLineEdit *_jsonQuery;
|
||||||
QLabel *_jsonQueryHelp;
|
QLabel *_jsonQueryHelp;
|
||||||
VariableSpinBox *_jsonIndex;
|
VariableSpinBox *_jsonIndex;
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ void DurationModifierEdit::Collapse(bool collapse)
|
|||||||
|
|
||||||
MacroConditionEdit::MacroConditionEdit(
|
MacroConditionEdit::MacroConditionEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
||||||
const std::string &id, bool isRootCondition)
|
bool isRootCondition)
|
||||||
: MacroSegmentEdit(parent),
|
: MacroSegmentEdit(parent),
|
||||||
_logicSelection(new QComboBox()),
|
_logicSelection(new QComboBox()),
|
||||||
_conditionSelection(new FilterComboBox()),
|
_conditionSelection(new FilterComboBox()),
|
||||||
@@ -239,7 +239,7 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
|||||||
(*_entryData)->SetIndex(idx);
|
(*_entryData)->SetIndex(idx);
|
||||||
(*_entryData)->SetLogicType(logic);
|
(*_entryData)->SetLogicType(logic);
|
||||||
(*_entryData)->PostLoad();
|
(*_entryData)->PostLoad();
|
||||||
RunPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
}
|
}
|
||||||
auto widget =
|
auto widget =
|
||||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||||
|
|||||||
@@ -34,11 +34,9 @@ class MacroConditionEdit : public MacroSegmentEdit {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MacroConditionEdit(
|
MacroConditionEdit(QWidget *parent = nullptr,
|
||||||
QWidget *parent = nullptr,
|
std::shared_ptr<MacroCondition> * = nullptr,
|
||||||
std::shared_ptr<MacroCondition> * = nullptr,
|
bool root = true);
|
||||||
const std::string &id = MacroCondition::GetDefaultID().data(),
|
|
||||||
bool root = true);
|
|
||||||
bool IsRootNode() const;
|
bool IsRootNode() const;
|
||||||
void SetRootNode(bool);
|
void SetRootNode(bool);
|
||||||
void SetupWidgets(bool basicSetup = false);
|
void SetupWidgets(bool basicSetup = false);
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ bool MacroConditionMacro::CheckActionStateCondition()
|
|||||||
if (!macro) {
|
if (!macro) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1, false)) {
|
if (!IsValidActionIndex(macro.get(), _actionIndex - 1)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (_type == Type::ACTION_DISABLED) {
|
if (_type == Type::ACTION_DISABLED) {
|
||||||
@@ -315,6 +315,7 @@ MacroConditionMacroEdit::MacroConditionMacroEdit(
|
|||||||
_actionIndex(new MacroSegmentSelection(
|
_actionIndex(new MacroSegmentSelection(
|
||||||
this, MacroSegmentSelection::Type::ACTION))
|
this, MacroSegmentSelection::Type::ACTION))
|
||||||
{
|
{
|
||||||
|
_macros->HideGroups();
|
||||||
_count->setMaximum(10000000);
|
_count->setMaximum(10000000);
|
||||||
populateTypeSelection(_types);
|
populateTypeSelection(_types);
|
||||||
populateCounterConditionSelection(_counterConditions);
|
populateCounterConditionSelection(_counterConditions);
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ void MacroDock::RunClicked()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ret = macro->PerformActions(true);
|
auto ret = macro->PerformActions(true, true, true);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
QString err =
|
QString err =
|
||||||
obs_module_text("AdvSceneSwitcher.macroTab.runFail");
|
obs_module_text("AdvSceneSwitcher.macroTab.runFail");
|
||||||
|
|||||||
@@ -418,8 +418,7 @@ void MacroEdit::PopulateMacroActions(Macro &m, uint32_t afterIdx)
|
|||||||
ui->actionsList->SetVisibilityCheckEnable(false);
|
ui->actionsList->SetVisibilityCheckEnable(false);
|
||||||
|
|
||||||
for (; afterIdx < actions.size(); afterIdx++) {
|
for (; afterIdx < actions.size(); afterIdx++) {
|
||||||
auto newEntry = new MacroActionEdit(this, &actions[afterIdx],
|
auto newEntry = new MacroActionEdit(this, &actions[afterIdx]);
|
||||||
actions[afterIdx]->GetId());
|
|
||||||
ui->actionsList->Add(newEntry);
|
ui->actionsList->Add(newEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,8 +443,7 @@ void MacroEdit::PopulateMacroElseActions(Macro &m, uint32_t afterIdx)
|
|||||||
ui->elseActionsList->SetVisibilityCheckEnable(false);
|
ui->elseActionsList->SetVisibilityCheckEnable(false);
|
||||||
|
|
||||||
for (; afterIdx < actions.size(); afterIdx++) {
|
for (; afterIdx < actions.size(); afterIdx++) {
|
||||||
auto newEntry = new MacroActionEdit(this, &actions[afterIdx],
|
auto newEntry = new MacroActionEdit(this, &actions[afterIdx]);
|
||||||
actions[afterIdx]->GetId());
|
|
||||||
ui->elseActionsList->Add(newEntry);
|
ui->elseActionsList->Add(newEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,8 +470,7 @@ void MacroEdit::PopulateMacroConditions(Macro &m, uint32_t afterIdx)
|
|||||||
|
|
||||||
for (; afterIdx < conditions.size(); afterIdx++) {
|
for (; afterIdx < conditions.size(); afterIdx++) {
|
||||||
auto newEntry = new MacroConditionEdit(
|
auto newEntry = new MacroConditionEdit(
|
||||||
this, &conditions[afterIdx],
|
this, &conditions[afterIdx], root);
|
||||||
conditions[afterIdx]->GetId(), root);
|
|
||||||
ui->conditionsList->Add(newEntry);
|
ui->conditionsList->Add(newEntry);
|
||||||
root = false;
|
root = false;
|
||||||
}
|
}
|
||||||
@@ -1080,11 +1077,10 @@ void MacroEdit::AddMacroAction(Macro *macro, int idx, const std::string &id,
|
|||||||
macro->Actions().at(idx)->Load(data);
|
macro->Actions().at(idx)->Load(data);
|
||||||
}
|
}
|
||||||
macro->Actions().at(idx)->PostLoad();
|
macro->Actions().at(idx)->PostLoad();
|
||||||
RunPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
macro->UpdateActionIndices();
|
macro->UpdateActionIndices();
|
||||||
ui->actionsList->Insert(
|
ui->actionsList->Insert(
|
||||||
idx,
|
idx, new MacroActionEdit(this, ¯o->Actions()[idx]));
|
||||||
new MacroActionEdit(this, ¯o->Actions()[idx], id));
|
|
||||||
SetActionData(*macro);
|
SetActionData(*macro);
|
||||||
}
|
}
|
||||||
HighlightAction(idx);
|
HighlightAction(idx);
|
||||||
@@ -1383,11 +1379,11 @@ void MacroEdit::AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
|||||||
macro->ElseActions().at(idx)->Load(data);
|
macro->ElseActions().at(idx)->Load(data);
|
||||||
}
|
}
|
||||||
macro->ElseActions().at(idx)->PostLoad();
|
macro->ElseActions().at(idx)->PostLoad();
|
||||||
RunPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
macro->UpdateElseActionIndices();
|
macro->UpdateElseActionIndices();
|
||||||
ui->elseActionsList->Insert(
|
ui->elseActionsList->Insert(
|
||||||
idx, new MacroActionEdit(
|
idx,
|
||||||
this, ¯o->ElseActions()[idx], id));
|
new MacroActionEdit(this, ¯o->ElseActions()[idx]));
|
||||||
SetElseActionData(*macro);
|
SetElseActionData(*macro);
|
||||||
}
|
}
|
||||||
HighlightElseAction(idx);
|
HighlightElseAction(idx);
|
||||||
@@ -1583,13 +1579,13 @@ void MacroEdit::AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
|||||||
macro->Conditions().at(idx)->Load(data);
|
macro->Conditions().at(idx)->Load(data);
|
||||||
}
|
}
|
||||||
macro->Conditions().at(idx)->PostLoad();
|
macro->Conditions().at(idx)->PostLoad();
|
||||||
RunPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
(*cond)->SetLogicType(logic);
|
(*cond)->SetLogicType(logic);
|
||||||
macro->UpdateConditionIndices();
|
macro->UpdateConditionIndices();
|
||||||
ui->conditionsList->Insert(
|
ui->conditionsList->Insert(
|
||||||
idx,
|
idx,
|
||||||
new MacroConditionEdit(this, ¯o->Conditions()[idx],
|
new MacroConditionEdit(this, ¯o->Conditions()[idx],
|
||||||
id, idx == 0));
|
idx == 0));
|
||||||
SetConditionData(*macro);
|
SetConditionData(*macro);
|
||||||
}
|
}
|
||||||
HighlightCondition(idx);
|
HighlightCondition(idx);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "macro-helpers.hpp"
|
#include "macro-helpers.hpp"
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
|
#include "macro-action-macro.hpp"
|
||||||
#include "plugin-state-helpers.hpp"
|
#include "plugin-state-helpers.hpp"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -8,6 +9,87 @@ static std::atomic_bool abortMacroWait = {false};
|
|||||||
static std::atomic_bool macroSceneSwitched = {false};
|
static std::atomic_bool macroSceneSwitched = {false};
|
||||||
static std::atomic_int shutdownConditionCount = {0};
|
static std::atomic_int shutdownConditionCount = {0};
|
||||||
|
|
||||||
|
static void appendNestedMacros(std::deque<std::shared_ptr<Macro>> ¯os,
|
||||||
|
Macro *macro)
|
||||||
|
{
|
||||||
|
if (!macro) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto iterate = [¯os](const std::deque<
|
||||||
|
std::shared_ptr<MacroAction>> &actions) {
|
||||||
|
for (const auto &action : actions) {
|
||||||
|
const auto nestedMacroAction =
|
||||||
|
dynamic_cast<MacroActionMacro *>(action.get());
|
||||||
|
if (!nestedMacroAction) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
macros.push_back(nestedMacroAction->_nestedMacro);
|
||||||
|
appendNestedMacros(
|
||||||
|
macros, nestedMacroAction->_nestedMacro.get());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
iterate(macro->Actions());
|
||||||
|
iterate(macro->ElseActions());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::deque<std::shared_ptr<Macro>> &GetTopLevelMacros()
|
||||||
|
{
|
||||||
|
static std::deque<std::shared_ptr<Macro>> macros;
|
||||||
|
return macros;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::deque<std::shared_ptr<Macro>> &GetTemporaryMacros()
|
||||||
|
{
|
||||||
|
static std::deque<std::shared_ptr<Macro>> tempMacros;
|
||||||
|
return tempMacros;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::deque<std::shared_ptr<Macro>> GetAllMacros()
|
||||||
|
{
|
||||||
|
auto macros = GetTopLevelMacros();
|
||||||
|
for (const auto &topLevelMacro : macros) {
|
||||||
|
appendNestedMacros(macros, topLevelMacro.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &tempMacros = GetTemporaryMacros();
|
||||||
|
macros.insert(macros.end(), tempMacros.begin(), tempMacros.end());
|
||||||
|
for (const auto &tempMacro : tempMacros) {
|
||||||
|
appendNestedMacros(macros, tempMacro.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return macros;
|
||||||
|
}
|
||||||
|
|
||||||
|
Macro *GetMacroByName(const char *name)
|
||||||
|
{
|
||||||
|
for (const auto &m : GetTopLevelMacros()) {
|
||||||
|
if (m->Name() == name) {
|
||||||
|
return m.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Macro *GetMacroByQString(const QString &name)
|
||||||
|
{
|
||||||
|
return GetMacroByName(name.toUtf8().constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Macro> GetWeakMacroByName(const char *name)
|
||||||
|
{
|
||||||
|
for (const auto &m : GetTopLevelMacros()) {
|
||||||
|
if (m->Name() == name) {
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::deque<std::shared_ptr<MacroAction>>>
|
std::optional<std::deque<std::shared_ptr<MacroAction>>>
|
||||||
GetMacroActions(Macro *macro)
|
GetMacroActions(Macro *macro)
|
||||||
{
|
{
|
||||||
@@ -17,6 +99,15 @@ GetMacroActions(Macro *macro)
|
|||||||
return macro->Actions();
|
return macro->Actions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::deque<std::shared_ptr<MacroAction>>>
|
||||||
|
GetMacroElseActions(Macro *macro)
|
||||||
|
{
|
||||||
|
if (!macro) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return macro->ElseActions();
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::deque<std::shared_ptr<MacroCondition>>>
|
std::optional<std::deque<std::shared_ptr<MacroCondition>>>
|
||||||
GetMacroConditions(Macro *macro)
|
GetMacroConditions(Macro *macro)
|
||||||
{
|
{
|
||||||
@@ -26,9 +117,32 @@ GetMacroConditions(Macro *macro)
|
|||||||
return macro->Conditions();
|
return macro->Conditions();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string_view GetSceneSwitchActionId()
|
bool IsGroupMacro(Macro *macro)
|
||||||
{
|
{
|
||||||
return MacroAction::GetDefaultID();
|
return macro && macro->IsGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Macro>> GetGroupMacroEntries(Macro *macro)
|
||||||
|
{
|
||||||
|
if (!macro || !macro->IsGroup()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::shared_ptr<Macro>> entries;
|
||||||
|
entries.reserve(macro->GroupSize());
|
||||||
|
|
||||||
|
const auto ¯os = GetTopLevelMacros();
|
||||||
|
for (auto it = macros.begin(); it < macros.end(); it++) {
|
||||||
|
if ((*it)->Name() != macro->Name()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (uint32_t i = 1; i <= macro->GroupSize(); i++) {
|
||||||
|
entries.emplace_back(*std::next(it, i));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::condition_variable &GetMacroWaitCV()
|
std::condition_variable &GetMacroWaitCV()
|
||||||
@@ -128,6 +242,11 @@ bool RunMacroActions(Macro *macro)
|
|||||||
return macro && macro->PerformActions(true);
|
return macro && macro->PerformActions(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RunMacroElseActions(Macro *macro)
|
||||||
|
{
|
||||||
|
return macro && macro->PerformActions(false);
|
||||||
|
}
|
||||||
|
|
||||||
void ResetMacroConditionTimers(Macro *macro)
|
void ResetMacroConditionTimers(Macro *macro)
|
||||||
{
|
{
|
||||||
if (!macro) {
|
if (!macro) {
|
||||||
@@ -144,20 +263,42 @@ void ResetMacroRunCount(Macro *macro)
|
|||||||
macro->ResetRunCount();
|
macro->ResetRunCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValidMacroSegmentIndex(const Macro *m, const int idx, bool isCondition)
|
bool IsValidActionIndex(const Macro *m, const int idx)
|
||||||
{
|
{
|
||||||
if (!m || idx < 0) {
|
if (!m || idx < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (isCondition) {
|
|
||||||
if (idx >= (int)m->Conditions().size()) {
|
if (idx >= (int)m->Actions().size()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (idx >= (int)m->Actions().size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValidElseActionIndex(const Macro *m, const int idx)
|
||||||
|
{
|
||||||
|
if (!m || idx < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx >= (int)m->ElseActions().size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsValidConditionIndex(const Macro *m, const int idx)
|
||||||
|
{
|
||||||
|
if (!m || idx < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx >= (int)m->Conditions().size()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "export-symbol-helper.hpp"
|
#include "export-symbol-helper.hpp"
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
struct obs_data;
|
struct obs_data;
|
||||||
@@ -18,16 +19,25 @@ class Macro;
|
|||||||
class MacroAction;
|
class MacroAction;
|
||||||
class MacroCondition;
|
class MacroCondition;
|
||||||
|
|
||||||
EXPORT std::deque<std::shared_ptr<Macro>> &GetMacros();
|
static const int macro_func = 10;
|
||||||
|
|
||||||
|
EXPORT std::deque<std::shared_ptr<Macro>> &GetTopLevelMacros();
|
||||||
|
std::deque<std::shared_ptr<Macro>> &GetTemporaryMacros();
|
||||||
|
EXPORT std::deque<std::shared_ptr<Macro>> GetAllMacros();
|
||||||
|
|
||||||
|
Macro *GetMacroByName(const char *name);
|
||||||
|
Macro *GetMacroByQString(const QString &name);
|
||||||
|
std::weak_ptr<Macro> GetWeakMacroByName(const char *name);
|
||||||
|
|
||||||
EXPORT std::optional<std::deque<std::shared_ptr<MacroAction>>>
|
EXPORT std::optional<std::deque<std::shared_ptr<MacroAction>>>
|
||||||
GetMacroActions(Macro *);
|
GetMacroActions(Macro *);
|
||||||
|
EXPORT std::optional<std::deque<std::shared_ptr<MacroAction>>>
|
||||||
|
GetMacroElseActions(Macro *);
|
||||||
EXPORT std::optional<std::deque<std::shared_ptr<MacroCondition>>>
|
EXPORT std::optional<std::deque<std::shared_ptr<MacroCondition>>>
|
||||||
GetMacroConditions(Macro *);
|
GetMacroConditions(Macro *);
|
||||||
|
|
||||||
std::string_view GetSceneSwitchActionId();
|
EXPORT bool IsGroupMacro(Macro *);
|
||||||
|
EXPORT std::vector<std::shared_ptr<Macro>> GetGroupMacroEntries(Macro *);
|
||||||
constexpr auto macro_func = 10;
|
|
||||||
|
|
||||||
EXPORT std::condition_variable &GetMacroWaitCV();
|
EXPORT std::condition_variable &GetMacroWaitCV();
|
||||||
EXPORT std::condition_variable &GetMacroTransitionCV();
|
EXPORT std::condition_variable &GetMacroTransitionCV();
|
||||||
@@ -58,6 +68,7 @@ EXPORT void AddMacroHelperThread(Macro *, std::thread &&);
|
|||||||
EXPORT bool CheckMacros();
|
EXPORT bool CheckMacros();
|
||||||
|
|
||||||
EXPORT bool RunMacroActions(Macro *);
|
EXPORT bool RunMacroActions(Macro *);
|
||||||
|
bool RunMacroElseActions(Macro *);
|
||||||
EXPORT bool RunMacros();
|
EXPORT bool RunMacros();
|
||||||
void StopAllMacros();
|
void StopAllMacros();
|
||||||
|
|
||||||
@@ -68,6 +79,8 @@ EXPORT void InvalidateMacroTempVarValues();
|
|||||||
EXPORT void ResetMacroConditionTimers(Macro *);
|
EXPORT void ResetMacroConditionTimers(Macro *);
|
||||||
EXPORT void ResetMacroRunCount(Macro *);
|
EXPORT void ResetMacroRunCount(Macro *);
|
||||||
|
|
||||||
bool IsValidMacroSegmentIndex(const Macro *m, const int idx, bool isCondition);
|
bool IsValidActionIndex(const Macro *m, const int idx);
|
||||||
|
bool IsValidElseActionIndex(const Macro *m, const int idx);
|
||||||
|
bool IsValidConditionIndex(const Macro *m, const int idx);
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
323
lib/macro/macro-search.cpp
Normal file
323
lib/macro/macro-search.cpp
Normal file
@@ -0,0 +1,323 @@
|
|||||||
|
#include "macro-search.hpp"
|
||||||
|
#include "layout-helpers.hpp"
|
||||||
|
#include "macro.hpp"
|
||||||
|
#include "macro-action-factory.hpp"
|
||||||
|
#include "macro-condition-factory.hpp"
|
||||||
|
#include "macro-helpers.hpp"
|
||||||
|
#include "macro-signals.hpp"
|
||||||
|
#include "plugin-state-helpers.hpp"
|
||||||
|
#include "ui-helpers.hpp"
|
||||||
|
|
||||||
|
#include <obs.hpp>
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QLayout>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
static bool searchEnabled = false;
|
||||||
|
static bool setup();
|
||||||
|
static bool setupDone = setup();
|
||||||
|
|
||||||
|
static QLayout *searchLayout = nullptr;
|
||||||
|
static QComboBox *searchType = nullptr;
|
||||||
|
static RegexConfigWidget *searchRegex = nullptr;
|
||||||
|
static QPushButton *showSettings = nullptr;
|
||||||
|
static std::function<void()> refreshFilter;
|
||||||
|
|
||||||
|
static void save(obs_data_t *data)
|
||||||
|
{
|
||||||
|
GetMacroSearchSettings().Save(data, "macroSearchSettings");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load(obs_data_t *data)
|
||||||
|
{
|
||||||
|
GetMacroSearchSettings().Load(data, "macroSearchSettings");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setup()
|
||||||
|
{
|
||||||
|
AddSaveStep(save);
|
||||||
|
AddLoadStep(load);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroSearchSettings::Save(obs_data_t *data, const char *name)
|
||||||
|
{
|
||||||
|
OBSDataAutoRelease settings = obs_data_create();
|
||||||
|
obs_data_set_bool(settings, "showAlways", showAlways);
|
||||||
|
obs_data_set_int(settings, "searchType", static_cast<int>(searchType));
|
||||||
|
obs_data_set_string(settings, "searchString", searchString.c_str());
|
||||||
|
regex.Save(settings);
|
||||||
|
obs_data_set_obj(data, name, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroSearchSettings::Load(obs_data_t *data, const char *name)
|
||||||
|
{
|
||||||
|
OBSDataAutoRelease settings = obs_data_get_obj(data, name);
|
||||||
|
showAlways = obs_data_get_bool(settings, "showAlways");
|
||||||
|
searchType = static_cast<SearchType>(
|
||||||
|
obs_data_get_int(settings, "searchType"));
|
||||||
|
searchString = obs_data_get_string(settings, "searchString");
|
||||||
|
regex.Load(settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void showAdvancedSearchSettings(bool show)
|
||||||
|
{
|
||||||
|
assert(searchType);
|
||||||
|
assert(searchRegex);
|
||||||
|
|
||||||
|
searchType->setVisible(show);
|
||||||
|
searchRegex->setVisible(show);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool shouldShowSearch()
|
||||||
|
{
|
||||||
|
static const int showSearchThreshold = 10;
|
||||||
|
return GetMacroSearchSettings().showAlways ||
|
||||||
|
GetTopLevelMacros().size() >= showSearchThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckMacroSearchVisibility()
|
||||||
|
{
|
||||||
|
assert(searchLayout);
|
||||||
|
assert(searchType);
|
||||||
|
assert(searchRegex);
|
||||||
|
assert(showSettings);
|
||||||
|
|
||||||
|
searchEnabled = shouldShowSearch();
|
||||||
|
SetLayoutVisible(searchLayout, searchEnabled);
|
||||||
|
showAdvancedSearchSettings(false);
|
||||||
|
showSettings->setChecked(false);
|
||||||
|
refreshFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupMacroSearchWidgets(QLayout *searchLayoutArg, QLineEdit *searchText,
|
||||||
|
QPushButton *searchClear, QComboBox *searchTypeArg,
|
||||||
|
RegexConfigWidget *searchRegexArg,
|
||||||
|
QPushButton *showSettingsArg,
|
||||||
|
const std::function<void()> &refreshArg)
|
||||||
|
{
|
||||||
|
searchLayout = searchLayoutArg;
|
||||||
|
searchType = searchTypeArg;
|
||||||
|
searchRegex = searchRegexArg;
|
||||||
|
refreshFilter = refreshArg;
|
||||||
|
showSettings = showSettingsArg;
|
||||||
|
|
||||||
|
searchClear->setMaximumWidth(22);
|
||||||
|
SetButtonIcon(searchClear, GetThemeTypeName() == "Light"
|
||||||
|
? "theme:Light/close.svg"
|
||||||
|
: "theme:Dark/close.svg");
|
||||||
|
searchClear->setDisabled(GetMacroSearchSettings().searchString.empty());
|
||||||
|
|
||||||
|
QWidget::connect(searchClear, &QPushButton::clicked, searchClear,
|
||||||
|
[=]() {
|
||||||
|
searchText->setText("");
|
||||||
|
searchClear->setDisabled(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto ph = searchText->placeholderText();
|
||||||
|
const QFontMetrics fm(searchText->font());
|
||||||
|
const int width = fm.horizontalAdvance(ph);
|
||||||
|
// Add a little padding so the text isn't cramped
|
||||||
|
searchText->setMinimumWidth(width + 10);
|
||||||
|
|
||||||
|
searchText->setText(
|
||||||
|
QString::fromStdString(GetMacroSearchSettings().searchString));
|
||||||
|
QWidget::connect(searchText, &QLineEdit::textChanged, searchText,
|
||||||
|
[searchClear](const QString &text) {
|
||||||
|
GetMacroSearchSettings().searchString =
|
||||||
|
text.toStdString();
|
||||||
|
searchClear->setDisabled(text.isEmpty());
|
||||||
|
refreshFilter();
|
||||||
|
});
|
||||||
|
|
||||||
|
searchType->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.macroTab.search.name"),
|
||||||
|
static_cast<int>(MacroSearchSettings::SearchType::NAME));
|
||||||
|
searchType->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.macroTab.search.allSegments"),
|
||||||
|
static_cast<int>(
|
||||||
|
MacroSearchSettings::SearchType::ALL_SEGMENTS));
|
||||||
|
searchType->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.macroTab.search.conditions"),
|
||||||
|
static_cast<int>(MacroSearchSettings::SearchType::CONDITIONS));
|
||||||
|
searchType->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.macroTab.search.actions"),
|
||||||
|
static_cast<int>(MacroSearchSettings::SearchType::ACTIONS));
|
||||||
|
searchType->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.macroTab.search.label"),
|
||||||
|
static_cast<int>(MacroSearchSettings::SearchType::LABEL));
|
||||||
|
searchType->setCurrentIndex(searchType->findData(
|
||||||
|
static_cast<int>(GetMacroSearchSettings().searchType)));
|
||||||
|
QWidget::connect(
|
||||||
|
searchType, &QComboBox::currentIndexChanged, searchType, []() {
|
||||||
|
GetMacroSearchSettings().searchType =
|
||||||
|
static_cast<MacroSearchSettings::SearchType>(
|
||||||
|
searchType->currentData().toInt());
|
||||||
|
refreshFilter();
|
||||||
|
});
|
||||||
|
|
||||||
|
searchRegex->SetRegexConfig(GetMacroSearchSettings().regex);
|
||||||
|
QWidget::connect(searchRegex, &RegexConfigWidget::RegexConfigChanged,
|
||||||
|
searchRegex, [](const RegexConfig ®ex) {
|
||||||
|
GetMacroSearchSettings().regex = regex;
|
||||||
|
refreshFilter();
|
||||||
|
});
|
||||||
|
|
||||||
|
showSettings->setCheckable(true);
|
||||||
|
showSettings->setMaximumWidth(11);
|
||||||
|
SetButtonIcon(showSettings, GetThemeTypeName() == "Light"
|
||||||
|
? ":/res/images/dots-vert.svg"
|
||||||
|
: "theme:Dark/dots-vert.svg");
|
||||||
|
QWidget::connect(showSettings, &QPushButton::toggled, showSettings,
|
||||||
|
showAdvancedSearchSettings);
|
||||||
|
|
||||||
|
QWidget::connect(MacroSignalManager::Instance(),
|
||||||
|
&MacroSignalManager::Rename, searchText,
|
||||||
|
[]() { refreshFilter(); });
|
||||||
|
|
||||||
|
CheckMacroSearchVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroSearchSettings &GetMacroSearchSettings()
|
||||||
|
{
|
||||||
|
static MacroSearchSettings settings;
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool stringMatches(const std::string &text)
|
||||||
|
{
|
||||||
|
const auto &settings = GetMacroSearchSettings();
|
||||||
|
const auto ®ex = settings.regex;
|
||||||
|
const auto &searchString = settings.searchString;
|
||||||
|
|
||||||
|
if (regex.Enabled()) {
|
||||||
|
return regex.Matches(text, searchString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return QString::fromStdString(text).contains(
|
||||||
|
QString::fromStdString(searchString), Qt::CaseInsensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool segmentTypeMatches(MacroSegment *segment, bool isCondition)
|
||||||
|
{
|
||||||
|
if (!segment) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto getNameFromId =
|
||||||
|
isCondition ? MacroConditionFactory::GetConditionName
|
||||||
|
: MacroActionFactory::GetActionName;
|
||||||
|
const auto name = getNameFromId(segment->GetId());
|
||||||
|
return stringMatches(obs_module_text(name.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool segmentLabelMatches(MacroSegment *segment)
|
||||||
|
{
|
||||||
|
if (!segment) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!segment->GetUseCustomLabel()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto label = segment->GetCustomLabel();
|
||||||
|
return stringMatches(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroMatchesSearchFilter(Macro *macro)
|
||||||
|
{
|
||||||
|
assert(macro);
|
||||||
|
|
||||||
|
if (!searchEnabled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &settings = GetMacroSearchSettings();
|
||||||
|
|
||||||
|
if (settings.searchString.empty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (macro->IsGroup()) {
|
||||||
|
const auto groupEntries = GetGroupMacroEntries(macro);
|
||||||
|
for (const auto &entry : groupEntries) {
|
||||||
|
if (MacroMatchesSearchFilter(entry.get())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (settings.searchType) {
|
||||||
|
case MacroSearchSettings::SearchType::NAME: {
|
||||||
|
const auto name = macro->Name();
|
||||||
|
return stringMatches(name);
|
||||||
|
}
|
||||||
|
case MacroSearchSettings::SearchType::ALL_SEGMENTS:
|
||||||
|
for (const auto &condition : macro->Conditions()) {
|
||||||
|
if (segmentTypeMatches(condition.get(), true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto &action : macro->Actions()) {
|
||||||
|
if (segmentTypeMatches(action.get(), false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto &action : macro->ElseActions()) {
|
||||||
|
if (segmentTypeMatches(action.get(), false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case MacroSearchSettings::SearchType::CONDITIONS:
|
||||||
|
for (const auto &condition : macro->Conditions()) {
|
||||||
|
if (segmentTypeMatches(condition.get(), true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case MacroSearchSettings::SearchType::ACTIONS:
|
||||||
|
for (const auto &action : macro->Actions()) {
|
||||||
|
if (segmentTypeMatches(action.get(), false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto &action : macro->ElseActions()) {
|
||||||
|
if (segmentTypeMatches(action.get(), false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
case MacroSearchSettings::SearchType::LABEL:
|
||||||
|
for (const auto &condition : macro->Conditions()) {
|
||||||
|
if (segmentLabelMatches(condition.get())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto &action : macro->Actions()) {
|
||||||
|
if (segmentLabelMatches(action.get())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto &action : macro->ElseActions()) {
|
||||||
|
if (segmentLabelMatches(action.get())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unhandled search type
|
||||||
|
assert(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
43
lib/macro/macro-search.hpp
Normal file
43
lib/macro/macro-search.hpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "regex-config.hpp"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class QComboBox;
|
||||||
|
class QLayout;
|
||||||
|
class QLineEdit;
|
||||||
|
class QPushButton;
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
class Macro;
|
||||||
|
|
||||||
|
struct MacroSearchSettings {
|
||||||
|
void Save(obs_data_t *data, const char *name);
|
||||||
|
void Load(obs_data_t *data, const char *name);
|
||||||
|
|
||||||
|
enum class SearchType {
|
||||||
|
NAME = 0,
|
||||||
|
ALL_SEGMENTS = 10,
|
||||||
|
CONDITIONS = 20,
|
||||||
|
ACTIONS = 30,
|
||||||
|
LABEL = 40,
|
||||||
|
};
|
||||||
|
|
||||||
|
SearchType searchType = SearchType::NAME;
|
||||||
|
std::string searchString;
|
||||||
|
RegexConfig regex;
|
||||||
|
bool showAlways = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
void CheckMacroSearchVisibility();
|
||||||
|
void SetupMacroSearchWidgets(QLayout *searchLayout, QLineEdit *searchText,
|
||||||
|
QPushButton *searchClear, QComboBox *searchType,
|
||||||
|
RegexConfigWidget *searchRegex,
|
||||||
|
QPushButton *showSettings,
|
||||||
|
const std::function<void()> &refresh);
|
||||||
|
MacroSearchSettings &GetMacroSearchSettings();
|
||||||
|
bool MacroMatchesSearchFilter(Macro *macro);
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -73,35 +73,46 @@ void MacroSegmentSelection::MacroSegmentOrderChanged()
|
|||||||
}
|
}
|
||||||
|
|
||||||
static QString GetMacroSegmentDescription(Macro *macro, int idx,
|
static QString GetMacroSegmentDescription(Macro *macro, int idx,
|
||||||
bool isCondition)
|
MacroSegmentSelection::Type type)
|
||||||
{
|
{
|
||||||
if (!macro) {
|
if (!macro) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
if (!IsValidMacroSegmentIndex(macro, idx, isCondition)) {
|
|
||||||
|
MacroSegment *segment;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case MacroSegmentSelection::Type::CONDITION:
|
||||||
|
if (!IsValidConditionIndex(macro, idx)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
segment = GetMacroConditions(macro)->at(idx).get();
|
||||||
|
break;
|
||||||
|
case MacroSegmentSelection::Type::ACTION:
|
||||||
|
if (!IsValidActionIndex(macro, idx)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
segment = GetMacroActions(macro)->at(idx).get();
|
||||||
|
break;
|
||||||
|
case MacroSegmentSelection::Type::ELSE_ACTION:
|
||||||
|
if (!IsValidElseActionIndex(macro, idx)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
segment = GetMacroElseActions(macro)->at(idx).get();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroSegment *segment;
|
const auto idToName = type == MacroSegmentSelection::Type::CONDITION
|
||||||
if (isCondition) {
|
? MacroConditionFactory::GetConditionName
|
||||||
segment = GetMacroConditions(macro)->at(idx).get();
|
: MacroActionFactory::GetActionName;
|
||||||
} else {
|
const QString typeStr =
|
||||||
segment = GetMacroActions(macro)->at(idx).get();
|
obs_module_text(idToName(segment->GetId()).c_str());
|
||||||
}
|
const QString description =
|
||||||
|
QString::fromStdString(segment->GetShortDesc());
|
||||||
|
|
||||||
QString description = QString::fromStdString(segment->GetShortDesc());
|
QString result = typeStr;
|
||||||
QString type;
|
|
||||||
if (isCondition) {
|
|
||||||
type = obs_module_text(MacroConditionFactory::GetConditionName(
|
|
||||||
segment->GetId())
|
|
||||||
.c_str());
|
|
||||||
} else {
|
|
||||||
type = obs_module_text(
|
|
||||||
MacroActionFactory::GetActionName(segment->GetId())
|
|
||||||
.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
QString result = type;
|
|
||||||
if (!description.isEmpty()) {
|
if (!description.isEmpty()) {
|
||||||
result += ": " + description;
|
result += ": " + description;
|
||||||
}
|
}
|
||||||
@@ -123,11 +134,25 @@ void MacroSegmentSelection::SetupDescription() const
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool validIndex = false;
|
||||||
|
switch (_type) {
|
||||||
|
case Type::CONDITION:
|
||||||
|
validIndex = IsValidConditionIndex(_macro, index - 1);
|
||||||
|
break;
|
||||||
|
case Type::ACTION:
|
||||||
|
validIndex = IsValidActionIndex(_macro, index - 1);
|
||||||
|
break;
|
||||||
|
case Type::ELSE_ACTION:
|
||||||
|
validIndex = IsValidElseActionIndex(_macro, index - 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
QString description;
|
QString description;
|
||||||
if (IsValidMacroSegmentIndex(_macro, index - 1,
|
if (validIndex) {
|
||||||
_type == Type::CONDITION)) {
|
description =
|
||||||
description = GetMacroSegmentDescription(
|
GetMacroSegmentDescription(_macro, index - 1, _type);
|
||||||
_macro, index - 1, _type == Type::CONDITION);
|
|
||||||
} else {
|
} else {
|
||||||
description = obs_module_text(
|
description = obs_module_text(
|
||||||
"AdvSceneSwitcher.macroSegmentSelection.invalid");
|
"AdvSceneSwitcher.macroSegmentSelection.invalid");
|
||||||
@@ -165,8 +190,23 @@ void MacroSegmentSelection::MarkSelectedSegment()
|
|||||||
if (index.GetType() == IntVariable::Type::VARIABLE) {
|
if (index.GetType() == IntVariable::Type::VARIABLE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!IsValidMacroSegmentIndex(_macro, index - 1,
|
|
||||||
_type == Type::CONDITION)) {
|
bool validIndex = false;
|
||||||
|
switch (_type) {
|
||||||
|
case Type::CONDITION:
|
||||||
|
validIndex = IsValidConditionIndex(_macro, index - 1);
|
||||||
|
break;
|
||||||
|
case Type::ACTION:
|
||||||
|
validIndex = IsValidActionIndex(_macro, index - 1);
|
||||||
|
break;
|
||||||
|
case Type::ELSE_ACTION:
|
||||||
|
validIndex = IsValidElseActionIndex(_macro, index - 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!validIndex) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class Macro;
|
|||||||
class MacroSegmentSelection : public QWidget {
|
class MacroSegmentSelection : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum class Type { CONDITION, ACTION };
|
enum class Type { CONDITION, ACTION, ELSE_ACTION };
|
||||||
|
|
||||||
MacroSegmentSelection(QWidget *parent, Type type,
|
MacroSegmentSelection(QWidget *parent, Type type,
|
||||||
bool allowVariables = true);
|
bool allowVariables = true);
|
||||||
|
|||||||
@@ -14,10 +14,7 @@ MacroSelection::MacroSelection(QWidget *parent)
|
|||||||
: FilterComboBox(parent,
|
: FilterComboBox(parent,
|
||||||
obs_module_text("AdvSceneSwitcher.selectMacro"))
|
obs_module_text("AdvSceneSwitcher.selectMacro"))
|
||||||
{
|
{
|
||||||
for (const auto &m : GetMacros()) {
|
for (const auto &m : GetTopLevelMacros()) {
|
||||||
if (m->IsGroup()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
addItem(QString::fromStdString(m->Name()));
|
addItem(QString::fromStdString(m->Name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +63,22 @@ void MacroSelection::HideSelectedMacro()
|
|||||||
qobject_cast<QListView *>(view())->setRowHidden(idx, true);
|
qobject_cast<QListView *>(view())->setRowHidden(idx, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroSelection::HideGroups()
|
||||||
|
{
|
||||||
|
for (const auto ¯o : GetTopLevelMacros()) {
|
||||||
|
if (!macro->IsGroup()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = findText(QString::fromStdString(macro->Name()));
|
||||||
|
if (idx == -1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
qobject_cast<QListView *>(view())->setRowHidden(idx, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MacroSelection::ShowAllMacros()
|
void MacroSelection::ShowAllMacros()
|
||||||
{
|
{
|
||||||
auto v = qobject_cast<QListView *>(view());
|
auto v = qobject_cast<QListView *>(view());
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ public:
|
|||||||
MacroSelection(QWidget *parent);
|
MacroSelection(QWidget *parent);
|
||||||
void SetCurrentMacro(const MacroRef &);
|
void SetCurrentMacro(const MacroRef &);
|
||||||
void HideSelectedMacro(); // Macro currently being edited
|
void HideSelectedMacro(); // Macro currently being edited
|
||||||
|
void HideGroups();
|
||||||
void ShowAllMacros();
|
void ShowAllMacros();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "macro-condition-edit.hpp"
|
#include "macro-condition-edit.hpp"
|
||||||
#include "macro-export-import-dialog.hpp"
|
#include "macro-export-import-dialog.hpp"
|
||||||
#include "macro-settings.hpp"
|
#include "macro-settings.hpp"
|
||||||
|
#include "macro-search.hpp"
|
||||||
#include "macro-signals.hpp"
|
#include "macro-signals.hpp"
|
||||||
#include "macro-tree.hpp"
|
#include "macro-tree.hpp"
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
@@ -24,6 +25,8 @@ namespace advss {
|
|||||||
|
|
||||||
static QObject *addPulse = nullptr;
|
static QObject *addPulse = nullptr;
|
||||||
static QTimer onChangeHighlightTimer;
|
static QTimer onChangeHighlightTimer;
|
||||||
|
static std::chrono::high_resolution_clock::time_point
|
||||||
|
lastOnChangeHighlightCheckTime{};
|
||||||
|
|
||||||
static void disableAddButtonHighlight()
|
static void disableAddButtonHighlight()
|
||||||
{
|
{
|
||||||
@@ -146,20 +149,7 @@ void AdvSceneSwitcher::on_macroAdd_clicked()
|
|||||||
static void addGroupSubitems(std::vector<std::shared_ptr<Macro>> ¯os,
|
static void addGroupSubitems(std::vector<std::shared_ptr<Macro>> ¯os,
|
||||||
const std::shared_ptr<Macro> &group)
|
const std::shared_ptr<Macro> &group)
|
||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<Macro>> subitems;
|
auto subitems = GetGroupMacroEntries(group.get());
|
||||||
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
|
// Remove subitems which were already selected to avoid duplicates
|
||||||
for (const auto &subitem : subitems) {
|
for (const auto &subitem : subitems) {
|
||||||
@@ -207,7 +197,7 @@ void AdvSceneSwitcher::RemoveMacro(std::shared_ptr<Macro> ¯o)
|
|||||||
// Don't cache widgets for about to be deleted macros
|
// Don't cache widgets for about to be deleted macros
|
||||||
MacroSegmentList::SetCachingEnabled(false);
|
MacroSegmentList::SetCachingEnabled(false);
|
||||||
ui->macros->Remove(macro);
|
ui->macros->Remove(macro);
|
||||||
MacroSegmentList::SetCachingEnabled(!switcher->disableMacroWidgetCache);
|
MacroSegmentList::SetCachingEnabled(true);
|
||||||
|
|
||||||
MacroSignalManager::Instance()->Remove(name);
|
MacroSignalManager::Instance()->Remove(name);
|
||||||
}
|
}
|
||||||
@@ -410,13 +400,17 @@ void AdvSceneSwitcher::ImportMacros()
|
|||||||
int groupSize = 0;
|
int groupSize = 0;
|
||||||
std::shared_ptr<Macro> group;
|
std::shared_ptr<Macro> group;
|
||||||
std::vector<std::shared_ptr<Macro>> importedMacros;
|
std::vector<std::shared_ptr<Macro>> importedMacros;
|
||||||
|
auto &tempMacros = GetTemporaryMacros();
|
||||||
|
|
||||||
auto lock = LockContext();
|
auto lock = LockContext();
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
tempMacros.clear();
|
||||||
|
|
||||||
OBSDataAutoRelease array_obj = obs_data_array_item(array, i);
|
OBSDataAutoRelease array_obj = obs_data_array_item(array, i);
|
||||||
auto macro = std::make_shared<Macro>();
|
auto macro = std::make_shared<Macro>();
|
||||||
|
tempMacros.emplace_back(macro);
|
||||||
macro->Load(array_obj);
|
macro->Load(array_obj);
|
||||||
RunPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
|
|
||||||
if (macroNameExists(macro->Name()) &&
|
if (macroNameExists(macro->Name()) &&
|
||||||
!ResolveMacroImportNameConflict(macro)) {
|
!ResolveMacroImportNameConflict(macro)) {
|
||||||
@@ -425,7 +419,7 @@ void AdvSceneSwitcher::ImportMacros()
|
|||||||
}
|
}
|
||||||
|
|
||||||
importedMacros.emplace_back(macro);
|
importedMacros.emplace_back(macro);
|
||||||
GetMacros().emplace_back(macro);
|
GetTopLevelMacros().emplace_back(macro);
|
||||||
if (groupSize > 0 && !macro->IsGroup()) {
|
if (groupSize > 0 && !macro->IsGroup()) {
|
||||||
Macro::PrepareMoveToGroup(group, macro);
|
Macro::PrepareMoveToGroup(group, macro);
|
||||||
groupSize--;
|
groupSize--;
|
||||||
@@ -444,9 +438,10 @@ void AdvSceneSwitcher::ImportMacros()
|
|||||||
for (const auto ¯o : importedMacros) {
|
for (const auto ¯o : importedMacros) {
|
||||||
macro->PostLoad();
|
macro->PostLoad();
|
||||||
}
|
}
|
||||||
RunPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
|
tempMacros.clear();
|
||||||
|
|
||||||
ui->macros->Reset(GetMacros(),
|
ui->macros->Reset(GetTopLevelMacros(),
|
||||||
GetGlobalMacroSettings()._highlightExecuted);
|
GetGlobalMacroSettings()._highlightExecuted);
|
||||||
disableAddButtonHighlight();
|
disableAddButtonHighlight();
|
||||||
}
|
}
|
||||||
@@ -557,10 +552,14 @@ void AdvSceneSwitcher::HighlightOnChange() const
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (macro->OnChangePreventedActionsRecently()) {
|
if (macro->OnChangePreventedActionsSince(
|
||||||
|
lastOnChangeHighlightCheckTime)) {
|
||||||
HighlightWidget(ui->runMacroOnChange, Qt::yellow,
|
HighlightWidget(ui->runMacroOnChange, Qt::yellow,
|
||||||
Qt::transparent, true);
|
Qt::transparent, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastOnChangeHighlightCheckTime =
|
||||||
|
std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_macroSettings_clicked()
|
void AdvSceneSwitcher::on_macroSettings_clicked()
|
||||||
@@ -610,17 +609,20 @@ setupToolBar(const std::initializer_list<std::initializer_list<QWidget *>>
|
|||||||
auto toolbar = new QToolBar();
|
auto toolbar = new QToolBar();
|
||||||
toolbar->setIconSize({16, 16});
|
toolbar->setIconSize({16, 16});
|
||||||
|
|
||||||
QAction *lastSeperator = nullptr;
|
QAction *lastSeparator = nullptr;
|
||||||
|
|
||||||
for (const auto &widgetGroup : widgetGroups) {
|
for (const auto &widgetGroup : widgetGroups) {
|
||||||
for (const auto &widget : widgetGroup) {
|
for (const auto &widget : widgetGroup) {
|
||||||
|
if (!widget) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
toolbar->addWidget(widget);
|
toolbar->addWidget(widget);
|
||||||
}
|
}
|
||||||
lastSeperator = toolbar->addSeparator();
|
lastSeparator = toolbar->addSeparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastSeperator) {
|
if (lastSeparator) {
|
||||||
toolbar->removeAction(lastSeperator);
|
toolbar->removeAction(lastSeparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prevent "extension" button from showing up
|
// Prevent "extension" button from showing up
|
||||||
@@ -633,7 +635,9 @@ void AdvSceneSwitcher::SetupMacroTab()
|
|||||||
{
|
{
|
||||||
ui->macros->installEventFilter(this);
|
ui->macros->installEventFilter(this);
|
||||||
|
|
||||||
if (GetMacros().size() == 0 && !switcher->disableHints) {
|
auto ¯os = GetTopLevelMacros();
|
||||||
|
|
||||||
|
if (macros.size() == 0 && !switcher->disableHints) {
|
||||||
addPulse = HighlightWidget(ui->macroAdd, QColor(Qt::green));
|
addPulse = HighlightWidget(ui->macroAdd, QColor(Qt::green));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,8 +645,7 @@ void AdvSceneSwitcher::SetupMacroTab()
|
|||||||
{ui->macroUp, ui->macroDown}});
|
{ui->macroUp, ui->macroDown}});
|
||||||
ui->macroControlLayout->addWidget(macroControls);
|
ui->macroControlLayout->addWidget(macroControls);
|
||||||
|
|
||||||
ui->macros->Reset(GetMacros(),
|
ui->macros->Reset(macros, GetGlobalMacroSettings()._highlightExecuted);
|
||||||
GetGlobalMacroSettings()._highlightExecuted);
|
|
||||||
connect(ui->macros, SIGNAL(MacroSelectionChanged()), this,
|
connect(ui->macros, SIGNAL(MacroSelectionChanged()), this,
|
||||||
SLOT(MacroSelectionChanged()));
|
SLOT(MacroSelectionChanged()));
|
||||||
ui->runMacro->SetMacroTree(ui->macros);
|
ui->runMacro->SetMacroTree(ui->macros);
|
||||||
@@ -655,6 +658,8 @@ void AdvSceneSwitcher::SetupMacroTab()
|
|||||||
ui->macroPriorityWarning->setVisible(
|
ui->macroPriorityWarning->setVisible(
|
||||||
switcher->functionNamesByPriority[0] != macro_func);
|
switcher->functionNamesByPriority[0] != macro_func);
|
||||||
|
|
||||||
|
lastOnChangeHighlightCheckTime =
|
||||||
|
std::chrono::high_resolution_clock::now();
|
||||||
onChangeHighlightTimer.setInterval(1500);
|
onChangeHighlightTimer.setInterval(1500);
|
||||||
connect(&onChangeHighlightTimer, SIGNAL(timeout()), this,
|
connect(&onChangeHighlightTimer, SIGNAL(timeout()), this,
|
||||||
SLOT(HighlightOnChange()));
|
SLOT(HighlightOnChange()));
|
||||||
@@ -671,6 +676,12 @@ void AdvSceneSwitcher::SetupMacroTab()
|
|||||||
switcher->macroListMacroEditSplitterPosition);
|
switcher->macroListMacroEditSplitterPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SetupMacroSearchWidgets(ui->macroSearchLayout, ui->macroSearchText,
|
||||||
|
ui->macroSearchClear, ui->macroSearchType,
|
||||||
|
ui->macroSearchRegex,
|
||||||
|
ui->macroSearchShowSettings,
|
||||||
|
[this]() { ui->macros->RefreshFilter(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::ShowMacroContextMenu(const QPoint &pos)
|
void AdvSceneSwitcher::ShowMacroContextMenu(const QPoint &pos)
|
||||||
@@ -752,7 +763,7 @@ void AdvSceneSwitcher::CopyMacro()
|
|||||||
newMacro->Load(data);
|
newMacro->Load(data);
|
||||||
newMacro->PostLoad();
|
newMacro->PostLoad();
|
||||||
newMacro->SetName(name);
|
newMacro->SetName(name);
|
||||||
RunPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
Macro::PrepareMoveToGroup(macro->Parent(), newMacro);
|
Macro::PrepareMoveToGroup(macro->Parent(), newMacro);
|
||||||
|
|
||||||
ui->macros->Add(newMacro, macro);
|
ui->macros->Add(newMacro, macro);
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
#include "macro-tree.hpp"
|
#include "macro-tree.hpp"
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
|
#include "macro-search.hpp"
|
||||||
#include "macro-signals.hpp"
|
#include "macro-signals.hpp"
|
||||||
#include "path-helpers.hpp"
|
#include "path-helpers.hpp"
|
||||||
#include "sync-helpers.hpp"
|
#include "sync-helpers.hpp"
|
||||||
#include "ui-helpers.hpp"
|
#include "ui-helpers.hpp"
|
||||||
#include "utility.hpp"
|
|
||||||
|
|
||||||
#include <obs.h>
|
#include <obs.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QSpacerItem>
|
#include <QSpacerItem>
|
||||||
#include <QPushButton>
|
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <QHBoxLayout>
|
#include <QHBoxLayout>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QStylePainter>
|
#include <QStylePainter>
|
||||||
|
#include <QToolTip>
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(std::shared_ptr<advss::Macro>);
|
Q_DECLARE_METATYPE(std::shared_ptr<advss::Macro>);
|
||||||
|
|
||||||
@@ -61,12 +61,11 @@ MacroTreeItem::MacroTreeItem(MacroTree *tree, std::shared_ptr<Macro> macroItem,
|
|||||||
|
|
||||||
_boxLayout = new QHBoxLayout();
|
_boxLayout = new QHBoxLayout();
|
||||||
_boxLayout->setContentsMargins(0, 0, 0, 0);
|
_boxLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
_boxLayout->addWidget(_running);
|
|
||||||
if (isGroup) {
|
if (isGroup) {
|
||||||
_boxLayout->addWidget(_iconLabel);
|
_boxLayout->addWidget(_iconLabel);
|
||||||
_boxLayout->addSpacing(2);
|
_boxLayout->addSpacing(2);
|
||||||
_running->hide();
|
|
||||||
}
|
}
|
||||||
|
_boxLayout->addWidget(_running);
|
||||||
_boxLayout->addWidget(_label);
|
_boxLayout->addWidget(_label);
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
/* Hack: Fixes a bug where scrollbars would be above the lock icon */
|
/* Hack: Fixes a bug where scrollbars would be above the lock icon */
|
||||||
@@ -76,29 +75,138 @@ MacroTreeItem::MacroTreeItem(MacroTree *tree, std::shared_ptr<Macro> macroItem,
|
|||||||
Update(true);
|
Update(true);
|
||||||
setLayout(_boxLayout);
|
setLayout(_boxLayout);
|
||||||
|
|
||||||
auto setRunning = [this](bool val) {
|
connect(_running, SIGNAL(clicked(bool)), this,
|
||||||
_macro->SetPaused(!val);
|
SLOT(RunningClicked(bool)));
|
||||||
};
|
|
||||||
connect(_running, &QAbstractButton::clicked, setRunning);
|
|
||||||
connect(MacroSignalManager::Instance(), SIGNAL(HighlightChanged(bool)),
|
connect(MacroSignalManager::Instance(), SIGNAL(HighlightChanged(bool)),
|
||||||
this, SLOT(EnableHighlight(bool)));
|
this, SLOT(EnableHighlight(bool)));
|
||||||
connect(MacroSignalManager::Instance(),
|
connect(MacroSignalManager::Instance(),
|
||||||
SIGNAL(Rename(const QString &, const QString &)), this,
|
SIGNAL(Rename(const QString &, const QString &)), this,
|
||||||
SLOT(MacroRenamed(const QString &, const QString &)));
|
SLOT(MacroRenamed(const QString &, const QString &)));
|
||||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(HighlightIfExecuted()));
|
connect(&_timer, SIGNAL(timeout()), this, SLOT(HighlightIfExecuted()));
|
||||||
connect(&_timer, SIGNAL(timeout()), this, SLOT(UpdatePaused()));
|
connect(&_timer, SIGNAL(timeout()), this, SLOT(UpdateRunning()));
|
||||||
|
|
||||||
|
UpdateRunning();
|
||||||
_timer.start(1500);
|
_timer.start(1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MacroTreeItem::event(QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() != QEvent::ToolTip) {
|
||||||
|
return QFrame::event(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_macro->IsGroup()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString text;
|
||||||
|
if (!_macro->WasExecutedSince({})) {
|
||||||
|
text = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.macroTab.macroNotYetExecutedTooltip");
|
||||||
|
} else {
|
||||||
|
const QString formatStr = obs_module_text(
|
||||||
|
"AdvSceneSwitcher.macroTab.macroLastExecutedTooltip");
|
||||||
|
const auto secondsSinceLastRun =
|
||||||
|
std::chrono::duration_cast<std::chrono::seconds>(
|
||||||
|
std::chrono::high_resolution_clock::now() -
|
||||||
|
_macro->GetLastExecutionTime());
|
||||||
|
text = formatStr.arg(secondsSinceLastRun.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto helpEvent = static_cast<QHelpEvent *>(event);
|
||||||
|
QToolTip::showText(helpEvent->globalPos(), text, this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void MacroTreeItem::EnableHighlight(bool enable)
|
void MacroTreeItem::EnableHighlight(bool enable)
|
||||||
{
|
{
|
||||||
_highlight = enable;
|
_highlight = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroTreeItem::UpdatePaused()
|
void MacroTreeItem::RunningClicked(bool running)
|
||||||
|
{
|
||||||
|
const auto updateWidget = [this](Macro *macro) {
|
||||||
|
if (!macro) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto ¯os = GetTopLevelMacros();
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
int idx = 0;
|
||||||
|
for (const auto &m : macros) {
|
||||||
|
if (m.get() == macro) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto widget = _tree->GetItemWidget(idx);
|
||||||
|
if (widget) {
|
||||||
|
widget->UpdateRunning();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!_macro->IsGroup()) {
|
||||||
|
_macro->SetPaused(!running);
|
||||||
|
if (!_macro->IsSubitem()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto group = _macro->Parent();
|
||||||
|
updateWidget(group.get());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto macros = GetGroupMacroEntries(_macro.get());
|
||||||
|
for (const auto ¯o : macros) {
|
||||||
|
macro->SetPaused(!running);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update backend values before updating UI to prevent flickering in
|
||||||
|
// running state of the group
|
||||||
|
for (const auto ¯o : macros) {
|
||||||
|
updateWidget(macro.get());
|
||||||
|
}
|
||||||
|
UpdateRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroTreeItem::UpdateRunning()
|
||||||
{
|
{
|
||||||
const QSignalBlocker blocker(_running);
|
const QSignalBlocker blocker(_running);
|
||||||
_running->setChecked(!_macro->Paused());
|
|
||||||
|
if (!_macro->IsGroup()) {
|
||||||
|
_running->setChecked(!_macro->Paused());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto macros = GetGroupMacroEntries(_macro.get());
|
||||||
|
bool allRunning = true;
|
||||||
|
bool allPaused = true;
|
||||||
|
for (const auto ¯o : macros) {
|
||||||
|
if (macro->Paused()) {
|
||||||
|
allRunning = false;
|
||||||
|
} else {
|
||||||
|
allPaused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allRunning) {
|
||||||
|
_running->setCheckState(Qt::Checked);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allPaused) {
|
||||||
|
_running->setCheckState(Qt::Unchecked);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_running->setCheckState(Qt::PartiallyChecked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroTreeItem::HighlightIfExecuted()
|
void MacroTreeItem::HighlightIfExecuted()
|
||||||
@@ -107,10 +215,19 @@ void MacroTreeItem::HighlightIfExecuted()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wasHighlighted = false;
|
||||||
if (_lastHighlightCheckTime.time_since_epoch().count() != 0 &&
|
if (_lastHighlightCheckTime.time_since_epoch().count() != 0 &&
|
||||||
_macro->WasExecutedSince(_lastHighlightCheckTime)) {
|
_macro->WasExecutedSince(_lastHighlightCheckTime)) {
|
||||||
HighlightWidget(this, Qt::green, QColor(0, 0, 0, 0), true);
|
HighlightWidget(this, Qt::green, QColor(0, 0, 0, 0), true);
|
||||||
|
wasHighlighted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!wasHighlighted &&
|
||||||
|
_lastHighlightCheckTime.time_since_epoch().count() != 0 &&
|
||||||
|
_macro->OnChangePreventedActionsSince(_lastHighlightCheckTime)) {
|
||||||
|
HighlightWidget(this, Qt::yellow, QColor(0, 0, 0, 0), true);
|
||||||
|
}
|
||||||
|
|
||||||
_lastHighlightCheckTime = std::chrono::high_resolution_clock::now();
|
_lastHighlightCheckTime = std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +304,7 @@ void MacroTreeItem::Update(bool force)
|
|||||||
_expand->blockSignals(true);
|
_expand->blockSignals(true);
|
||||||
_expand->setChecked(_macro->IsCollapsed());
|
_expand->setChecked(_macro->IsCollapsed());
|
||||||
_expand->blockSignals(false);
|
_expand->blockSignals(false);
|
||||||
connect(_expand, &QPushButton::toggled, this,
|
connect(_expand, &QCheckBox::toggled, this,
|
||||||
&MacroTreeItem::ExpandClicked);
|
&MacroTreeItem::ExpandClicked);
|
||||||
} else {
|
} else {
|
||||||
_spacer = new QSpacerItem(3, 1);
|
_spacer = new QSpacerItem(3, 1);
|
||||||
@@ -213,7 +330,6 @@ void MacroTreeModel::Reset(std::deque<std::shared_ptr<Macro>> &newItems)
|
|||||||
_macros = newItems;
|
_macros = newItems;
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
|
||||||
UpdateGroupState(false);
|
|
||||||
_mt->ResetWidgets();
|
_mt->ResetWidgets();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,9 +574,6 @@ void MacroTreeModel::Remove(std::shared_ptr<Macro> item)
|
|||||||
|
|
||||||
_mt->selectionModel()->clear();
|
_mt->selectionModel()->clear();
|
||||||
|
|
||||||
if (isGroup) {
|
|
||||||
UpdateGroupState(true);
|
|
||||||
}
|
|
||||||
assert(IsInValidState());
|
assert(IsInValidState());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,7 +662,6 @@ MacroTreeModel::MacroTreeModel(MacroTree *st_,
|
|||||||
_mt(st_),
|
_mt(st_),
|
||||||
_macros(macros)
|
_macros(macros)
|
||||||
{
|
{
|
||||||
UpdateGroupState(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MacroTreeModel::rowCount(const QModelIndex &parent) const
|
int MacroTreeModel::rowCount(const QModelIndex &parent) const
|
||||||
@@ -703,7 +815,6 @@ void MacroTreeModel::GroupSelectedItems(QModelIndexList &indices)
|
|||||||
offset++;
|
offset++;
|
||||||
}
|
}
|
||||||
|
|
||||||
_hasGroups = true;
|
|
||||||
_mt->selectionModel()->clear();
|
_mt->selectionModel()->clear();
|
||||||
|
|
||||||
Reset(_macros);
|
Reset(_macros);
|
||||||
@@ -761,29 +872,12 @@ void MacroTreeModel::CollapseGroup(std::shared_ptr<Macro> item)
|
|||||||
assert(IsInValidState());
|
assert(IsInValidState());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroTreeModel::UpdateGroupState(bool update)
|
|
||||||
{
|
|
||||||
bool nowHasGroups = false;
|
|
||||||
for (auto &item : _macros) {
|
|
||||||
if (item->IsGroup()) {
|
|
||||||
nowHasGroups = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nowHasGroups != _hasGroups) {
|
|
||||||
_hasGroups = nowHasGroups;
|
|
||||||
if (update) {
|
|
||||||
_mt->UpdateWidgets(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroTree::Reset(std::deque<std::shared_ptr<Macro>> ¯os,
|
void MacroTree::Reset(std::deque<std::shared_ptr<Macro>> ¯os,
|
||||||
bool highlight)
|
bool highlight)
|
||||||
{
|
{
|
||||||
_highlight = highlight;
|
_highlight = highlight;
|
||||||
MacroTreeModel *mtm = new MacroTreeModel(this, macros);
|
|
||||||
|
auto mtm = new MacroTreeModel(this, macros);
|
||||||
setModel(mtm);
|
setModel(mtm);
|
||||||
GetModel()->Reset(macros);
|
GetModel()->Reset(macros);
|
||||||
connect(selectionModel(),
|
connect(selectionModel(),
|
||||||
@@ -840,7 +934,6 @@ MacroTree::MacroTree(QWidget *parent_) : QListView(parent_)
|
|||||||
void MacroTree::ResetWidgets()
|
void MacroTree::ResetWidgets()
|
||||||
{
|
{
|
||||||
MacroTreeModel *mtm = GetModel();
|
MacroTreeModel *mtm = GetModel();
|
||||||
mtm->UpdateGroupState(false);
|
|
||||||
int modelIdx = 0;
|
int modelIdx = 0;
|
||||||
for (int i = 0; i < (int)mtm->_macros.size(); i++) {
|
for (int i = 0; i < (int)mtm->_macros.size(); i++) {
|
||||||
QModelIndex index = mtm->createIndex(modelIdx, 0, nullptr);
|
QModelIndex index = mtm->createIndex(modelIdx, 0, nullptr);
|
||||||
@@ -869,7 +962,7 @@ void MacroTree::UpdateWidgets(bool force)
|
|||||||
|
|
||||||
for (int i = 0; i < (int)mtm->_macros.size(); i++) {
|
for (int i = 0; i < (int)mtm->_macros.size(); i++) {
|
||||||
std::shared_ptr<Macro> item = mtm->_macros[i];
|
std::shared_ptr<Macro> item = mtm->_macros[i];
|
||||||
MacroTreeItem *widget = GetItemWidget(i);
|
auto widget = GetItemWidget(i);
|
||||||
|
|
||||||
if (!widget) {
|
if (!widget) {
|
||||||
UpdateWidget(mtm->createIndex(i, 0, nullptr), item);
|
UpdateWidget(mtm->createIndex(i, 0, nullptr), item);
|
||||||
@@ -1184,7 +1277,7 @@ bool MacroTree::SelectionEmpty() const
|
|||||||
|
|
||||||
bool MacroTree::GroupsExist() const
|
bool MacroTree::GroupsExist() const
|
||||||
{
|
{
|
||||||
for (const auto ¯o : GetMacros()) {
|
for (const auto ¯o : GetTopLevelMacros()) {
|
||||||
if (macro->IsGroup()) {
|
if (macro->IsGroup()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1204,6 +1297,12 @@ void MacroTree::CollapseGroup(std::shared_ptr<Macro> item) const
|
|||||||
mtm->CollapseGroup(item);
|
mtm->CollapseGroup(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroTree::RefreshFilter()
|
||||||
|
{
|
||||||
|
UpdateWidgets();
|
||||||
|
doItemsLayout();
|
||||||
|
}
|
||||||
|
|
||||||
void MacroTree::MoveItemBefore(const std::shared_ptr<Macro> &item,
|
void MacroTree::MoveItemBefore(const std::shared_ptr<Macro> &item,
|
||||||
const std::shared_ptr<Macro> &after) const
|
const std::shared_ptr<Macro> &after) const
|
||||||
{
|
{
|
||||||
@@ -1218,7 +1317,7 @@ void MacroTree::MoveItemAfter(const std::shared_ptr<Macro> &item,
|
|||||||
|
|
||||||
MacroTreeModel *MacroTree::GetModel() const
|
MacroTreeModel *MacroTree::GetModel() const
|
||||||
{
|
{
|
||||||
return reinterpret_cast<MacroTreeModel *>(model());
|
return qobject_cast<MacroTreeModel *>(model());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroTree::Remove(std::shared_ptr<Macro> item) const
|
void MacroTree::Remove(std::shared_ptr<Macro> item) const
|
||||||
@@ -1306,7 +1405,7 @@ void MacroTree::UngroupSelectedGroups()
|
|||||||
|
|
||||||
void MacroTree::ExpandAll()
|
void MacroTree::ExpandAll()
|
||||||
{
|
{
|
||||||
for (const auto ¯o : GetMacros()) {
|
for (const auto ¯o : GetTopLevelMacros()) {
|
||||||
if (!macro->IsGroup()) {
|
if (!macro->IsGroup()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1316,7 +1415,7 @@ void MacroTree::ExpandAll()
|
|||||||
|
|
||||||
void MacroTree::CollapseAll()
|
void MacroTree::CollapseAll()
|
||||||
{
|
{
|
||||||
for (const auto ¯o : GetMacros()) {
|
for (const auto ¯o : GetTopLevelMacros()) {
|
||||||
if (!macro->IsGroup()) {
|
if (!macro->IsGroup()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1333,8 +1432,8 @@ void MacroTree::SelectionChangedHelper(const QItemSelection &,
|
|||||||
|
|
||||||
inline MacroTreeItem *MacroTree::GetItemWidget(int idx) const
|
inline MacroTreeItem *MacroTree::GetItemWidget(int idx) const
|
||||||
{
|
{
|
||||||
QWidget *widget = indexWidget(GetModel()->createIndex(idx, 0, nullptr));
|
auto widget = indexWidget(GetModel()->createIndex(idx, 0, nullptr));
|
||||||
return reinterpret_cast<MacroTreeItem *>(widget);
|
return qobject_cast<MacroTreeItem *>(widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroTree::paintEvent(QPaintEvent *event)
|
void MacroTree::paintEvent(QPaintEvent *event)
|
||||||
@@ -1361,14 +1460,25 @@ MacroTreeDelegate::MacroTreeDelegate(QObject *parent)
|
|||||||
QSize MacroTreeDelegate::sizeHint(const QStyleOptionViewItem &option,
|
QSize MacroTreeDelegate::sizeHint(const QStyleOptionViewItem &option,
|
||||||
const QModelIndex &index) const
|
const QModelIndex &index) const
|
||||||
{
|
{
|
||||||
MacroTree *tree = qobject_cast<MacroTree *>(parent());
|
auto tree = qobject_cast<MacroTree *>(parent());
|
||||||
QWidget *item = tree->indexWidget(index);
|
auto widget = tree->indexWidget(index);
|
||||||
|
|
||||||
if (!item) {
|
if (!widget) {
|
||||||
return QStyledItemDelegate::sizeHint(option, index);
|
return QStyledItemDelegate::sizeHint(option, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
return QSize(item->sizeHint());
|
auto name = index.data(Qt::AccessibleTextRole).toString();
|
||||||
|
auto macro = GetMacroByQString(name);
|
||||||
|
|
||||||
|
if (!macro) {
|
||||||
|
return QStyledItemDelegate::sizeHint(option, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MacroMatchesSearchFilter(macro)) {
|
||||||
|
return QSize(widget->sizeHint());
|
||||||
|
}
|
||||||
|
|
||||||
|
return QSize(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -34,10 +34,14 @@ public:
|
|||||||
explicit MacroTreeItem(MacroTree *tree, std::shared_ptr<Macro> macro,
|
explicit MacroTreeItem(MacroTree *tree, std::shared_ptr<Macro> macro,
|
||||||
bool highlight);
|
bool highlight);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool event(QEvent *) override;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void ExpandClicked(bool checked);
|
void ExpandClicked(bool checked);
|
||||||
void EnableHighlight(bool enable);
|
void EnableHighlight(bool enable);
|
||||||
void UpdatePaused();
|
void RunningClicked(bool);
|
||||||
|
void UpdateRunning();
|
||||||
void HighlightIfExecuted();
|
void HighlightIfExecuted();
|
||||||
void MacroRenamed(const QString &, const QString &);
|
void MacroRenamed(const QString &, const QString &);
|
||||||
|
|
||||||
@@ -106,7 +110,6 @@ private:
|
|||||||
void UngroupSelectedGroups(QModelIndexList &indices);
|
void UngroupSelectedGroups(QModelIndexList &indices);
|
||||||
void ExpandGroup(std::shared_ptr<Macro> item);
|
void ExpandGroup(std::shared_ptr<Macro> item);
|
||||||
void CollapseGroup(std::shared_ptr<Macro> item);
|
void CollapseGroup(std::shared_ptr<Macro> item);
|
||||||
void UpdateGroupState(bool update);
|
|
||||||
int GetItemMacroIndex(const std::shared_ptr<Macro> &item) const;
|
int GetItemMacroIndex(const std::shared_ptr<Macro> &item) const;
|
||||||
int GetItemModelIndex(const std::shared_ptr<Macro> &item) const;
|
int GetItemModelIndex(const std::shared_ptr<Macro> &item) const;
|
||||||
bool IsLastItem(std::shared_ptr<Macro> item) const;
|
bool IsLastItem(std::shared_ptr<Macro> item) const;
|
||||||
@@ -114,7 +117,6 @@ private:
|
|||||||
|
|
||||||
MacroTree *_mt;
|
MacroTree *_mt;
|
||||||
std::deque<std::shared_ptr<Macro>> &_macros;
|
std::deque<std::shared_ptr<Macro>> &_macros;
|
||||||
bool _hasGroups = false;
|
|
||||||
|
|
||||||
friend class MacroTree;
|
friend class MacroTree;
|
||||||
friend class MacroTreeItem;
|
friend class MacroTreeItem;
|
||||||
@@ -142,6 +144,7 @@ public:
|
|||||||
bool GroupsExist() const;
|
bool GroupsExist() const;
|
||||||
void ExpandGroup(std::shared_ptr<Macro> item) const;
|
void ExpandGroup(std::shared_ptr<Macro> item) const;
|
||||||
void CollapseGroup(std::shared_ptr<Macro> item) const;
|
void CollapseGroup(std::shared_ptr<Macro> item) const;
|
||||||
|
void RefreshFilter();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void GroupSelectedItems();
|
void GroupSelectedItems();
|
||||||
|
|||||||
111
lib/macro/macro-websocket-trigger.cpp
Normal file
111
lib/macro/macro-websocket-trigger.cpp
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
#include "websocket-api.hpp"
|
||||||
|
#include "log-helper.hpp"
|
||||||
|
#include "plugin-state-helpers.hpp"
|
||||||
|
#include "variable.hpp"
|
||||||
|
#include "macro-helpers.hpp"
|
||||||
|
|
||||||
|
#include <obs.hpp>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
static bool setup();
|
||||||
|
static bool setupDone = setup();
|
||||||
|
static void receiveRunMacroMessage(obs_data_t *data, obs_data_t *);
|
||||||
|
static void receiveSetVariablesMessage(obs_data_t *data, obs_data_t *);
|
||||||
|
|
||||||
|
static const char *runMacroMessage = "AdvancedSceneSwitcherRunMacro";
|
||||||
|
static const char *setVariablesMessage = "AdvancedSceneSwitcherSetVariables";
|
||||||
|
|
||||||
|
static bool setup()
|
||||||
|
{
|
||||||
|
AddPluginInitStep([]() {
|
||||||
|
RegisterWebsocketRequest(runMacroMessage,
|
||||||
|
receiveRunMacroMessage);
|
||||||
|
RegisterWebsocketRequest(setVariablesMessage,
|
||||||
|
receiveSetVariablesMessage);
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setVariables(obs_data_t *data)
|
||||||
|
{
|
||||||
|
OBSDataArrayAutoRelease variables =
|
||||||
|
obs_data_get_array(data, "variables");
|
||||||
|
size_t count = obs_data_array_count(variables);
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
OBSDataAutoRelease item = obs_data_array_item(variables, i);
|
||||||
|
if (!obs_data_has_user_value(item, "name")) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"ignoring invalid variable entry in \"%s\" websocket message (missing \"name\")",
|
||||||
|
runMacroMessage);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!obs_data_has_user_value(item, "value")) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"ignoring invalid variable entry in \"%s\" websocket message (missing \"value\")",
|
||||||
|
runMacroMessage);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto varName = obs_data_get_string(item, "name");
|
||||||
|
auto value = obs_data_get_string(item, "value");
|
||||||
|
|
||||||
|
auto weakVar = GetWeakVariableByName(varName);
|
||||||
|
auto var = weakVar.lock();
|
||||||
|
if (!var) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"ignoring invalid variable name \"%s\" in \"%s\" websocket message",
|
||||||
|
varName, runMacroMessage);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var->SetValue(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void receiveRunMacroMessage(obs_data_t *data, obs_data_t *)
|
||||||
|
{
|
||||||
|
if (!obs_data_has_user_value(data, "name")) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"ignoring invalid \"%s\" websocket message (missing \"name\")",
|
||||||
|
runMacroMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto name = obs_data_get_string(data, "name");
|
||||||
|
const auto weakMacro =
|
||||||
|
GetWeakMacroByName(obs_data_get_string(data, "name"));
|
||||||
|
const auto macro = weakMacro.lock();
|
||||||
|
if (!macro) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"ignoring invalid \"%s\" websocket message (macro \"%s\") not found",
|
||||||
|
runMacroMessage, name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obs_data_has_user_value(data, "variables")) {
|
||||||
|
setVariables(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool runElse = obs_data_get_bool(data, "runElseActions");
|
||||||
|
if (runElse) {
|
||||||
|
RunMacroElseActions(macro.get());
|
||||||
|
} else {
|
||||||
|
RunMacroActions(macro.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void receiveSetVariablesMessage(obs_data_t *data, obs_data_t *)
|
||||||
|
{
|
||||||
|
if (!obs_data_has_user_value(data, "variables")) {
|
||||||
|
blog(LOG_INFO,
|
||||||
|
"ignoring invalid \"%s\" websocket message (missing \"variables\")",
|
||||||
|
setVariablesMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setVariables(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -17,8 +17,6 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
static std::deque<std::shared_ptr<Macro>> macros;
|
|
||||||
|
|
||||||
Macro::Macro(const std::string &name) : _dockSettings(this)
|
Macro::Macro(const std::string &name) : _dockSettings(this)
|
||||||
{
|
{
|
||||||
SetName(name);
|
SetName(name);
|
||||||
@@ -59,6 +57,7 @@ Macro::CreateGroup(const std::string &name,
|
|||||||
|
|
||||||
void Macro::RemoveGroup(std::shared_ptr<Macro> group)
|
void Macro::RemoveGroup(std::shared_ptr<Macro> group)
|
||||||
{
|
{
|
||||||
|
auto ¯os = GetTopLevelMacros();
|
||||||
auto it = std::find(macros.begin(), macros.end(), group);
|
auto it = std::find(macros.begin(), macros.end(), group);
|
||||||
if (it == macros.end()) {
|
if (it == macros.end()) {
|
||||||
return;
|
return;
|
||||||
@@ -75,6 +74,7 @@ void Macro::RemoveGroup(std::shared_ptr<Macro> group)
|
|||||||
|
|
||||||
void Macro::PrepareMoveToGroup(Macro *group, std::shared_ptr<Macro> item)
|
void Macro::PrepareMoveToGroup(Macro *group, std::shared_ptr<Macro> item)
|
||||||
{
|
{
|
||||||
|
auto ¯os = GetTopLevelMacros();
|
||||||
for (const auto &m : macros) {
|
for (const auto &m : macros) {
|
||||||
if (m.get() == group) {
|
if (m.get() == group) {
|
||||||
PrepareMoveToGroup(m, item);
|
PrepareMoveToGroup(m, item);
|
||||||
@@ -242,8 +242,12 @@ bool Macro::CheckConditions(bool ignorePause)
|
|||||||
vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched);
|
vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched);
|
||||||
|
|
||||||
_conditionSateChanged = _lastMatched != _matched;
|
_conditionSateChanged = _lastMatched != _matched;
|
||||||
if (!_conditionSateChanged && _performActionsOnChange) {
|
const bool hasActionsToExecute = _matched ? (_actions.size() > 0)
|
||||||
_onPreventedActionExecution = true;
|
: (_elseActions.size() > 0);
|
||||||
|
if (!_conditionSateChanged && _performActionsOnChange &&
|
||||||
|
hasActionsToExecute) {
|
||||||
|
_lastOnChangeActionsPreventedTime =
|
||||||
|
std::chrono::high_resolution_clock::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastMatched = _matched;
|
_lastMatched = _matched;
|
||||||
@@ -302,6 +306,16 @@ bool Macro::WasExecutedSince(const TimePoint &time) const
|
|||||||
return _lastExecutionTime > time;
|
return _lastExecutionTime > time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Macro::OnChangePreventedActionsSince(const TimePoint &time) const
|
||||||
|
{
|
||||||
|
return _lastOnChangeActionsPreventedTime > time;
|
||||||
|
}
|
||||||
|
|
||||||
|
Macro::TimePoint Macro::GetLastExecutionTime() const
|
||||||
|
{
|
||||||
|
return _lastExecutionTime;
|
||||||
|
}
|
||||||
|
|
||||||
bool Macro::ConditionsShouldBeChecked() const
|
bool Macro::ConditionsShouldBeChecked() const
|
||||||
{
|
{
|
||||||
if (!_useCustomConditionCheckInterval) {
|
if (!_useCustomConditionCheckInterval) {
|
||||||
@@ -948,12 +962,12 @@ bool Macro::PostLoad()
|
|||||||
bool Macro::SwitchesScene() const
|
bool Macro::SwitchesScene() const
|
||||||
{
|
{
|
||||||
for (const auto &a : _actions) {
|
for (const auto &a : _actions) {
|
||||||
if (a->GetId() == GetSceneSwitchActionId()) {
|
if (a->GetId() == MacroAction::GetDefaultID()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto &a : _elseActions) {
|
for (const auto &a : _elseActions) {
|
||||||
if (a->GetId() == GetSceneSwitchActionId()) {
|
if (a->GetId() == MacroAction::GetDefaultID()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -986,18 +1000,8 @@ bool Macro::HasValidSplitterPositions() const
|
|||||||
!_elseActionSplitterPosition.empty();
|
!_elseActionSplitterPosition.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Macro::OnChangePreventedActionsRecently()
|
|
||||||
{
|
|
||||||
if (_onPreventedActionExecution) {
|
|
||||||
_onPreventedActionExecution = false;
|
|
||||||
return _matched ? _actions.size() > 0 : _elseActions.size() > 0;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Macro::ResetUIHelpers()
|
void Macro::ResetUIHelpers()
|
||||||
{
|
{
|
||||||
_onPreventedActionExecution = false;
|
|
||||||
for (auto c : _conditions) {
|
for (auto c : _conditions) {
|
||||||
c->GetHighlightAndReset();
|
c->GetHighlightAndReset();
|
||||||
}
|
}
|
||||||
@@ -1114,7 +1118,7 @@ void Macro::SetHotkeysDesc() const
|
|||||||
void SaveMacros(obs_data_t *obj)
|
void SaveMacros(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
obs_data_array_t *macroArray = obs_data_array_create();
|
obs_data_array_t *macroArray = obs_data_array_create();
|
||||||
for (const auto &m : macros) {
|
for (const auto &m : GetTopLevelMacros()) {
|
||||||
obs_data_t *array_obj = obs_data_create();
|
obs_data_t *array_obj = obs_data_create();
|
||||||
|
|
||||||
m->Save(array_obj);
|
m->Save(array_obj);
|
||||||
@@ -1128,7 +1132,9 @@ void SaveMacros(obs_data_t *obj)
|
|||||||
|
|
||||||
void LoadMacros(obs_data_t *obj)
|
void LoadMacros(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
|
auto ¯os = GetTopLevelMacros();
|
||||||
macros.clear();
|
macros.clear();
|
||||||
|
|
||||||
obs_data_array_t *macroArray = obs_data_get_array(obj, "macros");
|
obs_data_array_t *macroArray = obs_data_get_array(obj, "macros");
|
||||||
size_t count = obs_data_array_count(macroArray);
|
size_t count = obs_data_array_count(macroArray);
|
||||||
|
|
||||||
@@ -1178,15 +1184,10 @@ void LoadMacros(obs_data_t *obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::deque<std::shared_ptr<Macro>> &GetMacros()
|
|
||||||
{
|
|
||||||
return macros;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CheckMacros()
|
bool CheckMacros()
|
||||||
{
|
{
|
||||||
bool matchFound = false;
|
bool matchFound = false;
|
||||||
for (const auto &m : macros) {
|
for (const auto &m : GetTopLevelMacros()) {
|
||||||
if (!m->ConditionsShouldBeChecked()) {
|
if (!m->ConditionsShouldBeChecked()) {
|
||||||
vblog(LOG_INFO,
|
vblog(LOG_INFO,
|
||||||
"skipping condition check for macro \"%s\" "
|
"skipping condition check for macro \"%s\" "
|
||||||
@@ -1213,7 +1214,7 @@ bool RunMacros()
|
|||||||
// reordered while macros are currently being executed.
|
// reordered while macros are currently being executed.
|
||||||
// For example, this can happen if a macro is performing a wait action,
|
// For example, this can happen if a macro is performing a wait action,
|
||||||
// as the main lock will be unlocked during this time.
|
// as the main lock will be unlocked during this time.
|
||||||
auto runPhaseMacros = macros;
|
auto runPhaseMacros = GetTopLevelMacros();
|
||||||
|
|
||||||
// Avoid deadlocks when opening settings window and calling frontend
|
// Avoid deadlocks when opening settings window and calling frontend
|
||||||
// API functions at the same time.
|
// API functions at the same time.
|
||||||
@@ -1253,41 +1254,14 @@ bool RunMacros()
|
|||||||
|
|
||||||
void StopAllMacros()
|
void StopAllMacros()
|
||||||
{
|
{
|
||||||
for (const auto &m : macros) {
|
for (const auto &m : GetAllMacros()) {
|
||||||
m->Stop();
|
m->Stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro *GetMacroByName(const char *name)
|
|
||||||
{
|
|
||||||
for (const auto &m : macros) {
|
|
||||||
if (m->Name() == name) {
|
|
||||||
return m.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Macro *GetMacroByQString(const QString &name)
|
|
||||||
{
|
|
||||||
return GetMacroByName(name.toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::weak_ptr<Macro> GetWeakMacroByName(const char *name)
|
|
||||||
{
|
|
||||||
for (const auto &m : macros) {
|
|
||||||
if (m->Name() == name) {
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void InvalidateMacroTempVarValues()
|
void InvalidateMacroTempVarValues()
|
||||||
{
|
{
|
||||||
for (const auto &m : macros) {
|
for (const auto &m : GetTopLevelMacros()) {
|
||||||
// Do not invalidate the temp vars set during condition checks
|
// Do not invalidate the temp vars set during condition checks
|
||||||
// or action executions running in parallel to the "main" macro
|
// or action executions running in parallel to the "main" macro
|
||||||
// loop, as otherwise access to the information stored in those
|
// loop, as otherwise access to the information stored in those
|
||||||
@@ -1302,6 +1276,8 @@ void InvalidateMacroTempVarValues()
|
|||||||
|
|
||||||
std::shared_ptr<Macro> GetMacroWithInvalidConditionInterval()
|
std::shared_ptr<Macro> GetMacroWithInvalidConditionInterval()
|
||||||
{
|
{
|
||||||
|
auto ¯os = GetTopLevelMacros();
|
||||||
|
|
||||||
if (macros.empty()) {
|
if (macros.empty()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,6 @@
|
|||||||
#include "temp-variable.hpp"
|
#include "temp-variable.hpp"
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <QString>
|
|
||||||
#include <QByteArray>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -139,7 +137,8 @@ public:
|
|||||||
const QList<int> &GetElseActionSplitterPosition() const;
|
const QList<int> &GetElseActionSplitterPosition() const;
|
||||||
bool HasValidSplitterPositions() const;
|
bool HasValidSplitterPositions() const;
|
||||||
bool WasExecutedSince(const TimePoint &) const;
|
bool WasExecutedSince(const TimePoint &) const;
|
||||||
bool OnChangePreventedActionsRecently();
|
bool OnChangePreventedActionsSince(const TimePoint &) const;
|
||||||
|
TimePoint GetLastExecutionTime() const;
|
||||||
void ResetUIHelpers();
|
void ResetUIHelpers();
|
||||||
|
|
||||||
// Hotkeys
|
// Hotkeys
|
||||||
@@ -170,6 +169,7 @@ private:
|
|||||||
TimePoint _lastCheckTime{};
|
TimePoint _lastCheckTime{};
|
||||||
TimePoint _lastUnpauseTime{};
|
TimePoint _lastUnpauseTime{};
|
||||||
TimePoint _lastExecutionTime{};
|
TimePoint _lastExecutionTime{};
|
||||||
|
TimePoint _lastOnChangeActionsPreventedTime{};
|
||||||
std::vector<std::thread> _helperThreads;
|
std::vector<std::thread> _helperThreads;
|
||||||
|
|
||||||
std::deque<std::shared_ptr<MacroCondition>> _conditions;
|
std::deque<std::shared_ptr<MacroCondition>> _conditions;
|
||||||
@@ -206,9 +206,6 @@ private:
|
|||||||
|
|
||||||
MacroInputVariables _inputVariables;
|
MacroInputVariables _inputVariables;
|
||||||
|
|
||||||
// UI helpers
|
|
||||||
bool _onPreventedActionExecution = false;
|
|
||||||
|
|
||||||
QList<int> _actionConditionSplitterPosition;
|
QList<int> _actionConditionSplitterPosition;
|
||||||
QList<int> _elseActionSplitterPosition;
|
QList<int> _elseActionSplitterPosition;
|
||||||
|
|
||||||
@@ -217,13 +214,9 @@ private:
|
|||||||
|
|
||||||
void LoadMacros(obs_data_t *obj);
|
void LoadMacros(obs_data_t *obj);
|
||||||
void SaveMacros(obs_data_t *obj);
|
void SaveMacros(obs_data_t *obj);
|
||||||
std::deque<std::shared_ptr<Macro>> &GetMacros();
|
|
||||||
bool CheckMacros();
|
bool CheckMacros();
|
||||||
bool RunMacros();
|
bool RunMacros();
|
||||||
void StopAllMacros();
|
void StopAllMacros();
|
||||||
Macro *GetMacroByName(const char *name);
|
|
||||||
Macro *GetMacroByQString(const QString &name);
|
|
||||||
std::weak_ptr<Macro> GetWeakMacroByName(const char *name);
|
|
||||||
void InvalidateMacroTempVarValues();
|
void InvalidateMacroTempVarValues();
|
||||||
std::shared_ptr<Macro> GetMacroWithInvalidConditionInterval();
|
std::shared_ptr<Macro> GetMacroWithInvalidConditionInterval();
|
||||||
|
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ bool IsFullscreen(const std::string &title)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> GetTextInWindow(const std::string &window)
|
std::optional<std::string> GetTextInWindow(const std::string &)
|
||||||
{
|
{
|
||||||
// Not implemented
|
// Not implemented
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ void ActionQueue::Add(const std::shared_ptr<MacroAction> &action)
|
|||||||
action->Save(data);
|
action->Save(data);
|
||||||
copy->Load(data);
|
copy->Load(data);
|
||||||
copy->PostLoad();
|
copy->PostLoad();
|
||||||
RunPostLoadSteps();
|
RunAndClearPostLoadSteps();
|
||||||
copy->ResolveVariablesToFixedValues();
|
copy->ResolveVariablesToFixedValues();
|
||||||
_actions.emplace_back(copy);
|
_actions.emplace_back(copy);
|
||||||
} else {
|
} else {
|
||||||
@@ -423,7 +423,7 @@ void ImportQueues(obs_data_t *data)
|
|||||||
importedQueues->emplace_back(queue);
|
importedQueues->emplace_back(queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
QeueUITask(signalImportedQueues, importedQueues);
|
QueueUITask(signalImportedQueues, importedQueues);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::weak_ptr<ActionQueue> GetWeakActionQueueByName(const std::string &name)
|
std::weak_ptr<ActionQueue> GetWeakActionQueueByName(const std::string &name)
|
||||||
|
|||||||
@@ -163,7 +163,6 @@ 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 = {};
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "auto-update-tooltip-label.hpp"
|
#include "auto-update-tooltip-label.hpp"
|
||||||
|
|
||||||
|
#include <QToolTip>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
AutoUpdateHelpIcon::AutoUpdateHelpIcon(
|
AutoUpdateHelpIcon::AutoUpdateHelpIcon(
|
||||||
@@ -16,6 +18,7 @@ AutoUpdateHelpIcon::AutoUpdateHelpIcon(
|
|||||||
|
|
||||||
void AutoUpdateHelpIcon::enterEvent(QEnterEvent *event)
|
void AutoUpdateHelpIcon::enterEvent(QEnterEvent *event)
|
||||||
{
|
{
|
||||||
|
UpdateTooltip();
|
||||||
_timer->start(_updateIntervalMs);
|
_timer->start(_updateIntervalMs);
|
||||||
QLabel::enterEvent(event);
|
QLabel::enterEvent(event);
|
||||||
}
|
}
|
||||||
@@ -28,7 +31,12 @@ void AutoUpdateHelpIcon::leaveEvent(QEvent *event)
|
|||||||
|
|
||||||
void AutoUpdateHelpIcon::UpdateTooltip()
|
void AutoUpdateHelpIcon::UpdateTooltip()
|
||||||
{
|
{
|
||||||
setToolTip(_callback());
|
if (!underMouse()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString text = _callback();
|
||||||
|
QToolTip::showText(QCursor::pos(), text, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -8,13 +8,18 @@
|
|||||||
|
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
#include <obs-module.h>
|
#include <obs-module.h>
|
||||||
#include <QFileDialog>
|
|
||||||
#include <QTextStream>
|
|
||||||
#include <util/config-file.h>
|
#include <util/config-file.h>
|
||||||
|
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
void AskForBackup(const QString &json)
|
static void showBackupDialogs(const QString &json)
|
||||||
{
|
{
|
||||||
const bool backupWasConfirmed = DisplayMessage(
|
const bool backupWasConfirmed = DisplayMessage(
|
||||||
obs_module_text("AdvSceneSwitcher.askBackup"), true, false);
|
obs_module_text("AdvSceneSwitcher.askBackup"), true, false);
|
||||||
@@ -42,6 +47,40 @@ void AskForBackup(const QString &json)
|
|||||||
out << json;
|
out << json;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AskForBackup(obs_data_t *settings)
|
||||||
|
{
|
||||||
|
// This function is called while the plugin settings are being loaded.
|
||||||
|
// Blocking at this stage can cause issues such as OBS failing to start
|
||||||
|
// or crashing.
|
||||||
|
// Therefore, we ask the user whether they want to back up the settings
|
||||||
|
// asynchronously.
|
||||||
|
//
|
||||||
|
// On macOS, an additional QTimer::singleShot wrapper is required for
|
||||||
|
// this to work correctly.
|
||||||
|
|
||||||
|
auto json = obs_data_get_json(settings);
|
||||||
|
static QString jsonQString = json ? json : "";
|
||||||
|
|
||||||
|
static const auto askForBackupWrapper = [](void *) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
QTimer::singleShot(0,
|
||||||
|
static_cast<QMainWindow *>(
|
||||||
|
obs_frontend_get_main_window()),
|
||||||
|
[]() {
|
||||||
|
#endif
|
||||||
|
showBackupDialogs(jsonQString);
|
||||||
|
#ifdef __APPLE__
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
std::thread t([]() {
|
||||||
|
obs_queue_task(OBS_TASK_UI, askForBackupWrapper, nullptr,
|
||||||
|
false);
|
||||||
|
});
|
||||||
|
t.detach();
|
||||||
|
}
|
||||||
|
|
||||||
void BackupSettingsOfCurrentVersion()
|
void BackupSettingsOfCurrentVersion()
|
||||||
{
|
{
|
||||||
auto sceneCollectionName = obs_frontend_get_current_scene_collection();
|
auto sceneCollectionName = obs_frontend_get_current_scene_collection();
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QString>
|
#include <obs-data.h>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
void AskForBackup(const QString &json);
|
void AskForBackup(obs_data_t *settings);
|
||||||
void BackupSettingsOfCurrentVersion();
|
void BackupSettingsOfCurrentVersion();
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ int GetCanvasCount()
|
|||||||
return 1;
|
return 1;
|
||||||
#else
|
#else
|
||||||
static const auto enumCanvases = [](void *countPtr,
|
static const auto enumCanvases = [](void *countPtr,
|
||||||
obs_canvas_t *canvas) -> bool {
|
obs_canvas_t *) -> bool {
|
||||||
auto count = static_cast<int *>(countPtr);
|
auto count = static_cast<int *>(countPtr);
|
||||||
(*count)++;
|
(*count)++;
|
||||||
return true;
|
return true;
|
||||||
@@ -145,6 +145,15 @@ OBSWeakSource GetActiveCanvasScene(const OBSWeakCanvas &weakCanvas)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas();
|
||||||
|
|
||||||
|
// The frontend scene order does not necessarily match the order of the
|
||||||
|
// scenes in the canvas.
|
||||||
|
if (canvas == mainCanvas) {
|
||||||
|
OBSSourceAutoRelease scene = obs_frontend_get_current_scene();
|
||||||
|
return OBSGetWeakRef(scene);
|
||||||
|
}
|
||||||
|
|
||||||
static const auto enumCanvasScenes = [](void *scenePtr,
|
static const auto enumCanvasScenes = [](void *scenePtr,
|
||||||
obs_source_t *source) -> bool {
|
obs_source_t *source) -> bool {
|
||||||
auto scene = static_cast<OBSWeakSource *>(scenePtr);
|
auto scene = static_cast<OBSWeakSource *>(scenePtr);
|
||||||
@@ -181,6 +190,25 @@ OBSWeakSource GetSceneAtIndex(const OBSWeakCanvas &weakCanvas, int idx)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas();
|
||||||
|
|
||||||
|
// The frontend scene order does not necessarily match the order of the
|
||||||
|
// scenes in the canvas.
|
||||||
|
// So, rely on obs_frontend_get_scenes() in case of the main canvas
|
||||||
|
// instead.
|
||||||
|
if (canvas == mainCanvas) {
|
||||||
|
struct obs_frontend_source_list scenes = {0};
|
||||||
|
obs_frontend_get_scenes(&scenes);
|
||||||
|
if (idx >= (int)scenes.sources.num) {
|
||||||
|
obs_frontend_source_list_free(&scenes);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto scene = OBSGetWeakRef(scenes.sources.array[idx]);
|
||||||
|
obs_frontend_source_list_free(&scenes);
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
const int idx;
|
const int idx;
|
||||||
int currentIdx;
|
int currentIdx;
|
||||||
@@ -223,6 +251,29 @@ int GetIndexOfScene(const OBSWeakCanvas &weakCanvas, const OBSWeakSource &scene)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas();
|
||||||
|
|
||||||
|
// The frontend scene order does not necessarily match the order of the
|
||||||
|
// scenes in the canvas.
|
||||||
|
// So, rely on obs_frontend_get_scenes() in case of the main canvas
|
||||||
|
// instead.
|
||||||
|
if (canvas == mainCanvas) {
|
||||||
|
struct obs_frontend_source_list scenes = {0};
|
||||||
|
obs_frontend_get_scenes(&scenes);
|
||||||
|
|
||||||
|
OBSSourceAutoRelease sceneSource = OBSGetStrongRef(scene);
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < scenes.sources.num; i++) {
|
||||||
|
if (scenes.sources.array[i] == sceneSource) {
|
||||||
|
idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_frontend_source_list_free(&scenes);
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
struct Data {
|
struct Data {
|
||||||
int idx;
|
int idx;
|
||||||
@@ -246,6 +297,12 @@ int GetIndexOfScene(const OBSWeakCanvas &weakCanvas, const OBSWeakSource &scene)
|
|||||||
return data.idx;
|
return data.idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OBSWeakCanvas GetMainCanvas()
|
||||||
|
{
|
||||||
|
OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas();
|
||||||
|
return OBSGetWeakRef(mainCanvas);
|
||||||
|
}
|
||||||
|
|
||||||
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||||
|
|
||||||
obs_canvas_t *obs_canvas_get_ref(obs_canvas_t *)
|
obs_canvas_t *obs_canvas_get_ref(obs_canvas_t *)
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ EXPORT OBSWeakSource GetActiveCanvasScene(const OBSWeakCanvas &canvas);
|
|||||||
EXPORT OBSWeakSource GetSceneAtIndex(const OBSWeakCanvas &weakCanvas, int idx);
|
EXPORT OBSWeakSource GetSceneAtIndex(const OBSWeakCanvas &weakCanvas, int idx);
|
||||||
EXPORT int GetIndexOfScene(const OBSWeakCanvas &weakCanvas,
|
EXPORT int GetIndexOfScene(const OBSWeakCanvas &weakCanvas,
|
||||||
const OBSWeakSource &scene);
|
const OBSWeakSource &scene);
|
||||||
|
EXPORT OBSWeakCanvas GetMainCanvas();
|
||||||
|
|
||||||
class CanvasSelection : public FilterComboBox {
|
class CanvasSelection : public FilterComboBox {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|||||||
153
lib/utils/crash-handler.cpp
Normal file
153
lib/utils/crash-handler.cpp
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
#include "crash-handler.hpp"
|
||||||
|
#include "log-helper.hpp"
|
||||||
|
#include "obs-module-helper.hpp"
|
||||||
|
#include "plugin-state-helpers.hpp"
|
||||||
|
#include "ui-helpers.hpp"
|
||||||
|
|
||||||
|
#include <obs-frontend-api.h>
|
||||||
|
#include <obs-module.h>
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
static constexpr std::string_view sentinel = ".running";
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
static constexpr bool handleUncleanShutdown = false;
|
||||||
|
#else
|
||||||
|
static constexpr bool handleUncleanShutdown = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool wasCleanShutdown = false;
|
||||||
|
|
||||||
|
static void setup();
|
||||||
|
static bool setupDone = []() {
|
||||||
|
AddPluginInitStep(setup);
|
||||||
|
return true;
|
||||||
|
}();
|
||||||
|
|
||||||
|
static void handleShutdown(enum obs_frontend_event event, void *)
|
||||||
|
{
|
||||||
|
if (event != OBS_FRONTEND_EVENT_EXIT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *sentinelFile = obs_module_config_path(sentinel.data());
|
||||||
|
if (!sentinelFile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(sentinelFile);
|
||||||
|
if (!file.exists()) {
|
||||||
|
bfree(sentinelFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.remove()) {
|
||||||
|
blog(LOG_WARNING, "failed to remove sentinel file");
|
||||||
|
}
|
||||||
|
|
||||||
|
bfree(sentinelFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup()
|
||||||
|
{
|
||||||
|
char *sentinelFile = obs_module_config_path(sentinel.data());
|
||||||
|
if (!sentinelFile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString dirPath = QFileInfo(sentinelFile).absolutePath();
|
||||||
|
QDir dir(dirPath);
|
||||||
|
if (!dir.exists()) {
|
||||||
|
if (!dir.mkpath(dirPath)) {
|
||||||
|
blog(LOG_WARNING,
|
||||||
|
"failed to create directory for sentinel file");
|
||||||
|
bfree(sentinelFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(sentinelFile);
|
||||||
|
|
||||||
|
wasCleanShutdown = file.exists();
|
||||||
|
|
||||||
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
|
blog(LOG_WARNING, "failed to create sentinel file");
|
||||||
|
bfree(sentinelFile);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.write("running");
|
||||||
|
file.close();
|
||||||
|
bfree(sentinelFile);
|
||||||
|
|
||||||
|
obs_frontend_add_event_callback(handleShutdown, nullptr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool wasUncleanShutdown()
|
||||||
|
{
|
||||||
|
static bool alreadyHandled = false;
|
||||||
|
|
||||||
|
if (!handleUncleanShutdown || !wasCleanShutdown || alreadyHandled) {
|
||||||
|
alreadyHandled = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
alreadyHandled = true;
|
||||||
|
blog(LOG_WARNING, "unclean shutdown detected");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void askForStartupSkip()
|
||||||
|
{
|
||||||
|
bool skipStart = DisplayMessage(
|
||||||
|
obs_module_text("AdvSceneSwitcher.crashDetected"), true, false);
|
||||||
|
if (!skipStart) {
|
||||||
|
StartPlugin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShouldSkipPluginStartOnUncleanShutdown()
|
||||||
|
{
|
||||||
|
if (!wasUncleanShutdown()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function is called while the plugin settings are being loaded.
|
||||||
|
// Blocking at this stage can cause issues such as OBS failing to start
|
||||||
|
// or crashing.
|
||||||
|
// Therefore, we ask the user whether they want to start the plugin
|
||||||
|
// asynchronously.
|
||||||
|
//
|
||||||
|
// On macOS, an additional QTimer::singleShot wrapper is required for
|
||||||
|
// this to work correctly.
|
||||||
|
static const auto showDialogWrapper = [](void *) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
QTimer::singleShot(0,
|
||||||
|
static_cast<QMainWindow *>(
|
||||||
|
obs_frontend_get_main_window()),
|
||||||
|
[]() {
|
||||||
|
#endif
|
||||||
|
askForStartupSkip();
|
||||||
|
#ifdef __APPLE__
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
std::thread t([]() {
|
||||||
|
obs_queue_task(OBS_TASK_UI, showDialogWrapper, nullptr, false);
|
||||||
|
});
|
||||||
|
t.detach();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
7
lib/utils/crash-handler.hpp
Normal file
7
lib/utils/crash-handler.hpp
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
bool ShouldSkipPluginStartOnUncleanShutdown();
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -4,9 +4,11 @@
|
|||||||
#include "ui-helpers.hpp"
|
#include "ui-helpers.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QMenu>
|
|
||||||
#include <QLayout>
|
#include <QLayout>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(advss::Item *);
|
Q_DECLARE_METATYPE(advss::Item *);
|
||||||
|
|
||||||
@@ -330,6 +332,13 @@ void ItemSettingsDialog::NameChanged(const QString &text)
|
|||||||
SetNameWarning("");
|
SetNameWarning("");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItemSettingsDialog::showEvent(QShowEvent *)
|
||||||
|
{
|
||||||
|
if (_showNameEmptyWarning && _name->text().isEmpty()) {
|
||||||
|
_name->setFocus(Qt::OtherFocusReason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ItemSettingsDialog::SetNameWarning(const QString warn)
|
void ItemSettingsDialog::SetNameWarning(const QString warn)
|
||||||
{
|
{
|
||||||
if (warn.isEmpty()) {
|
if (warn.isEmpty()) {
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ private slots:
|
|||||||
void NameChanged(const QString &);
|
void NameChanged(const QString &);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual void showEvent(QShowEvent *) override;
|
||||||
void SetNameWarning(const QString);
|
void SetNameWarning(const QString);
|
||||||
|
|
||||||
QLineEdit *_name;
|
QLineEdit *_name;
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ std::optional<double> GetDouble(const std::string &str)
|
|||||||
std::optional<int> GetInt(const std::string &str)
|
std::optional<int> GetInt(const std::string &str)
|
||||||
{
|
{
|
||||||
char *end = nullptr;
|
char *end = nullptr;
|
||||||
int value = std::strtol(str.c_str(), &end, 10);
|
int value = (int)std::strtol(str.c_str(), &end, 10);
|
||||||
|
|
||||||
if (end != str.c_str() && *end == '\0' && value != INT_MAX &&
|
if (end != str.c_str() && *end == '\0' && value != INT_MAX &&
|
||||||
value != INT_MIN) {
|
value != INT_MIN) {
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
#include "non-modal-dialog.hpp"
|
#include "non-modal-dialog.hpp"
|
||||||
#include "obs-module-helper.hpp"
|
#include "obs-module-helper.hpp"
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLayout>
|
#include <QLayout>
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QCoreApplication>
|
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
|
|||||||
@@ -113,12 +113,13 @@ void RunLoadSteps(obs_data_t *obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RunPostLoadSteps()
|
void RunAndClearPostLoadSteps()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(postLoadMutex);
|
std::lock_guard<std::mutex> lock(postLoadMutex);
|
||||||
for (const auto &func : getPostLoadSteps()) {
|
for (const auto &func : getPostLoadSteps()) {
|
||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
|
getPostLoadSteps().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearPostLoadSteps()
|
void ClearPostLoadSteps()
|
||||||
@@ -135,7 +136,7 @@ void AddPluginInitStep(std::function<void()> step)
|
|||||||
|
|
||||||
void AddPluginPostLoadStep(std::function<void()> step)
|
void AddPluginPostLoadStep(std::function<void()> step)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(initMutex);
|
std::lock_guard<std::mutex> lock(mutex);
|
||||||
getPluginPostLoadSteps().emplace_back(step);
|
getPluginPostLoadSteps().emplace_back(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ EXPORT void AddPostLoadStep(std::function<void()>);
|
|||||||
EXPORT void AddIntervalResetStep(std::function<void()>);
|
EXPORT void AddIntervalResetStep(std::function<void()>);
|
||||||
void RunSaveSteps(obs_data_t *);
|
void RunSaveSteps(obs_data_t *);
|
||||||
void RunLoadSteps(obs_data_t *);
|
void RunLoadSteps(obs_data_t *);
|
||||||
EXPORT void RunPostLoadSteps();
|
EXPORT void RunAndClearPostLoadSteps();
|
||||||
void ClearPostLoadSteps();
|
void ClearPostLoadSteps();
|
||||||
|
|
||||||
EXPORT void AddPluginInitStep(std::function<void()>);
|
EXPORT void AddPluginInitStep(std::function<void()>);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
ResourceTable::ResourceTable(QTabWidget *parent, const QString &help,
|
ResourceTable::ResourceTable(QWidget *parent, const QString &help,
|
||||||
const QString &addToolTip,
|
const QString &addToolTip,
|
||||||
const QString &removeToolTip,
|
const QString &removeToolTip,
|
||||||
const QStringList &headers,
|
const QStringList &headers,
|
||||||
@@ -65,13 +65,16 @@ ResourceTable::ResourceTable(QTabWidget *parent, const QString &help,
|
|||||||
[openSettings]() { openSettings(); });
|
[openSettings]() { openSettings(); });
|
||||||
|
|
||||||
auto settingsShortcut = new QShortcut(QKeySequence("F2"), this);
|
auto settingsShortcut = new QShortcut(QKeySequence("F2"), this);
|
||||||
|
settingsShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||||
QWidget::connect(settingsShortcut, &QShortcut::activated, this,
|
QWidget::connect(settingsShortcut, &QShortcut::activated, this,
|
||||||
openSettings);
|
openSettings);
|
||||||
auto removeShortcut = new QShortcut(QKeySequence("Del"), this);
|
auto removeShortcut = new QShortcut(QKeySequence("Del"), this);
|
||||||
|
removeShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||||
QWidget::connect(removeShortcut, &QShortcut::activated, this,
|
QWidget::connect(removeShortcut, &QShortcut::activated, this,
|
||||||
[this]() { Remove(); });
|
[this]() { Remove(); });
|
||||||
|
|
||||||
auto newShortcut = new QShortcut(QKeySequence("Ctrl+N"), this);
|
auto newShortcut = new QShortcut(QKeySequence("Ctrl+N"), this);
|
||||||
|
newShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
||||||
QWidget::connect(newShortcut, &QShortcut::activated, this,
|
QWidget::connect(newShortcut, &QShortcut::activated, this,
|
||||||
[this]() { Add(); });
|
[this]() { Add(); });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class ADVSS_EXPORT ResourceTable : public QWidget {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ResourceTable(QTabWidget *parent, const QString &help,
|
ResourceTable(QWidget *parent, const QString &help,
|
||||||
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);
|
||||||
|
|||||||
@@ -103,10 +103,11 @@ void SceneSelection::Load(obs_data_t *obj, const char *name,
|
|||||||
OBSDataAutoRelease data =
|
OBSDataAutoRelease data =
|
||||||
obs_data_get_obj(obj, selectionSaveName.data());
|
obs_data_get_obj(obj, selectionSaveName.data());
|
||||||
|
|
||||||
if (obs_data_has_user_value(data, canvasSaveName.data())) {
|
const char *canvasName =
|
||||||
_canvas = GetWeakCanvasByName(
|
obs_data_get_string(data, canvasSaveName.data());
|
||||||
obs_data_get_string(data, canvasSaveName.data()));
|
_canvas = GetWeakCanvasByName(
|
||||||
} else {
|
obs_data_get_string(data, canvasSaveName.data()));
|
||||||
|
if (strcmp(canvasName, "") == 0) {
|
||||||
OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas();
|
OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas();
|
||||||
_canvas = obs_canvas_get_weak_canvas(mainCanvas);
|
_canvas = obs_canvas_get_weak_canvas(mainCanvas);
|
||||||
obs_weak_canvas_release(_canvas);
|
obs_weak_canvas_release(_canvas);
|
||||||
@@ -239,22 +240,26 @@ void SceneSelection::ResolveVariables()
|
|||||||
_type = Type::SCENE;
|
_type = Type::SCENE;
|
||||||
}
|
}
|
||||||
|
|
||||||
SceneSelection SceneSelectionWidget::CurrentSelection()
|
static obs_weak_canvas_t *getWeakRefToMainCanvas()
|
||||||
{
|
{
|
||||||
SceneSelection s;
|
static auto canvas = obs_get_main_canvas();
|
||||||
|
static auto weakCanvas = obs_canvas_get_weak_canvas(canvas);
|
||||||
static auto mainCanvas = obs_get_main_canvas();
|
|
||||||
static auto mainCanvasWeak = obs_canvas_get_weak_canvas(mainCanvas);
|
|
||||||
[[maybe_unused]] static const bool _ = []() {
|
[[maybe_unused]] static const bool _ = []() {
|
||||||
// Let's just hope we don't have to deal with selecting scenes
|
// Let's just hope we don't have to deal with selecting scenes
|
||||||
// when the OBS main canvas gets deleted and release the
|
// when the OBS main canvas gets deleted and release the
|
||||||
// references here already to avoid reporting leaks on shutdown
|
// references here already to avoid reporting leaks on shutdown
|
||||||
obs_canvas_release(mainCanvas);
|
obs_canvas_release(canvas);
|
||||||
obs_weak_canvas_release(mainCanvasWeak);
|
obs_weak_canvas_release(weakCanvas);
|
||||||
return true;
|
return true;
|
||||||
}();
|
}();
|
||||||
|
return weakCanvas;
|
||||||
|
}
|
||||||
|
|
||||||
s._canvas = _forceMainCanvas ? OBSWeakCanvas(mainCanvasWeak)
|
SceneSelection SceneSelectionWidget::CurrentSelection()
|
||||||
|
{
|
||||||
|
SceneSelection s;
|
||||||
|
|
||||||
|
s._canvas = _forceMainCanvas ? OBSWeakCanvas(getWeakRefToMainCanvas())
|
||||||
: _canvas->GetCanvas();
|
: _canvas->GetCanvas();
|
||||||
|
|
||||||
const int idx = _scenes->currentIndex();
|
const int idx = _scenes->currentIndex();
|
||||||
@@ -330,6 +335,7 @@ static QStringList getCanvasScenesList(obs_weak_canvas_t *weakCanvas)
|
|||||||
|
|
||||||
QStringList list;
|
QStringList list;
|
||||||
obs_canvas_enum_scenes(canvas, enumCanvasScenes, &list);
|
obs_canvas_enum_scenes(canvas, enumCanvasScenes, &list);
|
||||||
|
list.sort();
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,6 +348,10 @@ void SceneSelectionWidget::Reset()
|
|||||||
|
|
||||||
void SceneSelectionWidget::PopulateSceneSelection(obs_weak_canvas_t *canvas)
|
void SceneSelectionWidget::PopulateSceneSelection(obs_weak_canvas_t *canvas)
|
||||||
{
|
{
|
||||||
|
if (_forceMainCanvas) {
|
||||||
|
canvas = getWeakRefToMainCanvas();
|
||||||
|
}
|
||||||
|
|
||||||
_scenes->clear();
|
_scenes->clear();
|
||||||
if ((_current || _previous)) {
|
if ((_current || _previous)) {
|
||||||
const bool isMain = IsMainCanvas(canvas);
|
const bool isMain = IsMainCanvas(canvas);
|
||||||
@@ -418,7 +428,7 @@ SceneSelectionWidget::SceneSelectionWidget(QWidget *parent, bool variables,
|
|||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
if (GetCanvasCount() <= 1) {
|
if (GetCanvasCount() <= 1) {
|
||||||
_canvas->hide();
|
LockToMainCanvas();
|
||||||
}
|
}
|
||||||
|
|
||||||
Resize();
|
Resize();
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
OBSWeakSource _scene;
|
OBSWeakSource _scene;
|
||||||
OBSWeakCanvas _canvas;
|
OBSWeakCanvas _canvas = GetMainCanvas();
|
||||||
SceneGroup *_group = nullptr;
|
SceneGroup *_group = nullptr;
|
||||||
std::weak_ptr<Variable> _variable;
|
std::weak_ptr<Variable> _variable;
|
||||||
Type _type = Type::SCENE;
|
Type _type = Type::SCENE;
|
||||||
|
|||||||
@@ -199,7 +199,17 @@ std::chrono::high_resolution_clock::time_point GetLastSceneChangeTime()
|
|||||||
|
|
||||||
OBSWeakSource GetCurrentScene()
|
OBSWeakSource GetCurrentScene()
|
||||||
{
|
{
|
||||||
return switcher->currentScene;
|
if (switcher->currentScene) {
|
||||||
|
return switcher->currentScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there wasn't any scene switch yet switcher->currentScene will be
|
||||||
|
// null and we must use obs_frontend_get_current_scene() instead
|
||||||
|
OBSSourceAutoRelease currentSceneSource =
|
||||||
|
obs_frontend_get_current_scene();
|
||||||
|
OBSWeakSourceAutoRelease currentSceneWeakSource =
|
||||||
|
obs_source_get_weak_source(currentSceneSource);
|
||||||
|
return currentSceneWeakSource.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSWeakSource GetPreviousScene()
|
OBSWeakSource GetPreviousScene()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "source-helpers.hpp"
|
#include "source-helpers.hpp"
|
||||||
|
#include "canvas-helpers.hpp"
|
||||||
|
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
@@ -28,15 +29,43 @@ std::string GetWeakSourceName(obs_weak_source_t *weak_source)
|
|||||||
|
|
||||||
OBSWeakSource GetWeakSourceByName(const char *name)
|
OBSWeakSource GetWeakSourceByName(const char *name)
|
||||||
{
|
{
|
||||||
OBSWeakSource weak;
|
OBSSourceAutoRelease source = obs_get_source_by_name(name);
|
||||||
obs_source_t *source = obs_get_source_by_name(name);
|
|
||||||
if (source) {
|
if (source) {
|
||||||
weak = obs_source_get_weak_source(source);
|
return OBSGetWeakRef(source);
|
||||||
obs_weak_source_release(weak);
|
|
||||||
obs_source_release(source);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return weak;
|
#if LIBOBS_API_VER > MAKE_SEMANTIC_VERSION(31, 1, 0)
|
||||||
|
struct SearchData {
|
||||||
|
const char *name;
|
||||||
|
OBSWeakSource &scene;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const auto enumCanvasScenes = [](void *dataPtr,
|
||||||
|
obs_source_t *source) -> bool {
|
||||||
|
auto data = static_cast<SearchData *>(dataPtr);
|
||||||
|
if (strcmp(data->name, obs_source_get_name(source)) == 0) {
|
||||||
|
data->scene = OBSGetWeakRef(source);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const auto enumCanvases = [](void *dataPtr,
|
||||||
|
obs_canvas_t *canvas) -> bool {
|
||||||
|
obs_canvas_enum_scenes(canvas, enumCanvasScenes, dataPtr);
|
||||||
|
|
||||||
|
auto data = static_cast<SearchData *>(dataPtr);
|
||||||
|
return data->scene == nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
OBSWeakSource weakScene;
|
||||||
|
SearchData searchData{name, weakScene};
|
||||||
|
obs_enum_canvases(enumCanvases, &searchData);
|
||||||
|
return weakScene;
|
||||||
|
#else
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
OBSWeakSource GetWeakSourceByQString(const QString &name)
|
OBSWeakSource GetWeakSourceByQString(const QString &name)
|
||||||
|
|||||||
@@ -58,6 +58,9 @@ StringListEdit::StringListEdit(
|
|||||||
_filterCallback(filter),
|
_filterCallback(filter),
|
||||||
_preprocessCallback(preprocess)
|
_preprocessCallback(preprocess)
|
||||||
{
|
{
|
||||||
|
if (_addString.isEmpty()) {
|
||||||
|
_addString = obs_module_text("AdvSceneSwitcher.windowTitle");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StringListEdit::SetStringList(const StringList &list)
|
void StringListEdit::SetStringList(const StringList &list)
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ namespace advss {
|
|||||||
|
|
||||||
class StringList : public QList<StringVariable> {
|
class StringList : public QList<StringVariable> {
|
||||||
public:
|
public:
|
||||||
|
using QList<StringVariable>::QList;
|
||||||
|
|
||||||
EXPORT bool Save(obs_data_t *obj, const char *name,
|
EXPORT bool Save(obs_data_t *obj, const char *name,
|
||||||
const char *elementName = "string") const;
|
const char *elementName = "string") const;
|
||||||
EXPORT bool Load(obs_data_t *obj, const char *name,
|
EXPORT bool Load(obs_data_t *obj, const char *name,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "tab-helpers.hpp"
|
#include "tab-helpers.hpp"
|
||||||
#include "log-helper.hpp"
|
#include "log-helper.hpp"
|
||||||
#include "obs-module-helper.hpp"
|
#include "obs-module-helper.hpp"
|
||||||
|
#include "plugin-state-helpers.hpp"
|
||||||
|
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
#include <QTabBar>
|
#include <QTabBar>
|
||||||
@@ -33,6 +34,21 @@ struct TabCallbacks {
|
|||||||
static std::unordered_map<const char *, TabCallbacks> createTabCallbacks;
|
static std::unordered_map<const char *, TabCallbacks> createTabCallbacks;
|
||||||
|
|
||||||
static int lastOpenedTab = -1;
|
static int lastOpenedTab = -1;
|
||||||
|
static bool alwaysShowTabs = false;
|
||||||
|
|
||||||
|
[[maybe_unused]] static bool _ = []() {
|
||||||
|
AddPluginInitStep([]() {
|
||||||
|
AddSaveStep([](obs_data_t *data) {
|
||||||
|
obs_data_set_bool(data, "alwaysShowTabs",
|
||||||
|
alwaysShowTabs);
|
||||||
|
});
|
||||||
|
AddLoadStep([](obs_data_t *data) {
|
||||||
|
alwaysShowTabs =
|
||||||
|
obs_data_get_bool(data, "alwaysShowTabs");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}();
|
||||||
|
|
||||||
void SetTabVisibleByName(QTabWidget *tabWidget, bool visible,
|
void SetTabVisibleByName(QTabWidget *tabWidget, bool visible,
|
||||||
const QString &name)
|
const QString &name)
|
||||||
@@ -197,7 +213,41 @@ void SetupOtherTabs(QTabWidget *tabWidget)
|
|||||||
.c_str());
|
.c_str());
|
||||||
tabWidget->insertTab(0, widget, tabText);
|
tabWidget->insertTab(0, widget, tabText);
|
||||||
callbacks.setupTab(tabWidget);
|
callbacks.setupTab(tabWidget);
|
||||||
|
|
||||||
|
if (alwaysShowTabs) {
|
||||||
|
tabWidget->setTabVisible(0, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetupShowAllTabsCheckBox(QCheckBox *checkBox, QTabWidget *tabWidget)
|
||||||
|
{
|
||||||
|
const auto stateChanged = [tabWidget](int state) {
|
||||||
|
const bool newState = (state != 0);
|
||||||
|
if (newState == alwaysShowTabs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
alwaysShowTabs = newState;
|
||||||
|
|
||||||
|
// Only show currently hidden tabs, but don't hide tabs which
|
||||||
|
// are already visible
|
||||||
|
if (!alwaysShowTabs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &[name, _] : createTabCallbacks) {
|
||||||
|
const auto localeKey =
|
||||||
|
std::string("AdvSceneSwitcher.") + name +
|
||||||
|
".title";
|
||||||
|
auto tabText = obs_module_text(localeKey.c_str());
|
||||||
|
SetTabVisibleByName(tabWidget, true, tabText);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
checkBox->setChecked(alwaysShowTabs);
|
||||||
|
QWidget::connect(checkBox, &QCheckBox::stateChanged, checkBox,
|
||||||
|
stateChanged);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#include "export-symbol-helper.hpp"
|
#include "export-symbol-helper.hpp"
|
||||||
|
|
||||||
#include <obs-data.h>
|
#include <obs-data.h>
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
#include <QTabWidget>
|
#include <QTabWidget>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -19,5 +21,6 @@ void SetupOtherTabs(QTabWidget *tabWidget);
|
|||||||
void SaveTabOrder(obs_data_t *obj);
|
void SaveTabOrder(obs_data_t *obj);
|
||||||
void LoadTabOrder(obs_data_t *obj);
|
void LoadTabOrder(obs_data_t *obj);
|
||||||
bool MacroTabIsInFocus();
|
bool MacroTabIsInFocus();
|
||||||
|
void SetupShowAllTabsCheckBox(QCheckBox *checkBox, QTabWidget *tabWidget);
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -190,29 +190,6 @@ static bool isMatchingNestedMacroAction(MacroAction *action, const Macro *macro)
|
|||||||
return nestedMacroAction->_nestedMacro.get() == macro;
|
return nestedMacroAction->_nestedMacro.get() == macro;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void appendNestedMacros(std::deque<std::shared_ptr<Macro>> ¯os,
|
|
||||||
Macro *macro)
|
|
||||||
{
|
|
||||||
if (!macro) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &action : macro->Actions()) {
|
|
||||||
const auto nestedMacroAction =
|
|
||||||
dynamic_cast<MacroActionMacro *>(action.get());
|
|
||||||
if (nestedMacroAction) {
|
|
||||||
macros.push_back(nestedMacroAction->_nestedMacro);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const auto &action : macro->ElseActions()) {
|
|
||||||
const auto nestedMacroAction =
|
|
||||||
dynamic_cast<MacroActionMacro *>(action.get());
|
|
||||||
if (nestedMacroAction) {
|
|
||||||
macros.push_back(nestedMacroAction->_nestedMacro);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Macro *getParentMacro(const Macro *targetMacro,
|
static Macro *getParentMacro(const Macro *targetMacro,
|
||||||
const std::vector<Macro *> ¯os)
|
const std::vector<Macro *> ¯os)
|
||||||
{
|
{
|
||||||
@@ -263,8 +240,10 @@ static Macro *getParentMacro(const Macro *targetMacro,
|
|||||||
|
|
||||||
static Macro *getParentMacro(const Macro *macro)
|
static Macro *getParentMacro(const Macro *macro)
|
||||||
{
|
{
|
||||||
|
const auto &topLevelMacros = GetTopLevelMacros();
|
||||||
std::vector<Macro *> macros;
|
std::vector<Macro *> macros;
|
||||||
for (const auto ¯o : GetMacros()) {
|
macros.reserve(topLevelMacros.size());
|
||||||
|
for (const auto ¯o : topLevelMacros) {
|
||||||
macros.emplace_back(macro.get());
|
macros.emplace_back(macro.get());
|
||||||
}
|
}
|
||||||
return getParentMacro(macro, macros);
|
return getParentMacro(macro, macros);
|
||||||
@@ -301,8 +280,9 @@ void TempVariableRef::Save(obs_data_t *obj, Macro *macro,
|
|||||||
|
|
||||||
void TempVariableRef::Load(obs_data_t *obj, Macro *macroPtr, const char *name)
|
void TempVariableRef::Load(obs_data_t *obj, Macro *macroPtr, const char *name)
|
||||||
{
|
{
|
||||||
|
const auto macros = GetAllMacros();
|
||||||
std::weak_ptr<Macro> macro;
|
std::weak_ptr<Macro> macro;
|
||||||
for (const auto ¯oShared : GetMacros()) {
|
for (const auto ¯oShared : macros) {
|
||||||
if (macroShared.get() == macroPtr) {
|
if (macroShared.get() == macroPtr) {
|
||||||
macro = macroShared;
|
macro = macroShared;
|
||||||
break;
|
break;
|
||||||
@@ -340,9 +320,9 @@ void TempVariableRef::PostLoad(int idx, SegmentType type,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Macro *macro = nullptr;
|
auto macro = childMacro.get();
|
||||||
for (int i = 0; i < _depth; i++) {
|
for (int i = 0; i < _depth; i++) {
|
||||||
macro = getParentMacro(childMacro.get());
|
macro = getParentMacro(macro);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!macro) {
|
if (!macro) {
|
||||||
@@ -486,15 +466,9 @@ void TempVariableSelection::MacroSegmentsChanged()
|
|||||||
SetVariable(currentSelection);
|
SetVariable(currentSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TempVariableSelection::SegmentTempVarsChanged(MacroSegment *segment)
|
void TempVariableSelection::SegmentTempVarsChanged(MacroSegment *)
|
||||||
{
|
{
|
||||||
const auto currentSegment = GetSegment();
|
MacroSegmentsChanged();
|
||||||
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)
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ private:
|
|||||||
void PostLoad(int idx, SegmentType, const std::weak_ptr<Macro> &);
|
void PostLoad(int idx, SegmentType, const std::weak_ptr<Macro> &);
|
||||||
|
|
||||||
std::string _id = "";
|
std::string _id = "";
|
||||||
std::weak_ptr<MacroSegment> _segment;
|
std::weak_ptr<MacroSegment> _segment = {};
|
||||||
int _depth = 0;
|
int _depth = 0;
|
||||||
|
|
||||||
friend TempVariable;
|
friend TempVariable;
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ std::string GetThemeTypeName()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void QeueUITask(void (*task)(void *param), void *param)
|
void QueueUITask(void (*task)(void *param), void *param)
|
||||||
{
|
{
|
||||||
obs_queue_task(OBS_TASK_UI, task, param, false);
|
obs_queue_task(OBS_TASK_UI, task, param, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ EXPORT void DisplayTrayMessage(const QString &title, const QString &msg,
|
|||||||
EXPORT std::string GetThemeTypeName();
|
EXPORT std::string GetThemeTypeName();
|
||||||
EXPORT QWidget *GetSettingsWindow();
|
EXPORT QWidget *GetSettingsWindow();
|
||||||
|
|
||||||
void QeueUITask(void (*task)(void *param), void *param);
|
EXPORT void QueueUITask(void (*task)(void *param), void *param);
|
||||||
|
|
||||||
bool IsCursorInWidgetArea(QWidget *widget);
|
bool IsCursorInWidgetArea(QWidget *widget);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
#include "ui-helpers.hpp"
|
#include "ui-helpers.hpp"
|
||||||
#include "variable.hpp"
|
#include "variable.hpp"
|
||||||
|
|
||||||
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
|
#include <QLayout>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
@@ -16,14 +19,62 @@ static bool registerTab();
|
|||||||
static void setupTab(QTabWidget *);
|
static void setupTab(QTabWidget *);
|
||||||
static bool registerTabDone = registerTab();
|
static bool registerTabDone = registerTab();
|
||||||
|
|
||||||
static VariableTable *tabWidget = nullptr;
|
static VariableTable *dockWidget = nullptr;
|
||||||
|
static bool addDock = false;
|
||||||
|
|
||||||
|
static VariableTable::Settings tabSettings;
|
||||||
|
static VariableTable::Settings dockSettings;
|
||||||
|
|
||||||
|
static void save(obs_data_t *data)
|
||||||
|
{
|
||||||
|
tabSettings.Save(data, "tabSettings");
|
||||||
|
dockSettings.Save(data, "dockSettings");
|
||||||
|
obs_data_set_bool(data, "addVariablesDock", addDock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void enableDock(bool enable)
|
||||||
|
{
|
||||||
|
if (OBSIsShuttingDown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_frontend_remove_dock("advss-variable-dock");
|
||||||
|
|
||||||
|
addDock = enable;
|
||||||
|
if (!addDock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dockWidget = new VariableTable(dockSettings);
|
||||||
|
dockWidget->HideDockOptions();
|
||||||
|
if (obs_frontend_add_dock_by_id(
|
||||||
|
"advss-variable-dock",
|
||||||
|
obs_module_text("AdvSceneSwitcher.variableTab.title"),
|
||||||
|
dockWidget)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
blog(LOG_INFO, "failed to register variable dock!");
|
||||||
|
dockWidget->deleteLater();
|
||||||
|
dockWidget = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void load(obs_data_t *data)
|
||||||
|
{
|
||||||
|
tabSettings.Load(data, "tabSettings");
|
||||||
|
dockSettings.Load(data, "dockSettings");
|
||||||
|
|
||||||
|
enableDock(obs_data_get_bool(data, "addVariablesDock"));
|
||||||
|
}
|
||||||
|
|
||||||
static bool registerTab()
|
static bool registerTab()
|
||||||
{
|
{
|
||||||
AddPluginInitStep([]() {
|
AddPluginInitStep([]() {
|
||||||
AddSetupTabCallback("variableTab", VariableTable::Create,
|
AddSetupTabCallback("variableTab",
|
||||||
setupTab);
|
VariableTable::CreateTabTable, setupTab);
|
||||||
});
|
});
|
||||||
|
AddSaveStep(save);
|
||||||
|
AddLoadStep(load);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,10 +85,14 @@ static void setTabVisible(QTabWidget *tabWidget, bool visible)
|
|||||||
obs_module_text("AdvSceneSwitcher.variableTab.title"));
|
obs_module_text("AdvSceneSwitcher.variableTab.title"));
|
||||||
}
|
}
|
||||||
|
|
||||||
VariableTable *VariableTable::Create()
|
VariableTable *VariableTable::CreateTabTable()
|
||||||
{
|
{
|
||||||
tabWidget = new VariableTable();
|
return new VariableTable(tabSettings);
|
||||||
return tabWidget;
|
}
|
||||||
|
|
||||||
|
void VariableTable::HideDockOptions() const
|
||||||
|
{
|
||||||
|
_addDock->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VariableTable::Add()
|
void VariableTable::Add()
|
||||||
@@ -163,15 +218,14 @@ static void updateVariableStatus(QTableWidget *table)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void openSettingsDialog()
|
static void openSettingsDialog(VariableTable *table)
|
||||||
{
|
{
|
||||||
auto selectedRows =
|
auto selectedRows = table->Table()->selectionModel()->selectedRows();
|
||||||
tabWidget->Table()->selectionModel()->selectedRows();
|
|
||||||
if (selectedRows.empty()) {
|
if (selectedRows.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cell = tabWidget->Table()->item(selectedRows.last().row(), 0);
|
auto cell = table->Table()->item(selectedRows.last().row(), 0);
|
||||||
if (!cell) {
|
if (!cell) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -194,15 +248,14 @@ static void openSettingsDialog()
|
|||||||
|
|
||||||
void VariableTable::Remove()
|
void VariableTable::Remove()
|
||||||
{
|
{
|
||||||
auto selectedRows =
|
auto selectedRows = Table()->selectionModel()->selectedRows();
|
||||||
tabWidget->Table()->selectionModel()->selectedRows();
|
|
||||||
if (selectedRows.empty()) {
|
if (selectedRows.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList varNames;
|
QStringList varNames;
|
||||||
for (const auto &row : selectedRows) {
|
for (const auto &row : selectedRows) {
|
||||||
auto cell = tabWidget->Table()->item(row.row(), 0);
|
auto cell = Table()->item(row.row(), 0);
|
||||||
if (!cell) {
|
if (!cell) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -235,7 +288,52 @@ void VariableTable::Remove()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VariableTable::VariableTable(QTabWidget *parent)
|
void VariableTable::Filter()
|
||||||
|
{
|
||||||
|
const auto itemMatches = [&](const QTableWidgetItem *item) {
|
||||||
|
if (!item) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_settings.searchString.empty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto text = item->text();
|
||||||
|
|
||||||
|
if (_settings.regex.Enabled()) {
|
||||||
|
return _settings.regex.Matches(text.toStdString(),
|
||||||
|
_settings.searchString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return text.contains(
|
||||||
|
QString::fromStdString(_settings.searchString),
|
||||||
|
Qt::CaseInsensitive);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int row = 0; row < Table()->rowCount(); ++row) {
|
||||||
|
bool match = false;
|
||||||
|
|
||||||
|
if (_settings.searchType == Settings::SearchType::ALL) {
|
||||||
|
for (int col = 0; col < Table()->columnCount(); ++col) {
|
||||||
|
if (itemMatches(Table()->item(row, col))) {
|
||||||
|
match = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (itemMatches(Table()->item(
|
||||||
|
row,
|
||||||
|
static_cast<int>(_settings.searchType)))) {
|
||||||
|
match = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Table()->setRowHidden(row, !match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VariableTable::VariableTable(Settings &settings, QWidget *parent)
|
||||||
: ResourceTable(
|
: ResourceTable(
|
||||||
parent, obs_module_text("AdvSceneSwitcher.variableTab.help"),
|
parent, obs_module_text("AdvSceneSwitcher.variableTab.help"),
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
@@ -253,13 +351,113 @@ VariableTable::VariableTable(QTabWidget *parent)
|
|||||||
"AdvSceneSwitcher.variableTab.lastUsed.header")
|
"AdvSceneSwitcher.variableTab.lastUsed.header")
|
||||||
<< obs_module_text(
|
<< obs_module_text(
|
||||||
"AdvSceneSwitcher.variableTab.lastChanged.header"),
|
"AdvSceneSwitcher.variableTab.lastChanged.header"),
|
||||||
openSettingsDialog)
|
[this]() { openSettingsDialog(this); }),
|
||||||
|
_searchField(new QLineEdit(this)),
|
||||||
|
_clear(new QPushButton(this)),
|
||||||
|
_searchType(new QComboBox(this)),
|
||||||
|
_regexWidget(new RegexConfigWidget(this)),
|
||||||
|
_addDock(new QCheckBox(
|
||||||
|
obs_module_text("AdvSceneSwitcher.variableTab.addDock"))),
|
||||||
|
_settings(settings)
|
||||||
{
|
{
|
||||||
|
_clear->setMaximumWidth(22);
|
||||||
|
SetButtonIcon(_clear, GetThemeTypeName() == "Light"
|
||||||
|
? "theme:Light/close.svg"
|
||||||
|
: "theme:Dark/close.svg");
|
||||||
|
_clear->setToolTip(
|
||||||
|
obs_module_text("AdvSceneSwitcher.variableTab.clear"));
|
||||||
|
_clear->setDisabled(_settings.searchString.empty());
|
||||||
|
|
||||||
|
connect(_clear, &QPushButton::clicked, this, [this]() {
|
||||||
|
_searchField->setText("");
|
||||||
|
_clear->setDisabled(true);
|
||||||
|
});
|
||||||
|
|
||||||
for (const auto &variable : GetVariables()) {
|
for (const auto &variable : GetVariables()) {
|
||||||
auto v = std::static_pointer_cast<Variable>(variable);
|
auto v = std::static_pointer_cast<Variable>(variable);
|
||||||
AddItemTableRow(Table(), getCellLabels(v.get()));
|
AddItemTableRow(Table(), getCellLabels(v.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connect(Table(), &QTableWidget::itemChanged, this,
|
||||||
|
[this]() { Filter(); });
|
||||||
|
|
||||||
|
_searchField->setPlaceholderText(obs_module_text(
|
||||||
|
("AdvSceneSwitcher.variableTab.search.placeholder")));
|
||||||
|
_searchField->setText(QString::fromStdString(_settings.searchString));
|
||||||
|
connect(_searchField, &QLineEdit::textChanged, this,
|
||||||
|
[this](const QString &text) {
|
||||||
|
_settings.searchString = text.toStdString();
|
||||||
|
_clear->setDisabled(text.isEmpty());
|
||||||
|
Filter();
|
||||||
|
});
|
||||||
|
|
||||||
|
_searchType->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.variableTab.search.all"),
|
||||||
|
Settings::SearchType::ALL);
|
||||||
|
_searchType->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.variableTab.search.name"),
|
||||||
|
Settings::SearchType::NAME);
|
||||||
|
_searchType->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.variableTab.search.value"),
|
||||||
|
Settings::SearchType::VALUE);
|
||||||
|
_searchType->setCurrentIndex(
|
||||||
|
_searchType->findData(_settings.searchType));
|
||||||
|
|
||||||
|
connect(_searchType, &QComboBox::currentIndexChanged, this, [this]() {
|
||||||
|
_settings.searchType = static_cast<Settings::SearchType>(
|
||||||
|
_searchType->currentData().toInt());
|
||||||
|
});
|
||||||
|
|
||||||
|
_regexWidget->SetRegexConfig(_settings.regex);
|
||||||
|
connect(_regexWidget, &RegexConfigWidget::RegexConfigChanged, this,
|
||||||
|
[this](const RegexConfig ®ex) {
|
||||||
|
_settings.regex = regex;
|
||||||
|
Filter();
|
||||||
|
});
|
||||||
|
|
||||||
|
_addDock->setChecked(addDock);
|
||||||
|
connect(_addDock, &QCheckBox::stateChanged, this,
|
||||||
|
[this](int checked) { enableDock(checked); });
|
||||||
|
|
||||||
|
QWidget::connect(VariableSignalManager::Instance(),
|
||||||
|
&VariableSignalManager::Rename, this,
|
||||||
|
[this](const QString &oldName,
|
||||||
|
const QString &newName) {
|
||||||
|
RenameItemTableRow(Table(), oldName, newName);
|
||||||
|
});
|
||||||
|
QWidget::connect(
|
||||||
|
VariableSignalManager::Instance(), &VariableSignalManager::Add,
|
||||||
|
this, [this](const QString &name) {
|
||||||
|
AddItemTableRow(
|
||||||
|
Table(),
|
||||||
|
getCellLabels(GetVariableByQString(name)));
|
||||||
|
SetHelpVisible(false);
|
||||||
|
HighlightAddButton(false);
|
||||||
|
});
|
||||||
|
QWidget::connect(VariableSignalManager::Instance(),
|
||||||
|
&VariableSignalManager::Remove, this,
|
||||||
|
[this](const QString &name) {
|
||||||
|
RemoveItemTableRow(Table(), name);
|
||||||
|
if (Table()->rowCount() == 0) {
|
||||||
|
SetHelpVisible(true);
|
||||||
|
HighlightAddButton(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
auto timer = new QTimer(this);
|
||||||
|
timer->setInterval(1000);
|
||||||
|
QWidget::connect(timer, &QTimer::timeout,
|
||||||
|
[this]() { updateVariableStatus(Table()); });
|
||||||
|
timer->start();
|
||||||
|
|
||||||
|
auto searchLayout = new QHBoxLayout();
|
||||||
|
searchLayout->addWidget(_searchField);
|
||||||
|
searchLayout->addWidget(_clear);
|
||||||
|
searchLayout->addWidget(_searchType);
|
||||||
|
searchLayout->addWidget(_regexWidget);
|
||||||
|
searchLayout->addWidget(_addDock);
|
||||||
|
qobject_cast<QVBoxLayout *>(layout())->insertLayout(0, searchLayout);
|
||||||
|
|
||||||
SetHelpVisible(GetVariables().empty());
|
SetHelpVisible(GetVariables().empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,36 +468,26 @@ static void setupTab(QTabWidget *tab)
|
|||||||
}
|
}
|
||||||
|
|
||||||
QWidget::connect(VariableSignalManager::Instance(),
|
QWidget::connect(VariableSignalManager::Instance(),
|
||||||
&VariableSignalManager::Rename, tab,
|
&VariableSignalManager::Add, tab,
|
||||||
[](const QString &oldName, const QString &newName) {
|
[tab](const QString &) { setTabVisible(tab, true); });
|
||||||
RenameItemTableRow(tabWidget->Table(), oldName,
|
}
|
||||||
newName);
|
|
||||||
});
|
|
||||||
QWidget::connect(
|
|
||||||
VariableSignalManager::Instance(), &VariableSignalManager::Add,
|
|
||||||
tab, [tab](const QString &name) {
|
|
||||||
AddItemTableRow(
|
|
||||||
tabWidget->Table(),
|
|
||||||
getCellLabels(GetVariableByQString(name)));
|
|
||||||
tabWidget->SetHelpVisible(false);
|
|
||||||
tabWidget->HighlightAddButton(false);
|
|
||||||
setTabVisible(tab, true);
|
|
||||||
});
|
|
||||||
QWidget::connect(VariableSignalManager::Instance(),
|
|
||||||
&VariableSignalManager::Remove, tab,
|
|
||||||
[](const QString &name) {
|
|
||||||
RemoveItemTableRow(tabWidget->Table(), name);
|
|
||||||
if (tabWidget->Table()->rowCount() == 0) {
|
|
||||||
tabWidget->SetHelpVisible(true);
|
|
||||||
tabWidget->HighlightAddButton(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
auto timer = new QTimer(tabWidget);
|
void VariableTable::Settings::Save(obs_data_t *data, const char *name)
|
||||||
timer->setInterval(1000);
|
{
|
||||||
QWidget::connect(timer, &QTimer::timeout,
|
OBSDataAutoRelease settings = obs_data_create();
|
||||||
[]() { updateVariableStatus(tabWidget->Table()); });
|
obs_data_set_int(settings, "searchType", static_cast<int>(searchType));
|
||||||
timer->start();
|
obs_data_set_string(settings, "searchString", searchString.c_str());
|
||||||
|
regex.Save(settings);
|
||||||
|
obs_data_set_obj(data, name, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VariableTable::Settings::Load(obs_data_t *data, const char *name)
|
||||||
|
{
|
||||||
|
OBSDataAutoRelease settings = obs_data_get_obj(data, name);
|
||||||
|
searchType = static_cast<SearchType>(
|
||||||
|
obs_data_get_int(settings, "searchType"));
|
||||||
|
searchString = obs_data_get_string(settings, "searchString");
|
||||||
|
regex.Load(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "resource-table.hpp"
|
#include "resource-table.hpp"
|
||||||
|
#include "regex-config.hpp"
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -7,14 +10,34 @@ class VariableTable final : public ResourceTable {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static VariableTable *Create();
|
struct Settings {
|
||||||
|
void Save(obs_data_t *data, const char *name);
|
||||||
|
void Load(obs_data_t *data, const char *name);
|
||||||
|
|
||||||
|
enum SearchType { ALL = -1, NAME = 0, VALUE = 1 };
|
||||||
|
|
||||||
|
SearchType searchType = SearchType::ALL;
|
||||||
|
std::string searchString;
|
||||||
|
RegexConfig regex;
|
||||||
|
};
|
||||||
|
|
||||||
|
VariableTable(Settings &settings, QWidget *parent = nullptr);
|
||||||
|
static VariableTable *CreateTabTable();
|
||||||
|
void HideDockOptions() const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void Add();
|
void Add();
|
||||||
void Remove();
|
void Remove();
|
||||||
|
void Filter();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VariableTable(QTabWidget *parent = nullptr);
|
QLineEdit *_searchField;
|
||||||
|
QPushButton *_clear;
|
||||||
|
QComboBox *_searchType;
|
||||||
|
RegexConfigWidget *_regexWidget;
|
||||||
|
QCheckBox *_addDock;
|
||||||
|
|
||||||
|
Settings &_settings;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -456,7 +456,7 @@ void ImportVariables(obs_data_t *data)
|
|||||||
|
|
||||||
obs_data_array_release(array);
|
obs_data_array_release(array);
|
||||||
|
|
||||||
QeueUITask(signalImportedVariables, importedVars);
|
QueueUITask(signalImportedVariables, importedVars);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point GetLastVariableChangeTime()
|
std::chrono::high_resolution_clock::time_point GetLastVariableChangeTime()
|
||||||
|
|||||||
@@ -261,6 +261,14 @@ std::optional<std::string> GetTextInWindow(const std::string &window)
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DWORD pid = 0;
|
||||||
|
DWORD thid = 0;
|
||||||
|
thid = GetWindowThreadProcessId(hwnd, &pid);
|
||||||
|
// Calling CoCreateInstance() on the OBS windows might cause a deadlock
|
||||||
|
if (GetCurrentProcessId() == pid) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
IUIAutomation *automation = nullptr;
|
IUIAutomation *automation = nullptr;
|
||||||
auto hr = CoCreateInstance(__uuidof(CUIAutomation), nullptr,
|
auto hr = CoCreateInstance(__uuidof(CUIAutomation), nullptr,
|
||||||
CLSCTX_INPROC_SERVER,
|
CLSCTX_INPROC_SERVER,
|
||||||
|
|||||||
@@ -150,6 +150,8 @@ target_sources(
|
|||||||
utils/connection-manager.hpp
|
utils/connection-manager.hpp
|
||||||
utils/cursor-helpers.cpp
|
utils/cursor-helpers.cpp
|
||||||
utils/cursor-helpers.hpp
|
utils/cursor-helpers.hpp
|
||||||
|
utils/day-of-week-selector.cpp
|
||||||
|
utils/day-of-week-selector.hpp
|
||||||
utils/filter-selection.cpp
|
utils/filter-selection.cpp
|
||||||
utils/filter-selection.hpp
|
utils/filter-selection.hpp
|
||||||
utils/hotkey-helpers.cpp
|
utils/hotkey-helpers.cpp
|
||||||
@@ -166,6 +168,8 @@ target_sources(
|
|||||||
utils/scene-item-selection.hpp
|
utils/scene-item-selection.hpp
|
||||||
utils/scene-item-transform-helpers.cpp
|
utils/scene-item-transform-helpers.cpp
|
||||||
utils/scene-item-transform-helpers.hpp
|
utils/scene-item-transform-helpers.hpp
|
||||||
|
utils/transition-helpers.cpp
|
||||||
|
utils/transition-helpers.hpp
|
||||||
utils/source-properties-button.cpp
|
utils/source-properties-button.cpp
|
||||||
utils/source-properties-button.hpp
|
utils/source-properties-button.hpp
|
||||||
utils/source-settings-helpers.cpp
|
utils/source-settings-helpers.cpp
|
||||||
|
|||||||
@@ -601,10 +601,10 @@ static void populateHotkeyNames(QComboBox *list,
|
|||||||
MacroActionHotkeyEdit::MacroActionHotkeyEdit(
|
MacroActionHotkeyEdit::MacroActionHotkeyEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroActionHotkey> entryData)
|
QWidget *parent, std::shared_ptr<MacroActionHotkey> entryData)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
_actionType(new QComboBox()),
|
_actionType(new FilterComboBox()),
|
||||||
_hotkeyType(new QComboBox()),
|
_hotkeyType(new FilterComboBox()),
|
||||||
_obsHotkeys(new QComboBox()),
|
_obsHotkeys(new FilterComboBox()),
|
||||||
_keys(new QComboBox()),
|
_keys(new FilterComboBox()),
|
||||||
_leftShift(new QCheckBox(
|
_leftShift(new QCheckBox(
|
||||||
obs_module_text("AdvSceneSwitcher.action.hotkey.leftShift"))),
|
obs_module_text("AdvSceneSwitcher.action.hotkey.leftShift"))),
|
||||||
_rightShift(new QCheckBox(obs_module_text(
|
_rightShift(new QCheckBox(obs_module_text(
|
||||||
|
|||||||
@@ -85,11 +85,14 @@ private slots:
|
|||||||
void DurationChanged(const Duration &);
|
void DurationChanged(const Duration &);
|
||||||
void OnlySendToOBSChanged(int state);
|
void OnlySendToOBSChanged(int state);
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
QComboBox *_actionType;
|
void RepopulateOBSHotkeySelection();
|
||||||
QComboBox *_hotkeyType;
|
void SetWidgetVisibility();
|
||||||
QComboBox *_obsHotkeys;
|
|
||||||
QComboBox *_keys;
|
FilterComboBox *_actionType;
|
||||||
|
FilterComboBox *_hotkeyType;
|
||||||
|
FilterComboBox *_obsHotkeys;
|
||||||
|
FilterComboBox *_keys;
|
||||||
QCheckBox *_leftShift;
|
QCheckBox *_leftShift;
|
||||||
QCheckBox *_rightShift;
|
QCheckBox *_rightShift;
|
||||||
QCheckBox *_leftCtrl;
|
QCheckBox *_leftCtrl;
|
||||||
@@ -101,15 +104,10 @@ protected:
|
|||||||
DurationSelection *_duration;
|
DurationSelection *_duration;
|
||||||
QCheckBox *_onlySendToOBS;
|
QCheckBox *_onlySendToOBS;
|
||||||
QLabel *_noKeyPressSimulationWarning;
|
QLabel *_noKeyPressSimulationWarning;
|
||||||
|
|
||||||
std::shared_ptr<MacroActionHotkey> _entryData;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void RepopulateOBSHotkeySelection();
|
|
||||||
void SetWidgetVisibility();
|
|
||||||
|
|
||||||
QHBoxLayout *_entryLayout;
|
QHBoxLayout *_entryLayout;
|
||||||
QHBoxLayout *_keyConfigLayout;
|
QHBoxLayout *_keyConfigLayout;
|
||||||
|
|
||||||
|
std::shared_ptr<MacroActionHotkey> _entryData;
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "plugin-state-helpers.hpp"
|
#include "plugin-state-helpers.hpp"
|
||||||
#include "scene-switch-helpers.hpp"
|
#include "scene-switch-helpers.hpp"
|
||||||
#include "source-helpers.hpp"
|
#include "source-helpers.hpp"
|
||||||
|
#include "transition-helpers.hpp"
|
||||||
|
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
@@ -68,14 +69,6 @@ static int getTransitionOverrideDuration(OBSWeakSource &scene)
|
|||||||
return duration;
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isUsingFixedLengthTransition(const OBSWeakSource &transition)
|
|
||||||
{
|
|
||||||
obs_source_t *source = obs_weak_source_get_source(transition);
|
|
||||||
bool ret = obs_transition_fixed(source);
|
|
||||||
obs_source_release(source);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static OBSWeakSource getOverrideTransition(OBSWeakSource &scene)
|
static OBSWeakSource getOverrideTransition(OBSWeakSource &scene)
|
||||||
{
|
{
|
||||||
OBSWeakSource transition;
|
OBSWeakSource transition;
|
||||||
@@ -101,13 +94,13 @@ static int getExpectedTransitionDuration(OBSWeakSource &scene,
|
|||||||
auto overrideTransition = getOverrideTransition(scene);
|
auto overrideTransition = getOverrideTransition(scene);
|
||||||
if (overrideTransition) {
|
if (overrideTransition) {
|
||||||
transition = overrideTransition;
|
transition = overrideTransition;
|
||||||
if (!isUsingFixedLengthTransition(transition)) {
|
if (!IsFixedLengthTransition(transition)) {
|
||||||
return getTransitionOverrideDuration(scene);
|
return getTransitionOverrideDuration(scene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUsingFixedLengthTransition(transition)) {
|
if (IsFixedLengthTransition(transition)) {
|
||||||
return -1; // no API is available to access the fixed duration
|
return -1; // no API is available to access the fixed duration
|
||||||
}
|
}
|
||||||
if (duration != 0) {
|
if (duration != 0) {
|
||||||
@@ -137,31 +130,51 @@ bool MacroActionSwitchScene::WaitForTransition(OBSWeakSource &scene,
|
|||||||
bool MacroActionSwitchScene::PerformAction()
|
bool MacroActionSwitchScene::PerformAction()
|
||||||
{
|
{
|
||||||
OBSWeakSource sceneToSwitchTo;
|
OBSWeakSource sceneToSwitchTo;
|
||||||
OBSWeakCanvas canvas;
|
OBSWeakCanvas canvasToSwitchFor;
|
||||||
|
|
||||||
|
OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas();
|
||||||
|
OBSWeakCanvas mainCanvasWeak = OBSGetWeakRef(mainCanvas);
|
||||||
|
|
||||||
|
const auto getActiveSceneHelper = [this](const OBSWeakCanvas &canvas) {
|
||||||
|
OBSWeakSource activeScene;
|
||||||
|
if (IsMainCanvas(canvas) && _sceneType == SceneType::PREVIEW) {
|
||||||
|
OBSSourceAutoRelease previewSource =
|
||||||
|
obs_frontend_get_current_preview_scene();
|
||||||
|
return OBSGetWeakRef(previewSource);
|
||||||
|
} else {
|
||||||
|
return GetActiveCanvasScene(canvas);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
switch (_action) {
|
switch (_action) {
|
||||||
case Action::SCENE_NAME:
|
case Action::SCENE_NAME:
|
||||||
sceneToSwitchTo = _scene.GetScene();
|
sceneToSwitchTo = _scene.GetScene();
|
||||||
canvas = _scene.GetCanvas();
|
canvasToSwitchFor = _scene.GetCanvas();
|
||||||
break;
|
break;
|
||||||
case Action::SCENE_LIST_NEXT: {
|
case Action::SCENE_LIST_NEXT: {
|
||||||
const auto activeScene = GetActiveCanvasScene(_canvas);
|
canvasToSwitchFor = _canvas ? _canvas : mainCanvasWeak;
|
||||||
const int currentIndex = GetIndexOfScene(_canvas, activeScene);
|
const auto activeScene =
|
||||||
sceneToSwitchTo = GetSceneAtIndex(_canvas, currentIndex + 1);
|
getActiveSceneHelper(canvasToSwitchFor);
|
||||||
canvas = _canvas;
|
const int currentIndex =
|
||||||
|
GetIndexOfScene(canvasToSwitchFor, activeScene);
|
||||||
|
sceneToSwitchTo =
|
||||||
|
GetSceneAtIndex(canvasToSwitchFor, currentIndex + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Action::SCENE_LIST_PREVIOUS: {
|
case Action::SCENE_LIST_PREVIOUS: {
|
||||||
const auto activeScene = GetActiveCanvasScene(_canvas);
|
canvasToSwitchFor = _canvas ? _canvas : mainCanvasWeak;
|
||||||
const int currentIndex = GetIndexOfScene(_canvas, activeScene);
|
const auto activeScene =
|
||||||
sceneToSwitchTo = GetSceneAtIndex(_canvas, currentIndex - 1);
|
getActiveSceneHelper(canvasToSwitchFor);
|
||||||
canvas = _canvas;
|
const int currentIndex =
|
||||||
|
GetIndexOfScene(canvasToSwitchFor, activeScene);
|
||||||
|
sceneToSwitchTo =
|
||||||
|
GetSceneAtIndex(canvasToSwitchFor, currentIndex - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Action::SCENE_LIST_INDEX: {
|
case Action::SCENE_LIST_INDEX: {
|
||||||
sceneToSwitchTo =
|
canvasToSwitchFor = _canvas ? _canvas : mainCanvasWeak;
|
||||||
GetSceneAtIndex(_canvas, _index.GetValue() - 1);
|
sceneToSwitchTo = GetSceneAtIndex(canvasToSwitchFor,
|
||||||
canvas = _canvas;
|
_index.GetValue() - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -176,11 +189,12 @@ bool MacroActionSwitchScene::PerformAction()
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto transition = _transition.GetTransition();
|
auto transition = _transition.GetTransition();
|
||||||
SwitchScene({sceneToSwitchTo, transition,
|
SwitchScene(
|
||||||
(int)(_duration.Milliseconds())},
|
{sceneToSwitchTo, transition, (int)(_duration.Milliseconds())},
|
||||||
obs_frontend_preview_program_mode_active(), canvas);
|
obs_frontend_preview_program_mode_active(), canvasToSwitchFor);
|
||||||
if (_blockUntilTransitionDone && sceneToSwitchTo &&
|
if (_blockUntilTransitionDone && sceneToSwitchTo &&
|
||||||
sceneToSwitchTo != GetCurrentScene() && IsMainCanvas(canvas)) {
|
sceneToSwitchTo != GetCurrentScene() &&
|
||||||
|
IsMainCanvas(canvasToSwitchFor)) {
|
||||||
return WaitForTransition(sceneToSwitchTo, transition);
|
return WaitForTransition(sceneToSwitchTo, transition);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -392,6 +406,7 @@ void MacroActionSwitchSceneEdit::SetWidgetData() const
|
|||||||
_sceneTypes->setCurrentIndex(_sceneTypes->findData(
|
_sceneTypes->setCurrentIndex(_sceneTypes->findData(
|
||||||
static_cast<int>(_entryData->_sceneType)));
|
static_cast<int>(_entryData->_sceneType)));
|
||||||
_scenes->SetScene(_entryData->_scene);
|
_scenes->SetScene(_entryData->_scene);
|
||||||
|
_canvas->SetCanvas(_entryData->_canvas);
|
||||||
_transitions->SetTransition(_entryData->_transition);
|
_transitions->SetTransition(_entryData->_transition);
|
||||||
_duration->SetDuration(_entryData->_duration);
|
_duration->SetDuration(_entryData->_duration);
|
||||||
_blockUntilTransitionDone->setChecked(
|
_blockUntilTransitionDone->setChecked(
|
||||||
@@ -431,7 +446,7 @@ void MacroActionSwitchSceneEdit::SceneSelectionCanvasChanged(
|
|||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionSwitchSceneEdit::ActionChanged(int value)
|
void MacroActionSwitchSceneEdit::ActionChanged(int)
|
||||||
{
|
{
|
||||||
GUARD_LOADING_AND_LOCK();
|
GUARD_LOADING_AND_LOCK();
|
||||||
_entryData->_action = static_cast<MacroActionSwitchScene::Action>(
|
_entryData->_action = static_cast<MacroActionSwitchScene::Action>(
|
||||||
@@ -481,7 +496,7 @@ shouldShowDurationInTransitionLayout(MacroActionSwitchScene::SceneType type,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUsingFixedLengthTransition(transition.GetTransition())) {
|
if (IsFixedLengthTransition(transition.GetTransition())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,9 +576,17 @@ void MacroActionSwitchSceneEdit::SetWidgetVisibility()
|
|||||||
{{"{{transitions}}", _transitions},
|
{{"{{transitions}}", _transitions},
|
||||||
{"{{duration}}", _duration}});
|
{"{{duration}}", _duration}});
|
||||||
|
|
||||||
const auto canvas = action == MacroActionSwitchScene::Action::SCENE_NAME
|
OBSWeakCanvas canvas;
|
||||||
? _entryData->_scene.GetCanvas()
|
if (action == MacroActionSwitchScene::Action::SCENE_NAME) {
|
||||||
: _entryData->_canvas;
|
canvas = _entryData->_scene.GetCanvas();
|
||||||
|
} else {
|
||||||
|
if (_entryData->_canvas) {
|
||||||
|
canvas = _entryData->_canvas;
|
||||||
|
} else {
|
||||||
|
OBSCanvasAutoRelease mainCanvas = obs_get_main_canvas();
|
||||||
|
canvas = OBSGetWeakRef(mainCanvas);
|
||||||
|
}
|
||||||
|
}
|
||||||
const bool isMainCanvas = IsMainCanvas(canvas);
|
const bool isMainCanvas = IsMainCanvas(canvas);
|
||||||
SetLayoutVisible(_transitionLayout, isMainCanvas);
|
SetLayoutVisible(_transitionLayout, isMainCanvas);
|
||||||
_blockUntilTransitionDone->setVisible(isMainCanvas);
|
_blockUntilTransitionDone->setVisible(isMainCanvas);
|
||||||
@@ -580,7 +603,7 @@ void MacroActionSwitchSceneEdit::SetWidgetVisibility()
|
|||||||
_notSupportedWarning->setText(
|
_notSupportedWarning->setText(
|
||||||
fmt.arg(QString::fromStdString(GetWeakCanvasName(canvas))));
|
fmt.arg(QString::fromStdString(GetWeakCanvasName(canvas))));
|
||||||
_notSupportedWarning->setVisible(
|
_notSupportedWarning->setVisible(
|
||||||
!IsMainCanvas(canvas) &&
|
!isMainCanvas &&
|
||||||
_entryData->_sceneType ==
|
_entryData->_sceneType ==
|
||||||
MacroActionSwitchScene::SceneType::PREVIEW);
|
MacroActionSwitchScene::SceneType::PREVIEW);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
#include "macro-action-scene-visibility.hpp"
|
#include "macro-action-scene-visibility.hpp"
|
||||||
#include "layout-helpers.hpp"
|
#include "layout-helpers.hpp"
|
||||||
|
#include "plugin-state-helpers.hpp"
|
||||||
|
#include "transition-helpers.hpp"
|
||||||
|
|
||||||
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -21,9 +25,168 @@ const static std::map<MacroActionSceneVisibility::Action, std::string>
|
|||||||
"AdvSceneSwitcher.action.sceneVisibility.type.toggle"},
|
"AdvSceneSwitcher.action.sceneVisibility.type.toggle"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct TransitionRestoreContext;
|
||||||
|
static std::unordered_map<obs_sceneitem_t *, TransitionRestoreContext *>
|
||||||
|
restoreContexts;
|
||||||
|
static std::mutex restoreMutex;
|
||||||
|
|
||||||
|
struct TransitionRestoreContext {
|
||||||
|
public:
|
||||||
|
obs_sceneitem_t *item;
|
||||||
|
bool wasVisible;
|
||||||
|
|
||||||
|
OBSSource originalTransition = nullptr;
|
||||||
|
uint32_t originalDuration;
|
||||||
|
|
||||||
|
obs_source_t *transition = nullptr;
|
||||||
|
signal_handler_t *sh = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
static void handleShutdown(enum obs_frontend_event event, void *private_data)
|
||||||
|
{
|
||||||
|
if (event != OBS_FRONTEND_EVENT_EXIT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(restoreMutex);
|
||||||
|
for (const auto &[_, ctx] : restoreContexts) {
|
||||||
|
obs_source_release(ctx->transition);
|
||||||
|
}
|
||||||
|
restoreContexts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setup()
|
||||||
|
{
|
||||||
|
obs_frontend_add_event_callback(handleShutdown, nullptr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool setupDone = setup();
|
||||||
|
|
||||||
|
static void handleSourceDestroyed(void *param, calldata_t *)
|
||||||
|
{
|
||||||
|
if (OBSIsShuttingDown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ctx = static_cast<TransitionRestoreContext *>(param);
|
||||||
|
ctx->sh = nullptr;
|
||||||
|
ctx->originalTransition = nullptr;
|
||||||
|
delete ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resetSceneItemTransition(void *param, calldata_t *)
|
||||||
|
{
|
||||||
|
if (OBSIsShuttingDown()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ctx = static_cast<TransitionRestoreContext *>(param);
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetSceneItemTransition(ctx->item, ctx->originalTransition,
|
||||||
|
!ctx->wasVisible);
|
||||||
|
|
||||||
|
obs_sceneitem_set_transition_duration(ctx->item, !ctx->wasVisible,
|
||||||
|
ctx->originalDuration);
|
||||||
|
|
||||||
|
signal_handler_disconnect(ctx->sh, "transition_stop",
|
||||||
|
resetSceneItemTransition, ctx);
|
||||||
|
signal_handler_disconnect(ctx->sh, "destroy", handleSourceDestroyed,
|
||||||
|
ctx);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(restoreMutex);
|
||||||
|
restoreContexts.erase(ctx->item);
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_release(ctx->transition);
|
||||||
|
delete ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void attachRestoreContext(obs_sceneitem_t *item,
|
||||||
|
obs_source_t *transition, bool itemWasVisible,
|
||||||
|
OBSSource originalTransition,
|
||||||
|
uint32_t originalDuration)
|
||||||
|
{
|
||||||
|
signal_handler_t *sh = obs_source_get_signal_handler(transition);
|
||||||
|
if (!sh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(restoreMutex);
|
||||||
|
|
||||||
|
auto ctx = new TransitionRestoreContext{
|
||||||
|
item,
|
||||||
|
itemWasVisible,
|
||||||
|
originalTransition,
|
||||||
|
originalDuration,
|
||||||
|
obs_source_get_ref(transition),
|
||||||
|
sh,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto it = restoreContexts.find(item);
|
||||||
|
if (it != restoreContexts.end()) {
|
||||||
|
auto *oldCtx = it->second;
|
||||||
|
|
||||||
|
signal_handler_disconnect(oldCtx->sh, "transition_stop",
|
||||||
|
resetSceneItemTransition, oldCtx);
|
||||||
|
|
||||||
|
signal_handler_disconnect(oldCtx->sh, "destroy",
|
||||||
|
handleSourceDestroyed, oldCtx);
|
||||||
|
|
||||||
|
ctx->originalTransition = oldCtx->originalTransition;
|
||||||
|
ctx->originalDuration = oldCtx->originalDuration;
|
||||||
|
|
||||||
|
obs_source_release(oldCtx->transition);
|
||||||
|
delete oldCtx;
|
||||||
|
|
||||||
|
restoreContexts.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
restoreContexts[item] = ctx;
|
||||||
|
|
||||||
|
signal_handler_connect(sh, "transition_stop", resetSceneItemTransition,
|
||||||
|
ctx);
|
||||||
|
signal_handler_connect(sh, "destroy", handleSourceDestroyed, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
static void setSceneItemVisibility(obs_sceneitem_t *item,
|
static void setSceneItemVisibility(obs_sceneitem_t *item,
|
||||||
|
const bool setTransition,
|
||||||
|
const OBSWeakSource &transitionWeak,
|
||||||
|
const bool setDuration,
|
||||||
|
const Duration &duration,
|
||||||
MacroActionSceneVisibility::Action action)
|
MacroActionSceneVisibility::Action action)
|
||||||
{
|
{
|
||||||
|
const OBSSourceAutoRelease transition = OBSGetStrongRef(transitionWeak);
|
||||||
|
const bool itemIsVisible = obs_sceneitem_visible(item);
|
||||||
|
|
||||||
|
const OBSSource currentTransition =
|
||||||
|
obs_sceneitem_get_transition(item, !itemIsVisible);
|
||||||
|
const uint32_t currentTransitionDuration =
|
||||||
|
obs_sceneitem_get_transition_duration(item, !itemIsVisible);
|
||||||
|
|
||||||
|
OBSSource privateTransitionSource = nullptr;
|
||||||
|
if (setTransition) {
|
||||||
|
privateTransitionSource = SetSceneItemTransition(
|
||||||
|
item, transition, !itemIsVisible);
|
||||||
|
} else {
|
||||||
|
privateTransitionSource =
|
||||||
|
obs_sceneitem_get_transition(item, !itemIsVisible);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setDuration) {
|
||||||
|
obs_sceneitem_set_transition_duration(item, !itemIsVisible,
|
||||||
|
duration.Milliseconds());
|
||||||
|
}
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case MacroActionSceneVisibility::Action::SHOW:
|
case MacroActionSceneVisibility::Action::SHOW:
|
||||||
obs_sceneitem_set_visible(item, true);
|
obs_sceneitem_set_visible(item, true);
|
||||||
@@ -32,16 +195,43 @@ static void setSceneItemVisibility(obs_sceneitem_t *item,
|
|||||||
obs_sceneitem_set_visible(item, false);
|
obs_sceneitem_set_visible(item, false);
|
||||||
break;
|
break;
|
||||||
case MacroActionSceneVisibility::Action::TOGGLE:
|
case MacroActionSceneVisibility::Action::TOGGLE:
|
||||||
obs_sceneitem_set_visible(item, !obs_sceneitem_visible(item));
|
obs_sceneitem_set_visible(item, !itemIsVisible);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!setTransition && !setDuration) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!privateTransitionSource) {
|
||||||
|
if (setTransition) {
|
||||||
|
SetSceneItemTransition(item, currentTransition,
|
||||||
|
!itemIsVisible);
|
||||||
|
}
|
||||||
|
if (setDuration) {
|
||||||
|
obs_sceneitem_set_transition_duration(
|
||||||
|
item, !itemIsVisible,
|
||||||
|
currentTransitionDuration);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sh = obs_source_get_signal_handler(privateTransitionSource);
|
||||||
|
if (!sh) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
attachRestoreContext(item, privateTransitionSource, itemIsVisible,
|
||||||
|
currentTransition, currentTransitionDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroActionSceneVisibility::PerformAction()
|
bool MacroActionSceneVisibility::PerformAction()
|
||||||
{
|
{
|
||||||
auto items = _source.GetSceneItems(_scene);
|
auto items = _source.GetSceneItems(_scene);
|
||||||
for (const auto &item : items) {
|
for (const auto &item : items) {
|
||||||
setSceneItemVisibility(item, _action);
|
setSceneItemVisibility(item, _updateTransition,
|
||||||
|
_transition.GetTransition(),
|
||||||
|
_updateDuration, _duration, _action);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -66,6 +256,10 @@ bool MacroActionSceneVisibility::Save(obs_data_t *obj) const
|
|||||||
MacroAction::Save(obj);
|
MacroAction::Save(obj);
|
||||||
_scene.Save(obj);
|
_scene.Save(obj);
|
||||||
_source.Save(obj);
|
_source.Save(obj);
|
||||||
|
obs_data_set_bool(obj, "updateTransition", _updateTransition);
|
||||||
|
_transition.Save(obj);
|
||||||
|
obs_data_set_bool(obj, "updateDuration", _updateDuration);
|
||||||
|
_duration.Save(obj);
|
||||||
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -82,6 +276,10 @@ bool MacroActionSceneVisibility::Load(obs_data_t *obj)
|
|||||||
MacroAction::Load(obj);
|
MacroAction::Load(obj);
|
||||||
_scene.Load(obj);
|
_scene.Load(obj);
|
||||||
_source.Load(obj);
|
_source.Load(obj);
|
||||||
|
_updateTransition = obs_data_get_bool(obj, "updateTransition");
|
||||||
|
_transition.Load(obj);
|
||||||
|
_updateDuration = obs_data_get_bool(obj, "updateDuration");
|
||||||
|
_duration.Load(obj);
|
||||||
_action = static_cast<MacroActionSceneVisibility::Action>(
|
_action = static_cast<MacroActionSceneVisibility::Action>(
|
||||||
obs_data_get_int(obj, "action"));
|
obs_data_get_int(obj, "action"));
|
||||||
|
|
||||||
@@ -141,10 +339,17 @@ MacroActionSceneVisibilityEdit::MacroActionSceneVisibilityEdit(
|
|||||||
SceneItemSelection::Type::ALL,
|
SceneItemSelection::Type::ALL,
|
||||||
},
|
},
|
||||||
SceneItemSelectionWidget::NameClashMode::ALL)),
|
SceneItemSelectionWidget::NameClashMode::ALL)),
|
||||||
|
_updateTransition(new QCheckBox(this)),
|
||||||
|
_transitions(new TransitionSelectionWidget(this, false, false)),
|
||||||
|
_updateDuration(new QCheckBox(this)),
|
||||||
|
_duration(new DurationSelection(this, false)),
|
||||||
|
_durationLayout(new QHBoxLayout),
|
||||||
_actions(new QComboBox())
|
_actions(new QComboBox())
|
||||||
{
|
{
|
||||||
populateActionSelection(_actions);
|
populateActionSelection(_actions);
|
||||||
|
|
||||||
|
_duration->SpinBox()->setSpecialValueText("-");
|
||||||
|
|
||||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(ActionChanged(int)));
|
SLOT(ActionChanged(int)));
|
||||||
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
|
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
|
||||||
@@ -154,18 +359,49 @@ MacroActionSceneVisibilityEdit::MacroActionSceneVisibilityEdit(
|
|||||||
QWidget::connect(_sources,
|
QWidget::connect(_sources,
|
||||||
SIGNAL(SceneItemChanged(const SceneItemSelection &)),
|
SIGNAL(SceneItemChanged(const SceneItemSelection &)),
|
||||||
this, SLOT(SourceChanged(const SceneItemSelection &)));
|
this, SLOT(SourceChanged(const SceneItemSelection &)));
|
||||||
|
QWidget::connect(_updateTransition, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(UpdateTransitionChanged(int)));
|
||||||
|
QWidget::connect(_transitions,
|
||||||
|
SIGNAL(TransitionChanged(const TransitionSelection &)),
|
||||||
|
this,
|
||||||
|
SLOT(TransitionChanged(const TransitionSelection &)));
|
||||||
|
QWidget::connect(_updateDuration, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(UpdateDurationChanged(int)));
|
||||||
|
QWidget::connect(_duration, SIGNAL(DurationChanged(const Duration &)),
|
||||||
|
this, SLOT(DurationChanged(const Duration &)));
|
||||||
|
|
||||||
auto layout = new QHBoxLayout;
|
auto sceneItemLayout = new QHBoxLayout;
|
||||||
PlaceWidgets(obs_module_text(
|
PlaceWidgets(obs_module_text(
|
||||||
"AdvSceneSwitcher.action.sceneVisibility.entry"),
|
"AdvSceneSwitcher.action.sceneVisibility.layout"),
|
||||||
layout,
|
sceneItemLayout,
|
||||||
{{"{{scenes}}", _scenes},
|
{{"{{scenes}}", _scenes},
|
||||||
{"{{sources}}", _sources},
|
{"{{sources}}", _sources},
|
||||||
{"{{actions}}", _actions}});
|
{"{{actions}}", _actions}});
|
||||||
|
|
||||||
|
auto transitionLayout = new QHBoxLayout;
|
||||||
|
PlaceWidgets(
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.sceneVisibility.layout.transition"),
|
||||||
|
transitionLayout,
|
||||||
|
{{"{{updateTransition}}", _updateTransition},
|
||||||
|
{"{{transitions}}", _transitions}});
|
||||||
|
|
||||||
|
PlaceWidgets(
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.sceneVisibility.layout.duration"),
|
||||||
|
_durationLayout,
|
||||||
|
{{"{{updateDuration}}", _updateDuration},
|
||||||
|
{"{{duration}}", _duration}});
|
||||||
|
|
||||||
|
auto layout = new QVBoxLayout;
|
||||||
|
layout->addLayout(sceneItemLayout);
|
||||||
|
layout->addLayout(transitionLayout);
|
||||||
|
layout->addLayout(_durationLayout);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
UpdateEntryData();
|
UpdateEntryData();
|
||||||
|
SetWidgetVisibility();
|
||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,7 +413,11 @@ void MacroActionSceneVisibilityEdit::UpdateEntryData()
|
|||||||
|
|
||||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||||
_scenes->SetScene(_entryData->_scene);
|
_scenes->SetScene(_entryData->_scene);
|
||||||
_sources->SetSceneItem((_entryData->_source));
|
_sources->SetSceneItem(_entryData->_source);
|
||||||
|
_updateTransition->setChecked(_entryData->_updateTransition);
|
||||||
|
_transitions->SetTransition(_entryData->_transition);
|
||||||
|
_updateDuration->setChecked(_entryData->_updateDuration);
|
||||||
|
_duration->SetDuration(_entryData->_duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionSceneVisibilityEdit::SceneChanged(const SceneSelection &s)
|
void MacroActionSceneVisibilityEdit::SceneChanged(const SceneSelection &s)
|
||||||
@@ -197,6 +437,34 @@ void MacroActionSceneVisibilityEdit::SourceChanged(
|
|||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionSceneVisibilityEdit::UpdateTransitionChanged(int state)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_updateTransition = state;
|
||||||
|
SetWidgetVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSceneVisibilityEdit::TransitionChanged(
|
||||||
|
const TransitionSelection &t)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_transition = t;
|
||||||
|
SetWidgetVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSceneVisibilityEdit::UpdateDurationChanged(int state)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_updateDuration = state;
|
||||||
|
SetWidgetVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSceneVisibilityEdit::DurationChanged(const Duration &dur)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_duration = dur;
|
||||||
|
}
|
||||||
|
|
||||||
void MacroActionSceneVisibilityEdit::ActionChanged(int value)
|
void MacroActionSceneVisibilityEdit::ActionChanged(int value)
|
||||||
{
|
{
|
||||||
GUARD_LOADING_AND_LOCK();
|
GUARD_LOADING_AND_LOCK();
|
||||||
@@ -204,4 +472,20 @@ void MacroActionSceneVisibilityEdit::ActionChanged(int value)
|
|||||||
static_cast<MacroActionSceneVisibility::Action>(value);
|
static_cast<MacroActionSceneVisibility::Action>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionSceneVisibilityEdit::SetWidgetVisibility()
|
||||||
|
{
|
||||||
|
const bool hideDurationSelection =
|
||||||
|
_entryData->_updateTransition &&
|
||||||
|
IsFixedLengthTransition(
|
||||||
|
_entryData->_transition.GetTransition());
|
||||||
|
|
||||||
|
SetLayoutVisible(_durationLayout, !hideDurationSelection);
|
||||||
|
|
||||||
|
_transitions->setEnabled(_entryData->_updateTransition);
|
||||||
|
_duration->setEnabled(_entryData->_updateDuration);
|
||||||
|
|
||||||
|
adjustSize();
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace advss
|
} // namespace advss
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "duration-control.hpp"
|
||||||
#include "macro-action-edit.hpp"
|
#include "macro-action-edit.hpp"
|
||||||
#include "scene-selection.hpp"
|
#include "scene-selection.hpp"
|
||||||
#include "scene-item-selection.hpp"
|
#include "scene-item-selection.hpp"
|
||||||
|
#include "transition-selection.hpp"
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -20,6 +22,10 @@ public:
|
|||||||
|
|
||||||
SceneSelection _scene;
|
SceneSelection _scene;
|
||||||
SceneItemSelection _source;
|
SceneItemSelection _source;
|
||||||
|
bool _updateTransition = false;
|
||||||
|
TransitionSelection _transition;
|
||||||
|
bool _updateDuration = false;
|
||||||
|
Duration _duration;
|
||||||
|
|
||||||
enum class Action {
|
enum class Action {
|
||||||
SHOW,
|
SHOW,
|
||||||
@@ -53,17 +59,27 @@ public:
|
|||||||
private slots:
|
private slots:
|
||||||
void SceneChanged(const SceneSelection &);
|
void SceneChanged(const SceneSelection &);
|
||||||
void SourceChanged(const SceneItemSelection &);
|
void SourceChanged(const SceneItemSelection &);
|
||||||
|
void UpdateTransitionChanged(int);
|
||||||
|
void TransitionChanged(const TransitionSelection &);
|
||||||
|
void UpdateDurationChanged(int);
|
||||||
|
void DurationChanged(const Duration &seconds);
|
||||||
void ActionChanged(int value);
|
void ActionChanged(int value);
|
||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
|
void SetWidgetVisibility();
|
||||||
|
|
||||||
SceneSelectionWidget *_scenes;
|
SceneSelectionWidget *_scenes;
|
||||||
SceneItemSelectionWidget *_sources;
|
SceneItemSelectionWidget *_sources;
|
||||||
|
QCheckBox *_updateTransition;
|
||||||
|
TransitionSelectionWidget *_transitions;
|
||||||
|
QCheckBox *_updateDuration;
|
||||||
|
DurationSelection *_duration;
|
||||||
|
QHBoxLayout *_durationLayout;
|
||||||
QComboBox *_actions;
|
QComboBox *_actions;
|
||||||
std::shared_ptr<MacroActionSceneVisibility> _entryData;
|
|
||||||
|
|
||||||
private:
|
std::shared_ptr<MacroActionSceneVisibility> _entryData;
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ MacroActionSequenceEdit::MacroActionSequenceEdit(
|
|||||||
_resetIndex(new VariableSpinBox()),
|
_resetIndex(new VariableSpinBox()),
|
||||||
_layout(new QHBoxLayout())
|
_layout(new QHBoxLayout())
|
||||||
{
|
{
|
||||||
|
_macros->HideGroups();
|
||||||
populateActionSelection(_actions);
|
populateActionSelection(_actions);
|
||||||
|
|
||||||
_resetIndex->setMinimum(1);
|
_resetIndex->setMinimum(1);
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
const std::string MacroActionSource::id = "source";
|
const std::string MacroActionSource::id = "source";
|
||||||
@@ -37,6 +39,12 @@ const static std::map<MacroActionSource::Action, std::string> actionTypes = {
|
|||||||
"AdvSceneSwitcher.action.source.type.openFilterDialog"},
|
"AdvSceneSwitcher.action.source.type.openFilterDialog"},
|
||||||
{MacroActionSource::Action::OPEN_PROPERTIES_DIALOG,
|
{MacroActionSource::Action::OPEN_PROPERTIES_DIALOG,
|
||||||
"AdvSceneSwitcher.action.source.type.openPropertiesDialog"},
|
"AdvSceneSwitcher.action.source.type.openPropertiesDialog"},
|
||||||
|
{MacroActionSource::Action::CLOSE_INTERACTION_DIALOG,
|
||||||
|
"AdvSceneSwitcher.action.source.type.closeInteractionDialog"},
|
||||||
|
{MacroActionSource::Action::CLOSE_FILTER_DIALOG,
|
||||||
|
"AdvSceneSwitcher.action.source.type.closeFilterDialog"},
|
||||||
|
{MacroActionSource::Action::CLOSE_PROPERTIES_DIALOG,
|
||||||
|
"AdvSceneSwitcher.action.source.type.closePropertiesDialog"},
|
||||||
};
|
};
|
||||||
|
|
||||||
const static std::map<obs_deinterlace_mode, std::string> deinterlaceModes = {
|
const static std::map<obs_deinterlace_mode, std::string> deinterlaceModes = {
|
||||||
@@ -108,9 +116,81 @@ static bool isInteractable(obs_source_t *source)
|
|||||||
return (flags & OBS_SOURCE_INTERACTION) != 0;
|
return (flags & OBS_SOURCE_INTERACTION) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void closeSourceDialog(obs_source_t *source, bool accept,
|
||||||
|
const char *className)
|
||||||
|
{
|
||||||
|
if (!source) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto mainWindow =
|
||||||
|
reinterpret_cast<QMainWindow *>(obs_frontend_get_main_window());
|
||||||
|
if (!mainWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto widget : mainWindow->children()) {
|
||||||
|
auto dialog = qobject_cast<QDialog *>(widget);
|
||||||
|
if (!dialog) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dialog->metaObject()->className() != QString(className)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *name = obs_source_get_name(source);
|
||||||
|
if (!name) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dialog->windowTitle().contains(QString(name))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (accept) {
|
||||||
|
dialog->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialog->reject() will ask for confirmation
|
||||||
|
// Try to avoid this by finding and pressing the cancel button
|
||||||
|
for (const auto widget : dialog->children()) {
|
||||||
|
auto buttons = qobject_cast<QDialogButtonBox *>(widget);
|
||||||
|
if (!buttons) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto *button : buttons->buttons()) {
|
||||||
|
if (buttons->buttonRole(button) ==
|
||||||
|
QDialogButtonBox::RejectRole) {
|
||||||
|
button->click();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F> void QueueUITaskLambda(F &&func)
|
||||||
|
{
|
||||||
|
using FnType = std::decay_t<F>;
|
||||||
|
auto *heapFunc = new FnType(std::forward<F>(func));
|
||||||
|
|
||||||
|
QueueUITask(
|
||||||
|
[](void *param) {
|
||||||
|
std::unique_ptr<FnType> fn(
|
||||||
|
static_cast<FnType *>(param));
|
||||||
|
(*fn)();
|
||||||
|
},
|
||||||
|
heapFunc);
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroActionSource::PerformAction()
|
bool MacroActionSource::PerformAction()
|
||||||
{
|
{
|
||||||
auto s = obs_weak_source_get_source(_source.GetSource());
|
OBSSource s = obs_weak_source_get_source(_source.GetSource());
|
||||||
|
obs_source_release(s);
|
||||||
|
|
||||||
switch (_action) {
|
switch (_action) {
|
||||||
case Action::ENABLE:
|
case Action::ENABLE:
|
||||||
obs_source_set_enabled(s, true);
|
obs_source_set_enabled(s, true);
|
||||||
@@ -172,10 +252,31 @@ bool MacroActionSource::PerformAction()
|
|||||||
case Action::OPEN_PROPERTIES_DIALOG:
|
case Action::OPEN_PROPERTIES_DIALOG:
|
||||||
obs_frontend_open_source_properties(s);
|
obs_frontend_open_source_properties(s);
|
||||||
break;
|
break;
|
||||||
|
case Action::CLOSE_INTERACTION_DIALOG:
|
||||||
|
if (!isInteractable(s)) {
|
||||||
|
// Nothing to do
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueueUITaskLambda([&]() {
|
||||||
|
closeSourceDialog(s, true, "OBSBasicInteraction");
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case Action::CLOSE_FILTER_DIALOG:
|
||||||
|
QueueUITaskLambda([&]() {
|
||||||
|
closeSourceDialog(s, _acceptDialog, "OBSBasicFilters");
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case Action::CLOSE_PROPERTIES_DIALOG:
|
||||||
|
QueueUITaskLambda([&]() {
|
||||||
|
closeSourceDialog(s, _acceptDialog,
|
||||||
|
"OBSBasicProperties");
|
||||||
|
});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
obs_source_release(s);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,6 +308,7 @@ bool MacroActionSource::Save(obs_data_t *obj) const
|
|||||||
static_cast<int>(_deinterlaceMode));
|
static_cast<int>(_deinterlaceMode));
|
||||||
obs_data_set_int(obj, "deinterlaceOrder",
|
obs_data_set_int(obj, "deinterlaceOrder",
|
||||||
static_cast<int>(_deinterlaceOrder));
|
static_cast<int>(_deinterlaceOrder));
|
||||||
|
obs_data_set_bool(obj, "acceptDialog", _acceptDialog);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,6 +333,7 @@ bool MacroActionSource::Load(obs_data_t *obj)
|
|||||||
obs_data_get_int(obj, "deinterlaceMode"));
|
obs_data_get_int(obj, "deinterlaceMode"));
|
||||||
_deinterlaceOrder = static_cast<obs_deinterlace_field_order>(
|
_deinterlaceOrder = static_cast<obs_deinterlace_field_order>(
|
||||||
obs_data_get_int(obj, "deinterlaceOrder"));
|
obs_data_get_int(obj, "deinterlaceOrder"));
|
||||||
|
_acceptDialog = obs_data_get_bool(obj, "acceptDialog");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -307,7 +410,9 @@ MacroActionSourceEdit::MacroActionSourceEdit(
|
|||||||
_warning(new QLabel(
|
_warning(new QLabel(
|
||||||
obs_module_text("AdvSceneSwitcher.action.source.warning"))),
|
obs_module_text("AdvSceneSwitcher.action.source.warning"))),
|
||||||
_refreshSettingSelection(new QPushButton(
|
_refreshSettingSelection(new QPushButton(
|
||||||
obs_module_text("AdvSceneSwitcher.action.source.refresh")))
|
obs_module_text("AdvSceneSwitcher.action.source.refresh"))),
|
||||||
|
_acceptDialog(new QCheckBox(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.source.dialog.accept")))
|
||||||
{
|
{
|
||||||
populateActionSelection(_actions);
|
populateActionSelection(_actions);
|
||||||
|
|
||||||
@@ -347,6 +452,8 @@ MacroActionSourceEdit::MacroActionSourceEdit(
|
|||||||
SLOT(SelectionChanged(const SourceSetting &)));
|
SLOT(SelectionChanged(const SourceSetting &)));
|
||||||
QWidget::connect(_refreshSettingSelection, SIGNAL(clicked()), this,
|
QWidget::connect(_refreshSettingSelection, SIGNAL(clicked()), this,
|
||||||
SLOT(RefreshVariableSourceSelectionValue()));
|
SLOT(RefreshVariableSourceSelectionValue()));
|
||||||
|
QWidget::connect(_acceptDialog, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(AcceptDialogChanged(int)));
|
||||||
|
|
||||||
auto entryLayout = new QHBoxLayout;
|
auto entryLayout = new QHBoxLayout;
|
||||||
entryLayout->setContentsMargins(0, 0, 0, 0);
|
entryLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
@@ -374,6 +481,7 @@ MacroActionSourceEdit::MacroActionSourceEdit(
|
|||||||
mainLayout->addLayout(_settingsLayout);
|
mainLayout->addLayout(_settingsLayout);
|
||||||
mainLayout->addWidget(_warning);
|
mainLayout->addWidget(_warning);
|
||||||
mainLayout->addWidget(_settingsString);
|
mainLayout->addWidget(_settingsString);
|
||||||
|
mainLayout->addWidget(_acceptDialog);
|
||||||
auto buttonLayout = new QHBoxLayout;
|
auto buttonLayout = new QHBoxLayout;
|
||||||
buttonLayout->setContentsMargins(0, 0, 0, 0);
|
buttonLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
buttonLayout->addWidget(_getSettings);
|
buttonLayout->addWidget(_getSettings);
|
||||||
@@ -406,6 +514,7 @@ void MacroActionSourceEdit::UpdateEntryData()
|
|||||||
static_cast<int>(_entryData->_settingsInputMethod)));
|
static_cast<int>(_entryData->_settingsInputMethod)));
|
||||||
_tempVars->SetVariable(_entryData->_tempVar);
|
_tempVars->SetVariable(_entryData->_tempVar);
|
||||||
_manualSettingValue->setPlainText(_entryData->_manualSettingValue);
|
_manualSettingValue->setPlainText(_entryData->_manualSettingValue);
|
||||||
|
_acceptDialog->setChecked(_entryData->_acceptDialog);
|
||||||
|
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
@@ -531,6 +640,12 @@ void MacroActionSourceEdit::RefreshVariableSourceSelectionValue()
|
|||||||
_sourceSettings->SetSource(_entryData->_source.GetSource());
|
_sourceSettings->SetSource(_entryData->_source.GetSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionSourceEdit::AcceptDialogChanged(int state)
|
||||||
|
{
|
||||||
|
GUARD_LOADING_AND_LOCK();
|
||||||
|
_entryData->_acceptDialog = state;
|
||||||
|
}
|
||||||
|
|
||||||
static QString GetIndividualListEntryName()
|
static QString GetIndividualListEntryName()
|
||||||
{
|
{
|
||||||
static const auto matchesInput =
|
static const auto matchesInput =
|
||||||
@@ -613,6 +728,12 @@ void MacroActionSourceEdit::SetWidgetVisibility()
|
|||||||
_entryData->_source.GetType() ==
|
_entryData->_source.GetType() ==
|
||||||
SourceSelection::Type::VARIABLE);
|
SourceSelection::Type::VARIABLE);
|
||||||
|
|
||||||
|
_acceptDialog->setVisible(
|
||||||
|
_entryData->_action ==
|
||||||
|
MacroActionSource::Action::CLOSE_FILTER_DIALOG ||
|
||||||
|
_entryData->_action ==
|
||||||
|
MacroActionSource::Action::CLOSE_PROPERTIES_DIALOG);
|
||||||
|
|
||||||
adjustSize();
|
adjustSize();
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,10 @@
|
|||||||
#include "source-selection.hpp"
|
#include "source-selection.hpp"
|
||||||
#include "source-setting.hpp"
|
#include "source-setting.hpp"
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QComboBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QComboBox>
|
|
||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ public:
|
|||||||
OBS_DEINTERLACE_FIELD_ORDER_TOP;
|
OBS_DEINTERLACE_FIELD_ORDER_TOP;
|
||||||
TempVariableRef _tempVar;
|
TempVariableRef _tempVar;
|
||||||
SourceSetting _setting;
|
SourceSetting _setting;
|
||||||
|
bool _acceptDialog = false;
|
||||||
|
|
||||||
enum class Action {
|
enum class Action {
|
||||||
ENABLE,
|
ENABLE,
|
||||||
@@ -45,6 +47,9 @@ public:
|
|||||||
OPEN_INTERACTION_DIALOG,
|
OPEN_INTERACTION_DIALOG,
|
||||||
OPEN_FILTER_DIALOG,
|
OPEN_FILTER_DIALOG,
|
||||||
OPEN_PROPERTIES_DIALOG,
|
OPEN_PROPERTIES_DIALOG,
|
||||||
|
CLOSE_INTERACTION_DIALOG,
|
||||||
|
CLOSE_FILTER_DIALOG,
|
||||||
|
CLOSE_PROPERTIES_DIALOG,
|
||||||
};
|
};
|
||||||
Action _action = Action::SETTINGS;
|
Action _action = Action::SETTINGS;
|
||||||
|
|
||||||
@@ -91,6 +96,7 @@ private slots:
|
|||||||
void SelectionChanged(const SourceSetting &);
|
void SelectionChanged(const SourceSetting &);
|
||||||
void ManualSettingsValueChanged();
|
void ManualSettingsValueChanged();
|
||||||
void RefreshVariableSourceSelectionValue();
|
void RefreshVariableSourceSelectionValue();
|
||||||
|
void AcceptDialogChanged(int);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
@@ -112,6 +118,7 @@ private:
|
|||||||
QComboBox *_deinterlaceOrder;
|
QComboBox *_deinterlaceOrder;
|
||||||
QLabel *_warning;
|
QLabel *_warning;
|
||||||
QPushButton *_refreshSettingSelection;
|
QPushButton *_refreshSettingSelection;
|
||||||
|
QCheckBox *_acceptDialog;
|
||||||
|
|
||||||
std::shared_ptr<MacroActionSource> _entryData;
|
std::shared_ptr<MacroActionSource> _entryData;
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
|
|||||||
@@ -31,15 +31,16 @@ bool MacroActionTimer::PerformAction()
|
|||||||
if (!macro) {
|
if (!macro) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
auto conditions = *GetMacroConditions(macro.get());
|
|
||||||
for (auto condition : conditions) {
|
const auto updateCondition = [this](MacroCondition *condition) {
|
||||||
if (condition->GetId() != id) {
|
if (condition->GetId() != id) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto timerCondition =
|
auto timerCondition =
|
||||||
dynamic_cast<MacroConditionTimer *>(condition.get());
|
dynamic_cast<MacroConditionTimer *>(condition);
|
||||||
if (!timerCondition) {
|
if (!timerCondition) {
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (_actionType) {
|
switch (_actionType) {
|
||||||
@@ -59,6 +60,23 @@ bool MacroActionTimer::PerformAction()
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto updateMacro = [&](Macro *macro) {
|
||||||
|
auto conditions = *GetMacroConditions(macro);
|
||||||
|
for (auto condition : conditions) {
|
||||||
|
updateCondition(condition.get());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!IsGroupMacro(macro.get())) {
|
||||||
|
updateMacro(macro.get());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto macros = GetGroupMacroEntries(macro.get());
|
||||||
|
for (const auto ¯o : macros) {
|
||||||
|
updateMacro(macro.get());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -131,7 +149,7 @@ void MacroActionTimer::ResolveVariablesToFixedValues()
|
|||||||
_duration.ResolveVariables();
|
_duration.ResolveVariables();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void populateTypeSelection(QComboBox *list)
|
static void populateTypeSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
for (const auto &[_, name] : timerActions) {
|
for (const auto &[_, name] : timerActions) {
|
||||||
list->addItem(obs_module_text(name.c_str()));
|
list->addItem(obs_module_text(name.c_str()));
|
||||||
@@ -140,12 +158,11 @@ static inline void populateTypeSelection(QComboBox *list)
|
|||||||
|
|
||||||
MacroActionTimerEdit::MacroActionTimerEdit(
|
MacroActionTimerEdit::MacroActionTimerEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroActionTimer> entryData)
|
QWidget *parent, std::shared_ptr<MacroActionTimer> entryData)
|
||||||
: QWidget(parent)
|
: QWidget(parent),
|
||||||
|
_macros(new MacroSelection(parent)),
|
||||||
|
_duration(new DurationSelection(this)),
|
||||||
|
_timerAction(new QComboBox(this))
|
||||||
{
|
{
|
||||||
_macros = new MacroSelection(parent);
|
|
||||||
_duration = new DurationSelection();
|
|
||||||
_timerAction = new QComboBox();
|
|
||||||
|
|
||||||
populateTypeSelection(_timerAction);
|
populateTypeSelection(_timerAction);
|
||||||
|
|
||||||
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
|
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
|
||||||
@@ -155,15 +172,13 @@ MacroActionTimerEdit::MacroActionTimerEdit(
|
|||||||
QWidget::connect(_timerAction, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_timerAction, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(ActionTypeChanged(int)));
|
SLOT(ActionTypeChanged(int)));
|
||||||
|
|
||||||
_mainLayout = new QHBoxLayout;
|
auto layout = new QHBoxLayout;
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
|
||||||
{"{{macros}}", _macros},
|
|
||||||
{"{{duration}}", _duration},
|
|
||||||
{"{{timerAction}}", _timerAction},
|
|
||||||
};
|
|
||||||
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.timer.entry"),
|
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.timer.entry"),
|
||||||
_mainLayout, widgetPlaceholders);
|
layout,
|
||||||
setLayout(_mainLayout);
|
{{"{{macros}}", _macros},
|
||||||
|
{"{{duration}}", _duration},
|
||||||
|
{"{{timerAction}}", _timerAction}});
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
UpdateEntryData();
|
UpdateEntryData();
|
||||||
|
|||||||
@@ -58,16 +58,14 @@ private slots:
|
|||||||
signals:
|
signals:
|
||||||
void HeaderInfoChanged(const QString &);
|
void HeaderInfoChanged(const QString &);
|
||||||
|
|
||||||
protected:
|
private:
|
||||||
void SetWidgetVisibility();
|
void SetWidgetVisibility();
|
||||||
|
|
||||||
MacroSelection *_macros;
|
MacroSelection *_macros;
|
||||||
DurationSelection *_duration;
|
DurationSelection *_duration;
|
||||||
QComboBox *_timerAction;
|
QComboBox *_timerAction;
|
||||||
std::shared_ptr<MacroActionTimer> _entryData;
|
|
||||||
|
|
||||||
private:
|
std::shared_ptr<MacroActionTimer> _entryData;
|
||||||
QHBoxLayout *_mainLayout;
|
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "macro-action-transition.hpp"
|
#include "macro-action-transition.hpp"
|
||||||
#include "layout-helpers.hpp"
|
#include "layout-helpers.hpp"
|
||||||
|
#include "transition-helpers.hpp"
|
||||||
|
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
|
|
||||||
@@ -75,26 +76,6 @@ static void obs_sceneitem_set_transition_duration(obs_sceneitem_t *item,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void setSceneItemTransition(const OBSSceneItem &item,
|
|
||||||
const OBSSourceAutoRelease &transition,
|
|
||||||
bool show)
|
|
||||||
{
|
|
||||||
OBSDataAutoRelease settings = obs_source_get_settings(transition);
|
|
||||||
if (!transition || !settings) {
|
|
||||||
// Set transition to "None"
|
|
||||||
obs_sceneitem_set_transition(item, show, nullptr);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We cannot share the transition source between
|
|
||||||
// scene items without introducing strange graphical
|
|
||||||
// artifacts so we have to create new ones here
|
|
||||||
OBSSourceAutoRelease transitionSource = obs_source_create_private(
|
|
||||||
obs_source_get_id(transition), obs_source_get_name(transition),
|
|
||||||
settings);
|
|
||||||
obs_sceneitem_set_transition(item, show, transitionSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionTransition::SetSourceTransition(bool show)
|
void MacroActionTransition::SetSourceTransition(bool show)
|
||||||
{
|
{
|
||||||
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(27, 0, 0)
|
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(27, 0, 0)
|
||||||
@@ -103,7 +84,7 @@ void MacroActionTransition::SetSourceTransition(bool show)
|
|||||||
const auto items = _source.GetSceneItems(_scene);
|
const auto items = _source.GetSceneItems(_scene);
|
||||||
for (const auto &item : items) {
|
for (const auto &item : items) {
|
||||||
if (_setTransitionType) {
|
if (_setTransitionType) {
|
||||||
setSceneItemTransition(item, transition, show);
|
SetSceneItemTransition(item, transition, show);
|
||||||
}
|
}
|
||||||
if (_setDuration) {
|
if (_setDuration) {
|
||||||
obs_sceneitem_set_transition_duration(
|
obs_sceneitem_set_transition_duration(
|
||||||
|
|||||||
@@ -38,32 +38,13 @@ const static std::map<MacroConditionDate::Condition, std::string>
|
|||||||
"AdvSceneSwitcher.condition.date.state.before"},
|
"AdvSceneSwitcher.condition.date.state.before"},
|
||||||
};
|
};
|
||||||
|
|
||||||
const static std::map<MacroConditionDate::Day, std::string> dayOfWeekNames = {
|
|
||||||
{MacroConditionDate::Day::ANY,
|
|
||||||
"AdvSceneSwitcher.condition.date.anyDay"},
|
|
||||||
{MacroConditionDate::Day::MONDAY,
|
|
||||||
"AdvSceneSwitcher.condition.date.monday"},
|
|
||||||
{MacroConditionDate::Day::TUESDAY,
|
|
||||||
"AdvSceneSwitcher.condition.date.tuesday"},
|
|
||||||
{MacroConditionDate::Day::WEDNESDAY,
|
|
||||||
"AdvSceneSwitcher.condition.date.wednesday"},
|
|
||||||
{MacroConditionDate::Day::THURSDAY,
|
|
||||||
"AdvSceneSwitcher.condition.date.thursday"},
|
|
||||||
{MacroConditionDate::Day::FRIDAY,
|
|
||||||
"AdvSceneSwitcher.condition.date.friday"},
|
|
||||||
{MacroConditionDate::Day::SATURDAY,
|
|
||||||
"AdvSceneSwitcher.condition.date.saturday"},
|
|
||||||
{MacroConditionDate::Day::SUNDAY,
|
|
||||||
"AdvSceneSwitcher.condition.date.sunday"},
|
|
||||||
};
|
|
||||||
|
|
||||||
bool MacroConditionDate::CheckDayOfWeek(int64_t msSinceLastCheck)
|
bool MacroConditionDate::CheckDayOfWeek(int64_t msSinceLastCheck)
|
||||||
{
|
{
|
||||||
QDateTime cur = QDateTime::currentDateTime();
|
QDateTime cur = QDateTime::currentDateTime();
|
||||||
SetVariables(cur);
|
SetVariables(cur);
|
||||||
|
|
||||||
if (_dayOfWeek != Day::ANY &&
|
if (!_days.contains(static_cast<DayOfWeekSelector::Day>(
|
||||||
cur.date().dayOfWeek() != static_cast<int>(_dayOfWeek)) {
|
cur.date().dayOfWeek()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (_ignoreTime) {
|
if (_ignoreTime) {
|
||||||
@@ -201,7 +182,7 @@ bool MacroConditionDate::CheckCondition()
|
|||||||
bool MacroConditionDate::Save(obs_data_t *obj) const
|
bool MacroConditionDate::Save(obs_data_t *obj) const
|
||||||
{
|
{
|
||||||
MacroCondition::Save(obj);
|
MacroCondition::Save(obj);
|
||||||
obs_data_set_int(obj, "dayOfWeek", static_cast<int>(_dayOfWeek));
|
SaveSelectedDays(obj, _days);
|
||||||
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
||||||
const auto &dateToSave = _updateOnRepeat ? _dateTime : _origDateTime;
|
const auto &dateToSave = _updateOnRepeat ? _dateTime : _origDateTime;
|
||||||
const auto &dateToSave2 = _updateOnRepeat ? _dateTime2 : _origDateTime2;
|
const auto &dateToSave2 = _updateOnRepeat ? _dateTime2 : _origDateTime2;
|
||||||
@@ -216,13 +197,14 @@ bool MacroConditionDate::Save(obs_data_t *obj) const
|
|||||||
_duration.Save(obj);
|
_duration.Save(obj);
|
||||||
obs_data_set_bool(obj, "dayOfWeekCheck", _dayOfWeekCheck);
|
obs_data_set_bool(obj, "dayOfWeekCheck", _dayOfWeekCheck);
|
||||||
obs_data_set_string(obj, "pattern", _pattern.c_str());
|
obs_data_set_string(obj, "pattern", _pattern.c_str());
|
||||||
|
obs_data_set_int(obj, "version", 1);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionDate::Load(obs_data_t *obj)
|
bool MacroConditionDate::Load(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
MacroCondition::Load(obj);
|
MacroCondition::Load(obj);
|
||||||
_dayOfWeek = static_cast<Day>(obs_data_get_int(obj, "dayOfWeek"));
|
_days = LoadSelectedDays(obj);
|
||||||
_condition = static_cast<MacroConditionDate::Condition>(
|
_condition = static_cast<MacroConditionDate::Condition>(
|
||||||
obs_data_get_int(obj, "condition"));
|
obs_data_get_int(obj, "condition"));
|
||||||
_dateTime = QDateTime::fromString(
|
_dateTime = QDateTime::fromString(
|
||||||
@@ -245,17 +227,64 @@ bool MacroConditionDate::Load(obs_data_t *obj)
|
|||||||
_condition == MacroConditionDate::Condition::BETWEEN) {
|
_condition == MacroConditionDate::Condition::BETWEEN) {
|
||||||
_condition = MacroConditionDate::Condition::AT;
|
_condition = MacroConditionDate::Condition::AT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!obs_data_has_user_value(obj, "version")) {
|
||||||
|
enum class Day {
|
||||||
|
ANY = 0,
|
||||||
|
MONDAY,
|
||||||
|
TUESDAY,
|
||||||
|
WEDNESDAY,
|
||||||
|
THURSDAY,
|
||||||
|
FRIDAY,
|
||||||
|
SATURDAY,
|
||||||
|
SUNDAY,
|
||||||
|
};
|
||||||
|
auto oldDay =
|
||||||
|
static_cast<Day>(obs_data_get_int(obj, "dayOfWeek"));
|
||||||
|
switch (oldDay) {
|
||||||
|
case Day::ANY:
|
||||||
|
_days = {DayOfWeekSelector::Monday,
|
||||||
|
DayOfWeekSelector::Tuesday,
|
||||||
|
DayOfWeekSelector::Wednesday,
|
||||||
|
DayOfWeekSelector::Thursday,
|
||||||
|
DayOfWeekSelector::Friday,
|
||||||
|
DayOfWeekSelector::Saturday,
|
||||||
|
DayOfWeekSelector::Sunday};
|
||||||
|
break;
|
||||||
|
case Day::MONDAY:
|
||||||
|
_days = {DayOfWeekSelector::Monday};
|
||||||
|
break;
|
||||||
|
case Day::TUESDAY:
|
||||||
|
_days = {DayOfWeekSelector::Tuesday};
|
||||||
|
break;
|
||||||
|
case Day::WEDNESDAY:
|
||||||
|
_days = {DayOfWeekSelector::Wednesday};
|
||||||
|
break;
|
||||||
|
case Day::THURSDAY:
|
||||||
|
_days = {DayOfWeekSelector::Thursday};
|
||||||
|
break;
|
||||||
|
case Day::FRIDAY:
|
||||||
|
_days = {DayOfWeekSelector::Friday};
|
||||||
|
break;
|
||||||
|
case Day::SATURDAY:
|
||||||
|
_days = {DayOfWeekSelector::Saturday};
|
||||||
|
break;
|
||||||
|
case Day::SUNDAY:
|
||||||
|
_days = {DayOfWeekSelector::Sunday};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string MacroConditionDate::GetShortDesc() const
|
std::string MacroConditionDate::GetShortDesc() const
|
||||||
{
|
{
|
||||||
if (_dayOfWeekCheck) {
|
if (_dayOfWeekCheck) {
|
||||||
auto it = dayOfWeekNames.find(_dayOfWeek);
|
const auto dayName =
|
||||||
if (it == dayOfWeekNames.end()) {
|
DayOfWeekSelector::ToString(_days).toStdString();
|
||||||
return "";
|
|
||||||
}
|
|
||||||
std::string dayName = obs_module_text(it->second.c_str());
|
|
||||||
if (_ignoreTime) {
|
if (_ignoreTime) {
|
||||||
return dayName;
|
return dayName;
|
||||||
}
|
}
|
||||||
@@ -347,13 +376,6 @@ void MacroConditionDate::SetupTempVars()
|
|||||||
obs_module_text("AdvSceneSwitcher.tempVar.date.dayOfWeek"));
|
obs_module_text("AdvSceneSwitcher.tempVar.date.dayOfWeek"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void populateDaySelection(QComboBox *list)
|
|
||||||
{
|
|
||||||
for (auto entry : dayOfWeekNames) {
|
|
||||||
list->addItem(obs_module_text(entry.second.c_str()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void populateConditionSelection(QComboBox *list)
|
static inline void populateConditionSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
for (auto entry : dateConditionTypes) {
|
for (auto entry : dateConditionTypes) {
|
||||||
@@ -372,7 +394,7 @@ MacroConditionDateEdit::MacroConditionDateEdit(
|
|||||||
QWidget *parent, std::shared_ptr<MacroConditionDate> entryData)
|
QWidget *parent, std::shared_ptr<MacroConditionDate> entryData)
|
||||||
: QWidget(parent),
|
: QWidget(parent),
|
||||||
_weekCondition(new QComboBox()),
|
_weekCondition(new QComboBox()),
|
||||||
_dayOfWeek(new QComboBox()),
|
_days(new DayOfWeekSelector(this)),
|
||||||
_ignoreWeekTime(new QCheckBox()),
|
_ignoreWeekTime(new QCheckBox()),
|
||||||
_weekTime(new QTimeEdit()),
|
_weekTime(new QTimeEdit()),
|
||||||
_condition(new QComboBox()),
|
_condition(new QComboBox()),
|
||||||
@@ -392,7 +414,7 @@ MacroConditionDateEdit::MacroConditionDateEdit(
|
|||||||
_currentDate(new QLabel()),
|
_currentDate(new QLabel()),
|
||||||
_advancedSettingsTooggle(new QPushButton(obs_module_text(
|
_advancedSettingsTooggle(new QPushButton(obs_module_text(
|
||||||
"AdvSceneSwitcher.condition.date.showAdvancedSettings"))),
|
"AdvSceneSwitcher.condition.date.showAdvancedSettings"))),
|
||||||
_simpleLayout(new QHBoxLayout()),
|
_simpleLayout(new QVBoxLayout()),
|
||||||
_advancedLayout(new QHBoxLayout()),
|
_advancedLayout(new QHBoxLayout()),
|
||||||
_repeatLayout(new QVBoxLayout()),
|
_repeatLayout(new QVBoxLayout()),
|
||||||
_repeatUpdateLayout(new QHBoxLayout()),
|
_repeatUpdateLayout(new QHBoxLayout()),
|
||||||
@@ -418,8 +440,8 @@ MacroConditionDateEdit::MacroConditionDateEdit(
|
|||||||
|
|
||||||
QWidget::connect(_weekCondition, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_weekCondition, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(ConditionChanged(int)));
|
SLOT(ConditionChanged(int)));
|
||||||
QWidget::connect(_dayOfWeek, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_days, &DayOfWeekSelector::SelectionChanged, this,
|
||||||
SLOT(DayOfWeekChanged(int)));
|
&MacroConditionDateEdit::DaysChanged);
|
||||||
QWidget::connect(_ignoreWeekTime, SIGNAL(stateChanged(int)), this,
|
QWidget::connect(_ignoreWeekTime, SIGNAL(stateChanged(int)), this,
|
||||||
SLOT(IgnoreTimeChanged(int)));
|
SLOT(IgnoreTimeChanged(int)));
|
||||||
QWidget::connect(_weekTime, SIGNAL(timeChanged(const QTime &)), this,
|
QWidget::connect(_weekTime, SIGNAL(timeChanged(const QTime &)), this,
|
||||||
@@ -449,13 +471,12 @@ MacroConditionDateEdit::MacroConditionDateEdit(
|
|||||||
QWidget::connect(_pattern, SIGNAL(editingFinished()), this,
|
QWidget::connect(_pattern, SIGNAL(editingFinished()), this,
|
||||||
SLOT(PatternChanged()));
|
SLOT(PatternChanged()));
|
||||||
|
|
||||||
populateDaySelection(_dayOfWeek);
|
|
||||||
populateConditionSelection(_condition);
|
populateConditionSelection(_condition);
|
||||||
populateWeekConditionSelection(_weekCondition);
|
populateWeekConditionSelection(_weekCondition);
|
||||||
|
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{weekCondition}}", _weekCondition},
|
{"{{weekCondition}}", _weekCondition},
|
||||||
{"{{dayOfWeek}}", _dayOfWeek},
|
{"{{dayOfWeek}}", _days},
|
||||||
{"{{ignoreWeekTime}}", _ignoreWeekTime},
|
{"{{ignoreWeekTime}}", _ignoreWeekTime},
|
||||||
{"{{weekTime}}", _weekTime},
|
{"{{weekTime}}", _weekTime},
|
||||||
{"{{condition}}", _condition},
|
{"{{condition}}", _condition},
|
||||||
@@ -472,28 +493,39 @@ MacroConditionDateEdit::MacroConditionDateEdit(
|
|||||||
{"{{pattern}}", _pattern},
|
{"{{pattern}}", _pattern},
|
||||||
{"{{currentDate}}", _currentDate},
|
{"{{currentDate}}", _currentDate},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto dayLayout = new QHBoxLayout;
|
||||||
PlaceWidgets(
|
PlaceWidgets(
|
||||||
obs_module_text("AdvSceneSwitcher.condition.date.entry.simple"),
|
obs_module_text(
|
||||||
_simpleLayout, widgetPlaceholders);
|
"AdvSceneSwitcher.condition.date.layout.simple.day"),
|
||||||
|
dayLayout, widgetPlaceholders);
|
||||||
|
auto timeLayout = new QHBoxLayout;
|
||||||
|
PlaceWidgets(
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.date.layout.simple.time"),
|
||||||
|
timeLayout, widgetPlaceholders);
|
||||||
|
_simpleLayout->addLayout(dayLayout);
|
||||||
|
_simpleLayout->addLayout(timeLayout);
|
||||||
|
|
||||||
PlaceWidgets(obs_module_text(
|
PlaceWidgets(obs_module_text(
|
||||||
"AdvSceneSwitcher.condition.date.entry.advanced"),
|
"AdvSceneSwitcher.condition.date.layout.advanced"),
|
||||||
_advancedLayout, widgetPlaceholders);
|
_advancedLayout, widgetPlaceholders);
|
||||||
PlaceWidgets(
|
PlaceWidgets(
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.condition.date.entry.updateOnRepeat"),
|
"AdvSceneSwitcher.condition.date.layout.updateOnRepeat"),
|
||||||
_repeatUpdateLayout, widgetPlaceholders);
|
_repeatUpdateLayout, widgetPlaceholders);
|
||||||
auto repeatLayout = new QHBoxLayout;
|
auto repeatLayout = new QHBoxLayout;
|
||||||
PlaceWidgets(
|
|
||||||
obs_module_text("AdvSceneSwitcher.condition.date.entry.repeat"),
|
|
||||||
repeatLayout, widgetPlaceholders);
|
|
||||||
PlaceWidgets(obs_module_text(
|
PlaceWidgets(obs_module_text(
|
||||||
"AdvSceneSwitcher.condition.date.entry.pattern"),
|
"AdvSceneSwitcher.condition.date.layout.repeat"),
|
||||||
|
repeatLayout, widgetPlaceholders);
|
||||||
|
PlaceWidgets(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.date.layout.pattern"),
|
||||||
_patternLayout, widgetPlaceholders);
|
_patternLayout, widgetPlaceholders);
|
||||||
_repeatLayout->addLayout(repeatLayout);
|
_repeatLayout->addLayout(repeatLayout);
|
||||||
_repeatLayout->addWidget(_nextMatchDate);
|
_repeatLayout->addWidget(_nextMatchDate);
|
||||||
_repeatLayout->addLayout(_repeatUpdateLayout);
|
_repeatLayout->addLayout(_repeatUpdateLayout);
|
||||||
|
|
||||||
auto *mainLayout = new QVBoxLayout;
|
auto mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addLayout(_simpleLayout);
|
mainLayout->addLayout(_simpleLayout);
|
||||||
mainLayout->addLayout(_advancedLayout);
|
mainLayout->addLayout(_advancedLayout);
|
||||||
mainLayout->addLayout(_patternLayout);
|
mainLayout->addLayout(_patternLayout);
|
||||||
@@ -515,10 +547,11 @@ MacroConditionDateEdit::MacroConditionDateEdit(
|
|||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionDateEdit::DayOfWeekChanged(int day)
|
void MacroConditionDateEdit::DaysChanged(
|
||||||
|
const QSet<DayOfWeekSelector::Day> &days)
|
||||||
{
|
{
|
||||||
GUARD_LOADING_AND_LOCK();
|
GUARD_LOADING_AND_LOCK();
|
||||||
_entryData->_dayOfWeek = static_cast<MacroConditionDate::Day>(day);
|
_entryData->_days = days;
|
||||||
emit HeaderInfoChanged(
|
emit HeaderInfoChanged(
|
||||||
QString::fromStdString(_entryData->GetShortDesc()));
|
QString::fromStdString(_entryData->GetShortDesc()));
|
||||||
}
|
}
|
||||||
@@ -632,7 +665,7 @@ void MacroConditionDateEdit::ShowNextMatch()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QString format(obs_module_text(
|
QString format(obs_module_text(
|
||||||
"AdvSceneSwitcher.condition.date.entry.nextMatchDate"));
|
"AdvSceneSwitcher.condition.date.layout.nextMatchDate"));
|
||||||
_nextMatchDate->setText(
|
_nextMatchDate->setText(
|
||||||
format.arg(_entryData->GetNextMatchDateTime().toString()));
|
format.arg(_entryData->GetNextMatchDateTime().toString()));
|
||||||
}
|
}
|
||||||
@@ -658,8 +691,7 @@ void MacroConditionDateEdit::UpdateEntryData()
|
|||||||
}
|
}
|
||||||
_weekCondition->setCurrentIndex(
|
_weekCondition->setCurrentIndex(
|
||||||
static_cast<int>(_entryData->_condition));
|
static_cast<int>(_entryData->_condition));
|
||||||
_dayOfWeek->setCurrentIndex(
|
_days->SetSelectedDays(_entryData->_days);
|
||||||
static_cast<int>(static_cast<int>(_entryData->_dayOfWeek)));
|
|
||||||
_ignoreWeekTime->setChecked(!_entryData->_ignoreTime);
|
_ignoreWeekTime->setChecked(!_entryData->_ignoreTime);
|
||||||
_weekTime->setTime(_entryData->GetDateTime1().time());
|
_weekTime->setTime(_entryData->GetDateTime1().time());
|
||||||
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "macro-condition-edit.hpp"
|
#include "macro-condition-edit.hpp"
|
||||||
|
#include "day-of-week-selector.hpp"
|
||||||
#include "duration-control.hpp"
|
#include "duration-control.hpp"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
@@ -30,17 +31,6 @@ public:
|
|||||||
QDateTime GetDateTime2() const;
|
QDateTime GetDateTime2() const;
|
||||||
QDateTime GetNextMatchDateTime() const;
|
QDateTime GetNextMatchDateTime() const;
|
||||||
|
|
||||||
enum class Day {
|
|
||||||
ANY = 0,
|
|
||||||
MONDAY,
|
|
||||||
TUESDAY,
|
|
||||||
WEDNESDAY,
|
|
||||||
THURSDAY,
|
|
||||||
FRIDAY,
|
|
||||||
SATURDAY,
|
|
||||||
SUNDAY,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class Condition {
|
enum class Condition {
|
||||||
AT,
|
AT,
|
||||||
AFTER,
|
AFTER,
|
||||||
@@ -49,7 +39,11 @@ public:
|
|||||||
PATTERN,
|
PATTERN,
|
||||||
};
|
};
|
||||||
|
|
||||||
Day _dayOfWeek = Day::ANY;
|
QSet<DayOfWeekSelector::Day> _days = {
|
||||||
|
DayOfWeekSelector::Day::Monday,
|
||||||
|
DayOfWeekSelector::Day::Tuesday,
|
||||||
|
DayOfWeekSelector::Day::Wednesday,
|
||||||
|
};
|
||||||
bool _ignoreDate = false;
|
bool _ignoreDate = false;
|
||||||
bool _ignoreTime = false;
|
bool _ignoreTime = false;
|
||||||
bool _repeat = false;
|
bool _repeat = false;
|
||||||
@@ -94,7 +88,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void DayOfWeekChanged(int day);
|
void DaysChanged(const QSet<DayOfWeekSelector::Day> &);
|
||||||
void ConditionChanged(int cond);
|
void ConditionChanged(int cond);
|
||||||
void DateChanged(const QDate &date);
|
void DateChanged(const QDate &date);
|
||||||
void TimeChanged(const QTime &time);
|
void TimeChanged(const QTime &time);
|
||||||
@@ -114,7 +108,7 @@ signals:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
QComboBox *_weekCondition;
|
QComboBox *_weekCondition;
|
||||||
QComboBox *_dayOfWeek;
|
DayOfWeekSelector *_days;
|
||||||
QCheckBox *_ignoreWeekTime;
|
QCheckBox *_ignoreWeekTime;
|
||||||
QTimeEdit *_weekTime;
|
QTimeEdit *_weekTime;
|
||||||
|
|
||||||
@@ -134,7 +128,7 @@ protected:
|
|||||||
QLabel *_currentDate;
|
QLabel *_currentDate;
|
||||||
|
|
||||||
QPushButton *_advancedSettingsTooggle;
|
QPushButton *_advancedSettingsTooggle;
|
||||||
QHBoxLayout *_simpleLayout;
|
QVBoxLayout *_simpleLayout;
|
||||||
QHBoxLayout *_advancedLayout;
|
QHBoxLayout *_advancedLayout;
|
||||||
QVBoxLayout *_repeatLayout;
|
QVBoxLayout *_repeatLayout;
|
||||||
QHBoxLayout *_repeatUpdateLayout;
|
QHBoxLayout *_repeatUpdateLayout;
|
||||||
|
|||||||
@@ -55,17 +55,17 @@ void MacroConditionGameCapture::GetCalldataInfo(calldata_t *cd)
|
|||||||
if (!calldata_get_string(cd, "title", &title)) {
|
if (!calldata_get_string(cd, "title", &title)) {
|
||||||
blog(LOG_WARNING, "%s failed to get title", __func__);
|
blog(LOG_WARNING, "%s failed to get title", __func__);
|
||||||
}
|
}
|
||||||
_title = title;
|
_title = title ? title : "";
|
||||||
const char *className = "";
|
const char *className = "";
|
||||||
if (!calldata_get_string(cd, "class", &className)) {
|
if (!calldata_get_string(cd, "class", &className)) {
|
||||||
blog(LOG_WARNING, "%s failed to get class", __func__);
|
blog(LOG_WARNING, "%s failed to get class", __func__);
|
||||||
}
|
}
|
||||||
_class = className;
|
_class = className ? className : "";
|
||||||
const char *executable = "";
|
const char *executable = "";
|
||||||
if (!calldata_get_string(cd, "executable", &executable)) {
|
if (!calldata_get_string(cd, "executable", &executable)) {
|
||||||
blog(LOG_WARNING, "%s failed to get executable", __func__);
|
blog(LOG_WARNING, "%s failed to get executable", __func__);
|
||||||
}
|
}
|
||||||
_executable = executable;
|
_executable = executable ? executable : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionGameCapture::HookedSignalReceived(void *data, calldata_t *cd)
|
void MacroConditionGameCapture::HookedSignalReceived(void *data, calldata_t *cd)
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ void MacroConditionProcessEdit::ProcessChanged(const QString &text)
|
|||||||
QString::fromStdString(_entryData->GetShortDesc()));
|
QString::fromStdString(_entryData->GetShortDesc()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionProcessEdit::showEvent(QShowEvent *event)
|
void MacroConditionProcessEdit::showEvent(QShowEvent *)
|
||||||
{
|
{
|
||||||
const QSignalBlocker b(_processSelection);
|
const QSignalBlocker b(_processSelection);
|
||||||
const auto text = _processSelection->currentText();
|
const auto text = _processSelection->currentText();
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ static int currentRecordingDurationInSeconds = 0;
|
|||||||
|
|
||||||
bool MacroConditionRecord::CheckCondition()
|
bool MacroConditionRecord::CheckCondition()
|
||||||
{
|
{
|
||||||
|
char *lastSavePath = obs_frontend_get_last_recording();
|
||||||
|
SetTempVarValue("lastSavePath", lastSavePath ? lastSavePath : "");
|
||||||
|
bfree(lastSavePath);
|
||||||
|
|
||||||
switch (_condition) {
|
switch (_condition) {
|
||||||
case Condition::STOP:
|
case Condition::STOP:
|
||||||
return !obs_frontend_recording_active();
|
return !obs_frontend_recording_active();
|
||||||
@@ -74,6 +78,14 @@ void MacroConditionRecord::SetCondition(Condition condition)
|
|||||||
void MacroConditionRecord::SetupTempVars()
|
void MacroConditionRecord::SetupTempVars()
|
||||||
{
|
{
|
||||||
MacroCondition::SetupTempVars();
|
MacroCondition::SetupTempVars();
|
||||||
|
|
||||||
|
AddTempvar(
|
||||||
|
"lastSavePath",
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.recording.lastSavePath"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.recording.lastSavePath.description"));
|
||||||
|
|
||||||
switch (_condition) {
|
switch (_condition) {
|
||||||
case Condition::DURATION:
|
case Condition::DURATION:
|
||||||
AddTempvar(
|
AddTempvar(
|
||||||
|
|||||||
@@ -58,6 +58,10 @@ bool MacroConditionReplayBuffer::ReplayBufferWasSaved()
|
|||||||
|
|
||||||
bool MacroConditionReplayBuffer::CheckCondition()
|
bool MacroConditionReplayBuffer::CheckCondition()
|
||||||
{
|
{
|
||||||
|
char *lastSavePath = obs_frontend_get_last_replay();
|
||||||
|
SetTempVarValue("lastSavePath", lastSavePath ? lastSavePath : "");
|
||||||
|
bfree(lastSavePath);
|
||||||
|
|
||||||
switch (_state) {
|
switch (_state) {
|
||||||
case Condition::STOP:
|
case Condition::STOP:
|
||||||
return !obs_frontend_replay_buffer_active();
|
return !obs_frontend_replay_buffer_active();
|
||||||
@@ -85,6 +89,16 @@ bool MacroConditionReplayBuffer::Load(obs_data_t *obj)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroConditionReplayBuffer::SetupTempVars()
|
||||||
|
{
|
||||||
|
MacroCondition::SetupTempVars();
|
||||||
|
AddTempvar(
|
||||||
|
"lastSavePath",
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.replay.lastSavePath"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.replay.lastSavePath.description"));
|
||||||
|
}
|
||||||
|
|
||||||
static inline void populateStateSelection(QComboBox *list)
|
static inline void populateStateSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
for (const auto &entry : conditions) {
|
for (const auto &entry : conditions) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace advss {
|
namespace advss {
|
||||||
|
|
||||||
class MacroConditionReplayBuffer : public MacroCondition {
|
class MacroConditionReplayBuffer final : public MacroCondition {
|
||||||
public:
|
public:
|
||||||
MacroConditionReplayBuffer(Macro *m) : MacroCondition(m) {}
|
MacroConditionReplayBuffer(Macro *m) : MacroCondition(m) {}
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
@@ -27,6 +27,7 @@ public:
|
|||||||
Condition _state = Condition::STOP;
|
Condition _state = Condition::STOP;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void SetupTempVars();
|
||||||
bool ReplayBufferWasSaved();
|
bool ReplayBufferWasSaved();
|
||||||
|
|
||||||
bool _saveTimeInitialized = false;
|
bool _saveTimeInitialized = false;
|
||||||
@@ -35,7 +36,7 @@ private:
|
|||||||
static const std::string id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionReplayBufferEdit : public QWidget {
|
class MacroConditionReplayBufferEdit final : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -55,11 +56,10 @@ public:
|
|||||||
private slots:
|
private slots:
|
||||||
void StateChanged(int value);
|
void StateChanged(int value);
|
||||||
|
|
||||||
protected:
|
|
||||||
QComboBox *_state;
|
|
||||||
std::shared_ptr<MacroConditionReplayBuffer> _entryData;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QComboBox *_state;
|
||||||
|
|
||||||
|
std::shared_ptr<MacroConditionReplayBuffer> _entryData;
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -252,6 +252,7 @@ MacroConditionSlideshowEdit::MacroConditionSlideshowEdit(
|
|||||||
setToolTip(obs_module_text(
|
setToolTip(obs_module_text(
|
||||||
"AdvSceneSwitcher.condition.slideshow.updateInterval.tooltip"));
|
"AdvSceneSwitcher.condition.slideshow.updateInterval.tooltip"));
|
||||||
_index->setMinimum(1);
|
_index->setMinimum(1);
|
||||||
|
_index->setMaximum(9999);
|
||||||
populateConditionSelection(_conditions);
|
populateConditionSelection(_conditions);
|
||||||
|
|
||||||
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
|||||||
@@ -29,6 +29,22 @@ static bool windowContainsText(const std::string &window,
|
|||||||
return text == matchText;
|
return text == matchText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroConditionWindow::SetCheckText(bool value)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
_checkText = value;
|
||||||
|
#else
|
||||||
|
(void)value;
|
||||||
|
_checkText = false;
|
||||||
|
#endif
|
||||||
|
SetupTempVars();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionWindow::GetCheckText()
|
||||||
|
{
|
||||||
|
return _checkText;
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroConditionWindow::WindowMatchesRequirements(
|
bool MacroConditionWindow::WindowMatchesRequirements(
|
||||||
const std::string &window) const
|
const std::string &window) const
|
||||||
{
|
{
|
||||||
@@ -94,12 +110,18 @@ void MacroConditionWindow::SetVariableValueBasedOnMatch(
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
SetTempVarValue("windowClass",
|
SetTempVarValue("windowClass",
|
||||||
GetWindowClassByWindowTitle(matchWindow));
|
GetWindowClassByWindowTitle(matchWindow));
|
||||||
|
if (_checkText) {
|
||||||
|
const auto text = GetTextInWindow(matchWindow);
|
||||||
|
if (text) {
|
||||||
|
SetTempVarValue("windowText", *text);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!IsReferencedInVars()) {
|
if (!IsReferencedInVars()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (_checkText) {
|
if (_checkText) {
|
||||||
auto text = GetTextInWindow(matchWindow);
|
const auto text = GetTextInWindow(matchWindow);
|
||||||
SetVariableValue(text.value_or(""));
|
SetVariableValue(text.value_or(""));
|
||||||
} else {
|
} else {
|
||||||
SetVariableValue(ForegroundWindowTitle());
|
SetVariableValue(ForegroundWindowTitle());
|
||||||
@@ -186,6 +208,16 @@ void MacroConditionWindow::SetupTempVars()
|
|||||||
obs_module_text("AdvSceneSwitcher.tempVar.window.windowClass"),
|
obs_module_text("AdvSceneSwitcher.tempVar.window.windowClass"),
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.tempVar.window.windowClass.description"));
|
"AdvSceneSwitcher.tempVar.window.windowClass.description"));
|
||||||
|
|
||||||
|
if (!_checkText) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddTempvar(
|
||||||
|
"windowText",
|
||||||
|
obs_module_text("AdvSceneSwitcher.tempVar.window.windowText"),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.tempVar.window.windowText.description"));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +381,7 @@ void MacroConditionWindowEdit::CheckTitleChanged(int state)
|
|||||||
void MacroConditionWindowEdit::CheckTextChanged(int state)
|
void MacroConditionWindowEdit::CheckTextChanged(int state)
|
||||||
{
|
{
|
||||||
GUARD_LOADING_AND_LOCK();
|
GUARD_LOADING_AND_LOCK();
|
||||||
_entryData->_checkText = state;
|
_entryData->SetCheckText(state);
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,8 +441,8 @@ void MacroConditionWindowEdit::SetWidgetVisibility()
|
|||||||
_entryData->_focus || _entryData->_windowFocusChanged);
|
_entryData->_focus || _entryData->_windowFocusChanged);
|
||||||
_windowSelection->setVisible(_entryData->_checkTitle);
|
_windowSelection->setVisible(_entryData->_checkTitle);
|
||||||
_windowRegex->setVisible(_entryData->_checkTitle);
|
_windowRegex->setVisible(_entryData->_checkTitle);
|
||||||
_textRegex->setVisible(_entryData->_checkText);
|
_textRegex->setVisible(_entryData->GetCheckText());
|
||||||
_text->setVisible(_entryData->_checkText);
|
_text->setVisible(_entryData->GetCheckText());
|
||||||
adjustSize();
|
adjustSize();
|
||||||
updateGeometry();
|
updateGeometry();
|
||||||
}
|
}
|
||||||
@@ -429,7 +461,7 @@ void MacroConditionWindowEdit::UpdateEntryData()
|
|||||||
_maximized->setChecked(_entryData->_maximized);
|
_maximized->setChecked(_entryData->_maximized);
|
||||||
_focused->setChecked(_entryData->_focus);
|
_focused->setChecked(_entryData->_focus);
|
||||||
_windowFocusChanged->setChecked(_entryData->_windowFocusChanged);
|
_windowFocusChanged->setChecked(_entryData->_windowFocusChanged);
|
||||||
_checkText->setChecked(_entryData->_checkText);
|
_checkText->setChecked(_entryData->GetCheckText());
|
||||||
_text->setPlainText(_entryData->_text);
|
_text->setPlainText(_entryData->_text);
|
||||||
_textRegex->SetRegexConfig(_entryData->_textRegex);
|
_textRegex->SetRegexConfig(_entryData->_textRegex);
|
||||||
SetWidgetVisibility();
|
SetWidgetVisibility();
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ public:
|
|||||||
return std::make_shared<MacroConditionWindow>(m);
|
return std::make_shared<MacroConditionWindow>(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetCheckText(bool value);
|
||||||
|
bool GetCheckText();
|
||||||
|
|
||||||
StringVariable _window;
|
StringVariable _window;
|
||||||
RegexConfig _windowRegex;
|
RegexConfig _windowRegex;
|
||||||
bool _checkTitle = true;
|
bool _checkTitle = true;
|
||||||
@@ -30,8 +33,6 @@ public:
|
|||||||
bool _focus = true;
|
bool _focus = true;
|
||||||
bool _windowFocusChanged = false;
|
bool _windowFocusChanged = false;
|
||||||
|
|
||||||
// For now only supported on Windows
|
|
||||||
bool _checkText = false;
|
|
||||||
StringVariable _text;
|
StringVariable _text;
|
||||||
RegexConfig _textRegex = RegexConfig::PartialMatchRegexConfig();
|
RegexConfig _textRegex = RegexConfig::PartialMatchRegexConfig();
|
||||||
|
|
||||||
@@ -42,6 +43,9 @@ private:
|
|||||||
void SetVariableValueBasedOnMatch(const std::string &matchWindow);
|
void SetVariableValueBasedOnMatch(const std::string &matchWindow);
|
||||||
void SetupTempVars();
|
void SetupTempVars();
|
||||||
|
|
||||||
|
// For now only supported on Windows
|
||||||
|
bool _checkText = false;
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const std::string id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|||||||
121
plugins/base/utils/day-of-week-selector.cpp
Normal file
121
plugins/base/utils/day-of-week-selector.cpp
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
#include "day-of-week-selector.hpp"
|
||||||
|
#include "obs-module-helper.hpp"
|
||||||
|
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
DayOfWeekSelector::DayOfWeekSelector(QWidget *parent) : QWidget(parent)
|
||||||
|
{
|
||||||
|
auto layout = new QHBoxLayout(this);
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
layout->setSpacing(4);
|
||||||
|
|
||||||
|
const QVector<QPair<Day, QString>> days = {
|
||||||
|
{Monday, obs_module_text("AdvSceneSwitcher.day.monday")},
|
||||||
|
{Tuesday, obs_module_text("AdvSceneSwitcher.day.tuesday")},
|
||||||
|
{Wednesday, obs_module_text("AdvSceneSwitcher.day.wednesday")},
|
||||||
|
{Thursday, obs_module_text("AdvSceneSwitcher.day.thursday")},
|
||||||
|
{Friday, obs_module_text("AdvSceneSwitcher.day.friday")},
|
||||||
|
{Saturday, obs_module_text("AdvSceneSwitcher.day.saturday")},
|
||||||
|
{Sunday, obs_module_text("AdvSceneSwitcher.day.sunday")}};
|
||||||
|
|
||||||
|
for (const auto &[day, name] : days) {
|
||||||
|
auto btn = new QPushButton(this);
|
||||||
|
btn->setText(name);
|
||||||
|
btn->setCheckable(true);
|
||||||
|
|
||||||
|
connect(btn, &QPushButton::toggled, this,
|
||||||
|
&DayOfWeekSelector::OnButtonToggled);
|
||||||
|
|
||||||
|
layout->addWidget(btn);
|
||||||
|
m_buttons.insert(day, btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLayout(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DayOfWeekSelector::OnButtonToggled(bool)
|
||||||
|
{
|
||||||
|
emit SelectionChanged(SelectedDays());
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<DayOfWeekSelector::Day> DayOfWeekSelector::SelectedDays() const
|
||||||
|
{
|
||||||
|
QSet<Day> result;
|
||||||
|
for (auto it = m_buttons.begin(); it != m_buttons.end(); ++it) {
|
||||||
|
if (it.value()->isChecked()) {
|
||||||
|
result.insert(it.key());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DayOfWeekSelector::SetSelectedDays(const QSet<Day> &days)
|
||||||
|
{
|
||||||
|
for (auto it = m_buttons.begin(); it != m_buttons.end(); ++it) {
|
||||||
|
it.value()->setChecked(days.contains(it.key()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DayOfWeekSelector::ToString(const QSet<Day> &days)
|
||||||
|
{
|
||||||
|
const QVector<QPair<Day, QString>> dayNames = {
|
||||||
|
{Monday, obs_module_text("AdvSceneSwitcher.day.monday")},
|
||||||
|
{Tuesday, obs_module_text("AdvSceneSwitcher.day.tuesday")},
|
||||||
|
{Wednesday, obs_module_text("AdvSceneSwitcher.day.wednesday")},
|
||||||
|
{Thursday, obs_module_text("AdvSceneSwitcher.day.thursday")},
|
||||||
|
{Friday, obs_module_text("AdvSceneSwitcher.day.friday")},
|
||||||
|
{Saturday, obs_module_text("AdvSceneSwitcher.day.saturday")},
|
||||||
|
{Sunday, obs_module_text("AdvSceneSwitcher.day.sunday")}};
|
||||||
|
|
||||||
|
if (days.isEmpty()) {
|
||||||
|
return obs_module_text("AdvSceneSwitcher.day.none");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (days.size() == 7) {
|
||||||
|
return obs_module_text("AdvSceneSwitcher.day.any");
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList parts;
|
||||||
|
for (const auto &[day, name] : dayNames) {
|
||||||
|
if (days.contains(day)) {
|
||||||
|
parts << name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts.join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveSelectedDays(obs_data_t *settings,
|
||||||
|
const QSet<DayOfWeekSelector::Day> &days)
|
||||||
|
{
|
||||||
|
uint64_t mask = 0;
|
||||||
|
|
||||||
|
for (DayOfWeekSelector::Day day : days) {
|
||||||
|
mask |= (1ULL << static_cast<int>(day));
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_set_int(settings, "selectedDays",
|
||||||
|
static_cast<long long>(mask));
|
||||||
|
}
|
||||||
|
|
||||||
|
QSet<DayOfWeekSelector::Day> LoadSelectedDays(obs_data_t *settings)
|
||||||
|
{
|
||||||
|
QSet<DayOfWeekSelector::Day> result;
|
||||||
|
|
||||||
|
uint64_t mask = static_cast<uint64_t>(
|
||||||
|
obs_data_get_int(settings, "selectedDays"));
|
||||||
|
|
||||||
|
for (int i = DayOfWeekSelector::Monday; i <= DayOfWeekSelector::Sunday;
|
||||||
|
++i) {
|
||||||
|
if (mask & (1ULL << i)) {
|
||||||
|
result.insert(static_cast<DayOfWeekSelector::Day>(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
45
plugins/base/utils/day-of-week-selector.hpp
Normal file
45
plugins/base/utils/day-of-week-selector.hpp
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QSet>
|
||||||
|
|
||||||
|
#include <obs-data.h>
|
||||||
|
|
||||||
|
class QPushButton;
|
||||||
|
|
||||||
|
namespace advss {
|
||||||
|
|
||||||
|
class DayOfWeekSelector : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Day {
|
||||||
|
Monday = 1,
|
||||||
|
Tuesday,
|
||||||
|
Wednesday,
|
||||||
|
Thursday,
|
||||||
|
Friday,
|
||||||
|
Saturday,
|
||||||
|
Sunday
|
||||||
|
};
|
||||||
|
Q_ENUM(Day)
|
||||||
|
|
||||||
|
explicit DayOfWeekSelector(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
QSet<Day> SelectedDays() const;
|
||||||
|
void SetSelectedDays(const QSet<Day> &days);
|
||||||
|
static QString ToString(const QSet<Day> &days);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void SelectionChanged(const QSet<Day> &days);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void OnButtonToggled(bool checked);
|
||||||
|
|
||||||
|
QMap<Day, QPushButton *> m_buttons;
|
||||||
|
};
|
||||||
|
|
||||||
|
void SaveSelectedDays(obs_data_t *settings,
|
||||||
|
const QSet<DayOfWeekSelector::Day> &days);
|
||||||
|
QSet<DayOfWeekSelector::Day> LoadSelectedDays(obs_data_t *settings);
|
||||||
|
|
||||||
|
} // namespace advss
|
||||||
@@ -10,7 +10,7 @@ namespace advss {
|
|||||||
enum class HotkeyType;
|
enum class HotkeyType;
|
||||||
|
|
||||||
bool CanSimulateKeyPresses();
|
bool CanSimulateKeyPresses();
|
||||||
void PressKeys(const std::vector<HotkeyType> keys, int duration);
|
void PressKeys(const std::vector<HotkeyType> &keys, int duration);
|
||||||
|
|
||||||
class Hotkey {
|
class Hotkey {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ static const std::unordered_map<HotkeyType, long> keyTable = {
|
|||||||
{HotkeyType::Key_NumpadEnter, XK_KP_Enter},
|
{HotkeyType::Key_NumpadEnter, XK_KP_Enter},
|
||||||
};
|
};
|
||||||
|
|
||||||
void PressKeys(const std::vector<HotkeyType> keys, int duration)
|
void PressKeys(const std::vector<HotkeyType> &keys, int duration)
|
||||||
{
|
{
|
||||||
if (!canSimulateKeyPresses) {
|
if (!canSimulateKeyPresses) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user