mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-05-01 02:27:02 -05:00
Merge branch 'master' into virtual-desktop
This commit is contained in:
commit
d66a2dc408
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
|
@ -200,7 +200,7 @@ jobs:
|
||||||
QT_VERSION: 5.10.1
|
QT_VERSION: 5.10.1
|
||||||
CMAKE_GENERATOR: "Visual Studio 16 2019"
|
CMAKE_GENERATOR: "Visual Studio 16 2019"
|
||||||
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
|
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
|
||||||
WINDOWS_DEPS_VERSION: '2017'
|
WINDOWS_DEPS_VERSION: '2019'
|
||||||
steps:
|
steps:
|
||||||
- name: Add msbuild to PATH
|
- name: Add msbuild to PATH
|
||||||
uses: microsoft/setup-msbuild@v1.0.2
|
uses: microsoft/setup-msbuild@v1.0.2
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,6 @@ set(advanced-scene-switcher_HEADERS
|
||||||
${advanced-scene-switcher_HEADERS}
|
${advanced-scene-switcher_HEADERS}
|
||||||
src/headers/advanced-scene-switcher.hpp
|
src/headers/advanced-scene-switcher.hpp
|
||||||
src/headers/switcher-data-structs.hpp
|
src/headers/switcher-data-structs.hpp
|
||||||
src/headers/utility.hpp
|
|
||||||
src/headers/scene-group.hpp
|
src/headers/scene-group.hpp
|
||||||
src/headers/scene-trigger.hpp
|
src/headers/scene-trigger.hpp
|
||||||
src/headers/switch-audio.hpp
|
src/headers/switch-audio.hpp
|
||||||
|
|
@ -82,32 +81,44 @@ set(advanced-scene-switcher_HEADERS
|
||||||
src/headers/switch-generic.hpp
|
src/headers/switch-generic.hpp
|
||||||
src/headers/macro-action-edit.hpp
|
src/headers/macro-action-edit.hpp
|
||||||
src/headers/macro-action-audio.hpp
|
src/headers/macro-action-audio.hpp
|
||||||
|
src/headers/macro-action-filter.hpp
|
||||||
|
src/headers/macro-action-macro.hpp
|
||||||
|
src/headers/macro-action-media.hpp
|
||||||
|
src/headers/macro-action-plugin-state.hpp
|
||||||
src/headers/macro-action-recording.hpp
|
src/headers/macro-action-recording.hpp
|
||||||
src/headers/macro-action-replay-buffer.hpp
|
src/headers/macro-action-replay-buffer.hpp
|
||||||
src/headers/macro-action-run.hpp
|
src/headers/macro-action-run.hpp
|
||||||
|
src/headers/macro-action-scene-switch.hpp
|
||||||
|
src/headers/macro-action-scene-visibility.hpp
|
||||||
|
src/headers/macro-action-source.hpp
|
||||||
src/headers/macro-action-streaming.hpp
|
src/headers/macro-action-streaming.hpp
|
||||||
src/headers/macro-action-switch-scene.hpp
|
|
||||||
src/headers/macro-action-wait.hpp
|
src/headers/macro-action-wait.hpp
|
||||||
src/headers/macro-condition-edit.hpp
|
src/headers/macro-condition-edit.hpp
|
||||||
src/headers/macro-condition-audio.hpp
|
src/headers/macro-condition-audio.hpp
|
||||||
|
src/headers/macro-condition-counter.hpp
|
||||||
src/headers/macro-condition-file.hpp
|
src/headers/macro-condition-file.hpp
|
||||||
src/headers/macro-condition-idle.hpp
|
src/headers/macro-condition-idle.hpp
|
||||||
|
src/headers/macro-condition-interval.hpp
|
||||||
src/headers/macro-condition-media.hpp
|
src/headers/macro-condition-media.hpp
|
||||||
src/headers/macro-condition-plugin-state.hpp
|
src/headers/macro-condition-plugin-state.hpp
|
||||||
src/headers/macro-condition-process.hpp
|
src/headers/macro-condition-process.hpp
|
||||||
src/headers/macro-condition-recording.hpp
|
src/headers/macro-condition-recording.hpp
|
||||||
src/headers/macro-condition-region.hpp
|
src/headers/macro-condition-region.hpp
|
||||||
src/headers/macro-condition-scene.hpp
|
src/headers/macro-condition-scene.hpp
|
||||||
|
src/headers/macro-condition-source.hpp
|
||||||
src/headers/macro-condition-streaming.hpp
|
src/headers/macro-condition-streaming.hpp
|
||||||
src/headers/macro-condition-video.hpp
|
src/headers/macro-condition-video.hpp
|
||||||
src/headers/macro-condition-virt-desktop.hpp
|
src/headers/macro-condition-virt-desktop.hpp
|
||||||
src/headers/macro-condition-window.hpp
|
src/headers/macro-condition-window.hpp
|
||||||
src/headers/macro.hpp
|
src/headers/macro.hpp
|
||||||
|
src/headers/macro-selection.hpp
|
||||||
src/headers/curl-helper.hpp
|
src/headers/curl-helper.hpp
|
||||||
src/headers/screenshot-helper.hpp
|
src/headers/screenshot-helper.hpp
|
||||||
src/headers/name-dialog.hpp
|
src/headers/name-dialog.hpp
|
||||||
src/headers/duration-control.hpp
|
src/headers/duration-control.hpp
|
||||||
src/headers/section.hpp
|
src/headers/section.hpp
|
||||||
|
src/headers/platform-funcs.hpp
|
||||||
|
src/headers/utility.hpp
|
||||||
src/headers/volume-control.hpp
|
src/headers/volume-control.hpp
|
||||||
src/headers/version.h
|
src/headers/version.h
|
||||||
)
|
)
|
||||||
|
|
@ -139,33 +150,44 @@ set(advanced-scene-switcher_SOURCES
|
||||||
src/switch-generic.cpp
|
src/switch-generic.cpp
|
||||||
src/macro-action-edit.cpp
|
src/macro-action-edit.cpp
|
||||||
src/macro-action-audio.cpp
|
src/macro-action-audio.cpp
|
||||||
|
src/macro-action-filter.cpp
|
||||||
|
src/macro-action-macro.cpp
|
||||||
|
src/macro-action-media.cpp
|
||||||
|
src/macro-action-plugin-state.cpp
|
||||||
src/macro-action-recording.cpp
|
src/macro-action-recording.cpp
|
||||||
src/macro-action-replay-buffer.cpp
|
src/macro-action-replay-buffer.cpp
|
||||||
src/macro-action-run.cpp
|
src/macro-action-run.cpp
|
||||||
|
src/macro-action-scene-switch.cpp
|
||||||
|
src/macro-action-scene-visibility.cpp
|
||||||
|
src/macro-action-source.cpp
|
||||||
src/macro-action-streaming.cpp
|
src/macro-action-streaming.cpp
|
||||||
src/macro-action-switch-scene.cpp
|
|
||||||
src/macro-action-wait.cpp
|
src/macro-action-wait.cpp
|
||||||
src/macro-condition-edit.cpp
|
src/macro-condition-edit.cpp
|
||||||
src/macro-condition-audio.cpp
|
src/macro-condition-audio.cpp
|
||||||
|
src/macro-condition-counter.cpp
|
||||||
src/macro-condition-file.cpp
|
src/macro-condition-file.cpp
|
||||||
src/macro-condition-idle.cpp
|
src/macro-condition-idle.cpp
|
||||||
|
src/macro-condition-interval.cpp
|
||||||
src/macro-condition-media.cpp
|
src/macro-condition-media.cpp
|
||||||
src/macro-condition-plugin-state.cpp
|
src/macro-condition-plugin-state.cpp
|
||||||
src/macro-condition-process.cpp
|
src/macro-condition-process.cpp
|
||||||
src/macro-condition-recording.cpp
|
src/macro-condition-recording.cpp
|
||||||
src/macro-condition-region.cpp
|
src/macro-condition-region.cpp
|
||||||
src/macro-condition-scene.cpp
|
src/macro-condition-scene.cpp
|
||||||
|
src/macro-condition-source.cpp
|
||||||
src/macro-condition-streaming.cpp
|
src/macro-condition-streaming.cpp
|
||||||
src/macro-condition-video.cpp
|
src/macro-condition-video.cpp
|
||||||
src/macro-condition-virt-desktop.cpp
|
src/macro-condition-virt-desktop.cpp
|
||||||
src/macro-condition-window.cpp
|
src/macro-condition-window.cpp
|
||||||
src/macro.cpp
|
src/macro.cpp
|
||||||
|
src/macro-selection.cpp
|
||||||
src/macro-tab.cpp
|
src/macro-tab.cpp
|
||||||
src/curl-helper.cpp
|
src/curl-helper.cpp
|
||||||
src/screenshot-helper.cpp
|
src/screenshot-helper.cpp
|
||||||
src/name-dialog.cpp
|
src/name-dialog.cpp
|
||||||
src/duration-control.cpp
|
src/duration-control.cpp
|
||||||
src/section.cpp
|
src/section.cpp
|
||||||
|
src/utility.cpp
|
||||||
src/volume-control.cpp
|
src/volume-control.cpp
|
||||||
src/version.cpp
|
src/version.cpp
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,9 @@ AdvSceneSwitcher.networkTab.Disabledwarning="Diese Funktionalität musste unter
|
||||||
AdvSceneSwitcher.networkTab.server="Server starten (Sendet Szenenwechselnachrichten zu allen verbundenen Clients)"
|
AdvSceneSwitcher.networkTab.server="Server starten (Sendet Szenenwechselnachrichten zu allen verbundenen Clients)"
|
||||||
AdvSceneSwitcher.networkTab.server.port="Port"
|
AdvSceneSwitcher.networkTab.server.port="Port"
|
||||||
AdvSceneSwitcher.networkTab.server.lockToIPv4="Nur IPv4 verwenden (deaktiviert IPv6)"
|
AdvSceneSwitcher.networkTab.server.lockToIPv4="Nur IPv4 verwenden (deaktiviert IPv6)"
|
||||||
AdvSceneSwitcher.networkTab.server.restrictSendToAutomatedSwitches="Sende nur Szenenwechselnachrichten für automatisierte Szenenwechsel"
|
AdvSceneSwitcher.networkTab.server.sendSceneChange="Sende Nachrichten für Szenenwechsel"
|
||||||
|
AdvSceneSwitcher.networkTab.server.restrictSendToAutomatedSwitches="Sende nur Szenenwechselnachrichten für automatisierte Szenenwechsel"
|
||||||
|
AdvSceneSwitcher.networkTab.server.sendPreview="Sende Nachrichten für Vorschau Szenenwechsel im Studio-Modus"
|
||||||
AdvSceneSwitcher.networkTab.startFailed.message="Der WebSocket-Server konnte nicht gestartet werden, mögliche Gründe:\n - Der TCP-Port %1 wird möglicherweise gerade von einem anderen Programm verwendet. Versuchen Sie einen anderen Port in den Websocket-Servereinstellungen zu setzen oder alle Programme zu beenden, die den Port möglicherweise verwenden.\n - Fehler: %2"
|
AdvSceneSwitcher.networkTab.startFailed.message="Der WebSocket-Server konnte nicht gestartet werden, mögliche Gründe:\n - Der TCP-Port %1 wird möglicherweise gerade von einem anderen Programm verwendet. Versuchen Sie einen anderen Port in den Websocket-Servereinstellungen zu setzen oder alle Programme zu beenden, die den Port möglicherweise verwenden.\n - Fehler: %2"
|
||||||
AdvSceneSwitcher.networkTab.server.status.currentStatus="Aktueller Status"
|
AdvSceneSwitcher.networkTab.server.status.currentStatus="Aktueller Status"
|
||||||
AdvSceneSwitcher.networkTab.server.status.notRunning="Nicht gestartet"
|
AdvSceneSwitcher.networkTab.server.status.notRunning="Nicht gestartet"
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,8 @@ AdvSceneSwitcher.generalTab.priority.macro="Macro"
|
||||||
AdvSceneSwitcher.macroTab.title="Macro"
|
AdvSceneSwitcher.macroTab.title="Macro"
|
||||||
AdvSceneSwitcher.macroTab.macros="Macros"
|
AdvSceneSwitcher.macroTab.macros="Macros"
|
||||||
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.editConditionHelp="This section allows you to define Macro conditions.\n\nSelect an existing or add a new Macro on the left."
|
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.\n\nSelect an existing or add a new Macro on the left."
|
AdvSceneSwitcher.macroTab.editActionHelp="This section allows you to define Macro actions.\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.edit="Edit macro"
|
AdvSceneSwitcher.macroTab.edit="Edit macro"
|
||||||
AdvSceneSwitcher.macroTab.edit.logic="Logic type:"
|
AdvSceneSwitcher.macroTab.edit.logic="Logic type:"
|
||||||
AdvSceneSwitcher.macroTab.edit.condition="Condition type:"
|
AdvSceneSwitcher.macroTab.edit.condition="Condition type:"
|
||||||
|
|
@ -68,6 +68,7 @@ AdvSceneSwitcher.macroTab.name="Name:"
|
||||||
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
||||||
AdvSceneSwitcher.macroTab.exists="Macro name exists already"
|
AdvSceneSwitcher.macroTab.exists="Macro name exists already"
|
||||||
AdvSceneSwitcher.macroTab.copy="Create copy"
|
AdvSceneSwitcher.macroTab.copy="Create copy"
|
||||||
|
|
||||||
; Macro Logic
|
; Macro Logic
|
||||||
AdvSceneSwitcher.logic.none="Ignore entry"
|
AdvSceneSwitcher.logic.none="Ignore entry"
|
||||||
AdvSceneSwitcher.logic.and="And"
|
AdvSceneSwitcher.logic.and="And"
|
||||||
|
|
@ -76,17 +77,18 @@ AdvSceneSwitcher.logic.andNot="And not"
|
||||||
AdvSceneSwitcher.logic.orNot="Or not"
|
AdvSceneSwitcher.logic.orNot="Or not"
|
||||||
AdvSceneSwitcher.logic.rootNone="If"
|
AdvSceneSwitcher.logic.rootNone="If"
|
||||||
AdvSceneSwitcher.logic.not="If not"
|
AdvSceneSwitcher.logic.not="If not"
|
||||||
|
|
||||||
; Macro Conditions
|
; Macro Conditions
|
||||||
AdvSceneSwitcher.condition.audio="Audio"
|
AdvSceneSwitcher.condition.audio="Audio"
|
||||||
AdvSceneSwitcher.ondition.audio.state.below="Below"
|
AdvSceneSwitcher.condition.audio.state.below="Below"
|
||||||
AdvSceneSwitcher.ondition.audio.state.above="Above"
|
AdvSceneSwitcher.condition.audio.state.above="Above"
|
||||||
AdvSceneSwitcher.condition.audio.entry="Volume of {{audioSources}} is {{condition}} {{volume}} for {{duration}} seconds"
|
AdvSceneSwitcher.condition.audio.entry="Volume of {{audioSources}} is {{condition}} {{volume}}"
|
||||||
AdvSceneSwitcher.condition.region="Screen region"
|
AdvSceneSwitcher.condition.region="Screen region"
|
||||||
AdvSceneSwitcher.condition.region.entry="Cursor is in {{minX}} {{minY}} x {{maxX}} {{maxY}}"
|
AdvSceneSwitcher.condition.region.entry="Cursor is in {{minX}} {{minY}} x {{maxX}} {{maxY}}"
|
||||||
AdvSceneSwitcher.condition.scene="Scene"
|
AdvSceneSwitcher.condition.scene="Scene"
|
||||||
AdvSceneSwitcher.condition.scene.type.current="Current"
|
AdvSceneSwitcher.condition.scene.type.current="Current"
|
||||||
AdvSceneSwitcher.condition.scene.type.previous="Previous"
|
AdvSceneSwitcher.condition.scene.type.previous="Previous"
|
||||||
AdvSceneSwitcher.condition.scene.entry="{{sceneType}} scene is {{scenes}} for {{duration}}"
|
AdvSceneSwitcher.condition.scene.entry="{{sceneType}} scene is {{scenes}}"
|
||||||
AdvSceneSwitcher.condition.window="Window"
|
AdvSceneSwitcher.condition.window="Window"
|
||||||
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} exist and ..."
|
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} exist and ..."
|
||||||
AdvSceneSwitcher.condition.window.entry.line2="... is {{fullscreen}} fullscreen {{maximized}} maximized {{focused}} focused"
|
AdvSceneSwitcher.condition.window.entry.line2="... is {{fullscreen}} fullscreen {{maximized}} maximized {{focused}} focused"
|
||||||
|
|
@ -105,16 +107,16 @@ AdvSceneSwitcher.condition.video.condition.noImage="has no output"
|
||||||
AdvSceneSwitcher.condition.video.askFileAction="Do you want to use an existing file or create a screenshot of the currently selected source?"
|
AdvSceneSwitcher.condition.video.askFileAction="Do you want to use an existing file or create a screenshot of the currently selected source?"
|
||||||
AdvSceneSwitcher.condition.video.askFileAction.file="Use existing file"
|
AdvSceneSwitcher.condition.video.askFileAction.file="Use existing file"
|
||||||
AdvSceneSwitcher.condition.video.askFileAction.screenshot="Create screenshot"
|
AdvSceneSwitcher.condition.video.askFileAction.screenshot="Create screenshot"
|
||||||
AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{filePath}} {{browseButton}} for {{duration}}"
|
AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{filePath}} {{browseButton}}"
|
||||||
AdvSceneSwitcher.condition.stream="Streaming"
|
AdvSceneSwitcher.condition.stream="Streaming"
|
||||||
AdvSceneSwitcher.condition.stream.state.start="Stream running"
|
AdvSceneSwitcher.condition.stream.state.start="Stream running"
|
||||||
AdvSceneSwitcher.condition.stream.state.stop="Stream stopped"
|
AdvSceneSwitcher.condition.stream.state.stop="Stream stopped"
|
||||||
AdvSceneSwitcher.condition.stream.entry="{{streamState}} for {{duration}}"
|
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
|
||||||
AdvSceneSwitcher.condition.record="Recording"
|
AdvSceneSwitcher.condition.record="Recording"
|
||||||
AdvSceneSwitcher.condition.record.state.start="Recording running"
|
AdvSceneSwitcher.condition.record.state.start="Recording running"
|
||||||
AdvSceneSwitcher.condition.record.state.pause="Recording paused"
|
AdvSceneSwitcher.condition.record.state.pause="Recording paused"
|
||||||
AdvSceneSwitcher.condition.record.state.stop="Recording stopped"
|
AdvSceneSwitcher.condition.record.state.stop="Recording stopped"
|
||||||
AdvSceneSwitcher.condition.record.entry="{{recordState}} for {{duration}}"
|
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
|
||||||
AdvSceneSwitcher.condition.process="Process"
|
AdvSceneSwitcher.condition.process="Process"
|
||||||
AdvSceneSwitcher.condition.process.entry="{{processes}} is running {{focused}} and is focused"
|
AdvSceneSwitcher.condition.process.entry="{{processes}} is running {{focused}} and is focused"
|
||||||
AdvSceneSwitcher.condition.idle="Idle"
|
AdvSceneSwitcher.condition.idle="Idle"
|
||||||
|
|
@ -126,6 +128,24 @@ AdvSceneSwitcher.condition.virtDesktop="Virtual desktop"
|
||||||
AdvSceneSwitcher.condition.virtDesktop.notAvailable="Not availbale"
|
AdvSceneSwitcher.condition.virtDesktop.notAvailable="Not availbale"
|
||||||
AdvSceneSwitcher.condition.virtDesktop.entry.line1="Active virtual desktop is {{virtDesktops}}"
|
AdvSceneSwitcher.condition.virtDesktop.entry.line1="Active virtual desktop is {{virtDesktops}}"
|
||||||
AdvSceneSwitcher.condition.virtDesktop.entry.line2="Current: {{currentDesktop}}"
|
AdvSceneSwitcher.condition.virtDesktop.entry.line2="Current: {{currentDesktop}}"
|
||||||
|
AdvSceneSwitcher.condition.interval="Interval"
|
||||||
|
AdvSceneSwitcher.condition.interval.entry="{{duration}} have passed"
|
||||||
|
AdvSceneSwitcher.condition.counter="Count"
|
||||||
|
AdvSceneSwitcher.condition.counter.type.below="Less than"
|
||||||
|
AdvSceneSwitcher.condition.counter.type.above="More than"
|
||||||
|
AdvSceneSwitcher.condition.counter.type.equal="Exactly"
|
||||||
|
AdvSceneSwitcher.condition.counter.reset="Reset"
|
||||||
|
AdvSceneSwitcher.condition.counter.entry.line1="{{macros}} was executed {{conditions}} {{count}} times"
|
||||||
|
AdvSceneSwitcher.condition.counter.entry.line2="Current count: {{currentCount}} {{resetCount}}"
|
||||||
|
AdvSceneSwitcher.condition.source="Source"
|
||||||
|
AdvSceneSwitcher.condition.source.type.active="Is active"
|
||||||
|
AdvSceneSwitcher.condition.source.type.showing="Is showing"
|
||||||
|
AdvSceneSwitcher.condition.source.type.settings="Settings match"
|
||||||
|
AdvSceneSwitcher.condition.source.regex="Use regular expressions"
|
||||||
|
AdvSceneSwitcher.condition.source.getSettings="Get current settings"
|
||||||
|
AdvSceneSwitcher.condition.source.entry.line1="{{sources}} {{conditions}}"
|
||||||
|
AdvSceneSwitcher.condition.source.entry.line2="{{settings}}"
|
||||||
|
AdvSceneSwitcher.condition.source.entry.line3="{{regex}} {{getSettings}}"
|
||||||
|
|
||||||
; Macro Actions
|
; Macro Actions
|
||||||
AdvSceneSwitcher.action.switchScene="Switch scene"
|
AdvSceneSwitcher.action.switchScene="Switch scene"
|
||||||
|
|
@ -159,7 +179,37 @@ AdvSceneSwitcher.action.streaming.type.start="Start streaming"
|
||||||
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
|
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
|
||||||
AdvSceneSwitcher.action.run="Run"
|
AdvSceneSwitcher.action.run="Run"
|
||||||
AdvSceneSwitcher.action.run.entry="Run {{filePath}} {{browseButton}}"
|
AdvSceneSwitcher.action.run.entry="Run {{filePath}} {{browseButton}}"
|
||||||
|
AdvSceneSwitcher.action.sceneVisibility="Scene item visibility"
|
||||||
|
AdvSceneSwitcher.action.sceneVisibility.type.show="Show"
|
||||||
|
AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
|
||||||
|
AdvSceneSwitcher.action.sceneVisibility.entry="On {{scenes}} {{actions}} {{sources}}"
|
||||||
|
AdvSceneSwitcher.action.filter="Filter"
|
||||||
|
AdvSceneSwitcher.action.filter.type.enable="Enable"
|
||||||
|
AdvSceneSwitcher.action.filter.type.disable="Disable"
|
||||||
|
AdvSceneSwitcher.action.filter.entry="On {{sources}} {{actions}} {{filters}}"
|
||||||
|
AdvSceneSwitcher.action.source="Source"
|
||||||
|
AdvSceneSwitcher.action.source.type.enable="Enable"
|
||||||
|
AdvSceneSwitcher.action.source.type.disable="Disable"
|
||||||
|
AdvSceneSwitcher.action.source.type.settings="Set settings"
|
||||||
|
AdvSceneSwitcher.action.source.entry="{{actions}} {{sources}}"
|
||||||
|
AdvSceneSwitcher.action.source.warning="Warning: Enabling and disabling sources globally cannot be controlled by the OBS UI"
|
||||||
|
AdvSceneSwitcher.action.source.getSettings="Get current settings"
|
||||||
|
AdvSceneSwitcher.action.media="Media"
|
||||||
|
AdvSceneSwitcher.action.media.type.play="Play"
|
||||||
|
AdvSceneSwitcher.action.media.type.pause="Pause"
|
||||||
|
AdvSceneSwitcher.action.media.type.stop="Stop"
|
||||||
|
AdvSceneSwitcher.action.media.type.restart="Restart"
|
||||||
|
AdvSceneSwitcher.action.media.type.next="Next"
|
||||||
|
AdvSceneSwitcher.action.media.type.previous="Previous"
|
||||||
|
AdvSceneSwitcher.action.media.entry="{{actions}} {{mediaSources}}"
|
||||||
|
AdvSceneSwitcher.action.macro="Macro"
|
||||||
|
AdvSceneSwitcher.action.macro.type.pause="Pause"
|
||||||
|
AdvSceneSwitcher.action.macro.type.unpause="Unpause"
|
||||||
|
AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter"
|
||||||
|
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
|
||||||
|
AdvSceneSwitcher.action.pluginState="Plugin state"
|
||||||
|
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
|
||||||
|
AdvSceneSwitcher.action.pluginState.entry="{{actions}}"
|
||||||
|
|
||||||
; Transition Tab
|
; Transition Tab
|
||||||
AdvSceneSwitcher.transitionTab.title="Transition"
|
AdvSceneSwitcher.transitionTab.title="Transition"
|
||||||
|
|
@ -336,7 +386,9 @@ AdvSceneSwitcher.networkTab.DisabledWarning="This functionality unfortunately ha
|
||||||
AdvSceneSwitcher.networkTab.server="Start server (Sends scene switch messages to all connected clients)"
|
AdvSceneSwitcher.networkTab.server="Start server (Sends scene switch messages to all connected clients)"
|
||||||
AdvSceneSwitcher.networkTab.server.port="Port"
|
AdvSceneSwitcher.networkTab.server.port="Port"
|
||||||
AdvSceneSwitcher.networkTab.server.lockToIPv4="Lock server to only using IPv4"
|
AdvSceneSwitcher.networkTab.server.lockToIPv4="Lock server to only using IPv4"
|
||||||
|
AdvSceneSwitcher.networkTab.server.sendSceneChange="Send messages for scene changes"
|
||||||
AdvSceneSwitcher.networkTab.server.restrictSendToAutomatedSwitches="Only send messages for automated scene switches"
|
AdvSceneSwitcher.networkTab.server.restrictSendToAutomatedSwitches="Only send messages for automated scene switches"
|
||||||
|
AdvSceneSwitcher.networkTab.server.sendPreview="Send messages for preview scene change when running in Studio mode"
|
||||||
AdvSceneSwitcher.networkTab.startFailed.message="The WebSockets server failed to start, maybe because:\n - TCP port %1 may currently be in use elsewhere on this system, possibly by another application. Try setting a different TCP port in the WebSocket server settings, or stop any application that could be using this port.\n - Error message: %2"
|
AdvSceneSwitcher.networkTab.startFailed.message="The WebSockets server failed to start, maybe because:\n - TCP port %1 may currently be in use elsewhere on this system, possibly by another application. Try setting a different TCP port in the WebSocket server settings, or stop any application that could be using this port.\n - Error message: %2"
|
||||||
AdvSceneSwitcher.networkTab.server.status.currentStatus="Current status"
|
AdvSceneSwitcher.networkTab.server.status.currentStatus="Current status"
|
||||||
AdvSceneSwitcher.networkTab.server.status.notRunning="Not running"
|
AdvSceneSwitcher.networkTab.server.status.notRunning="Not running"
|
||||||
|
|
@ -398,6 +450,8 @@ AdvSceneSwitcher.sceneTriggerTab.help="This tab allows you to trigger actions on
|
||||||
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher"
|
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher"
|
||||||
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="Stop the Advanced Scene Switcher"
|
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="Stop the Advanced Scene Switcher"
|
||||||
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Toggle Start/Stop for the Advanced Scene Switcher"
|
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Toggle Start/Stop for the Advanced Scene Switcher"
|
||||||
|
AdvSceneSwitcher.hotkey.macro.pause="Pause macro %1"
|
||||||
|
AdvSceneSwitcher.hotkey.macro.unpause="Unpause macro %1"
|
||||||
|
|
||||||
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?"
|
||||||
|
|
||||||
|
|
@ -409,10 +463,14 @@ AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
||||||
AdvSceneSwitcher.currentTransition="Current Transition"
|
AdvSceneSwitcher.currentTransition="Current Transition"
|
||||||
AdvSceneSwitcher.selectTransition="--select transition--"
|
AdvSceneSwitcher.selectTransition="--select transition--"
|
||||||
AdvSceneSwitcher.selectWindow="--select window--"
|
AdvSceneSwitcher.selectWindow="--select window--"
|
||||||
|
AdvSceneSwitcher.selectSource="--select source--"
|
||||||
AdvSceneSwitcher.selectAudioSource="--select audio source--"
|
AdvSceneSwitcher.selectAudioSource="--select audio source--"
|
||||||
AdvSceneSwitcher.selectVideoSource="--select video source--"
|
AdvSceneSwitcher.selectVideoSource="--select video source--"
|
||||||
AdvSceneSwitcher.selectMediaSource="--select media source--"
|
AdvSceneSwitcher.selectMediaSource="--select media source--"
|
||||||
AdvSceneSwitcher.selectProcess="--select process--"
|
AdvSceneSwitcher.selectProcess="--select process--"
|
||||||
|
AdvSceneSwitcher.selectFilter="--select filter--"
|
||||||
|
AdvSceneSwitcher.selectMacro="--select macro--"
|
||||||
|
AdvSceneSwitcher.selectItem="--select item--"
|
||||||
AdvSceneSwitcher.enterPath="--enter path--"
|
AdvSceneSwitcher.enterPath="--enter path--"
|
||||||
AdvSceneSwitcher.enterText="--enter text--"
|
AdvSceneSwitcher.enterText="--enter text--"
|
||||||
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved"
|
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved"
|
||||||
|
|
@ -425,3 +483,7 @@ AdvSceneSwitcher.unit.milliseconds="milliseconds"
|
||||||
AdvSceneSwitcher.unit.secends="seconds"
|
AdvSceneSwitcher.unit.secends="seconds"
|
||||||
AdvSceneSwitcher.unit.minutes="minutes"
|
AdvSceneSwitcher.unit.minutes="minutes"
|
||||||
AdvSceneSwitcher.unit.hours="hours"
|
AdvSceneSwitcher.unit.hours="hours"
|
||||||
|
AdvSceneSwitcher.duration.condition.none="No time constraint"
|
||||||
|
AdvSceneSwitcher.duration.condition.more="For at least"
|
||||||
|
AdvSceneSwitcher.duration.condition.equal="For exactly"
|
||||||
|
AdvSceneSwitcher.duration.condition.less="For at most"
|
||||||
|
|
|
||||||
423
data/locale/ru-RU.ini
Normal file
423
data/locale/ru-RU.ini
Normal file
|
|
@ -0,0 +1,423 @@
|
||||||
|
AdvSceneSwitcher.pluginName="Advanced Scene Switcher"
|
||||||
|
AdvSceneSwitcher.windowTitle="Advanced Scene Switcher"
|
||||||
|
|
||||||
|
; General Tab
|
||||||
|
AdvSceneSwitcher.generalTab.title="Общие"
|
||||||
|
AdvSceneSwitcher.generalTab.status="Статус"
|
||||||
|
AdvSceneSwitcher.generalTab.status.hotkeytips="Горячие клавиши можно определить в настройках OBS"
|
||||||
|
AdvSceneSwitcher.generalTab.status.currentStatus="Advanced Scene Switcher сейчас:"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup="При запуске OBS:"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="Запустить переключатель сцен, если он был запущен"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Всегда запускать переключатель сцен"
|
||||||
|
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Не запускать переключатель сцен"
|
||||||
|
AdvSceneSwitcher.generalTab.status.start="Старт"
|
||||||
|
AdvSceneSwitcher.generalTab.status.stop="Стоп"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart="Автоматически запускать переключатель сцен, когда:"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.never="Никогда"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.recording="Запись"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.streaming="Вещание"
|
||||||
|
AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming="Запись или потоковое вещание"
|
||||||
|
AdvSceneSwitcher.generalTab.status.checkInterval="Проверять условия переключения каждый раз"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior="Общее поведение"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="Если не выполняется условие переключения для"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="Будет только настолько точным, насколько настроен интервал проверки."
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="Не переключаться"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="Переключиться на любую сцену на вкладке Random"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="Переключиться на:"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="После совпадения не переключаться между сценами в течение"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="В течение этого времени потенциальные совпадения будут игнорироваться!"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Включить ведение подробного журнала"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Сохранять положение и размер окна"
|
||||||
|
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Отключить подсказки пользовательского интерфейса"
|
||||||
|
AdvSceneSwitcher.generalTab.priority="Приоритет"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.description="Приоритет методов переключения (самый высокий приоритет - вверху)"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.threadPriority="Использовать приоритет потока"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.threadPriorityNotice="(Поднимать приоритет выше \"Нормальный\" не рекомендуется)"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings="Сохранить / загрузить настройки"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Экспорт"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Импорт"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Экспортировать настройки расширенного переключателя сцен в файл ..."
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Импортировать настройки Advanced Scene Switcher из файла ..."
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Текстовые файлы (*.txt)"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Advanced Scene Switcher не удалось импортировать настройки"
|
||||||
|
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Настройки Advanced Scene Switcher импортированы успешно"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.fileContent="Содержание файла"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.sceneSequence="Последовательность сцены"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.idleDetection="Обнаружение простоя"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.executable="Исполняемый файл"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.screenRegion="Область экрана"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.windowTitle="Заголовок окна"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.media="Медиа"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.time="Время"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.audio="Аудио"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.video="Видео"
|
||||||
|
AdvSceneSwitcher.generalTab.priority.macro="Макрос"
|
||||||
|
|
||||||
|
; Macro Tab
|
||||||
|
AdvSceneSwitcher.macroTab.title="Макрос"
|
||||||
|
AdvSceneSwitcher.macroTab.macros="Макросы"
|
||||||
|
AdvSceneSwitcher.macroTab.help="Макросы позволяют выполнять ряд действий в зависимости от нескольких условий.\n\nНажмите на выделенный символ плюса, чтобы добавить новый макрос."
|
||||||
|
AdvSceneSwitcher.macroTab.editConditionHelp="Этот раздел позволяет определить условия макроса.\n\nВыберите существующий или добавьте новый макрос слева."
|
||||||
|
AdvSceneSwitcher.macroTab.editActionHelp="Этот раздел позволяет определить действия макроса.\n\n\nВыберите существующий или добавьте новый макрос слева."
|
||||||
|
AdvSceneSwitcher.macroTab.edit="Редактировать макрос"
|
||||||
|
AdvSceneSwitcher.macroTab.edit.logic="Тип логики:"
|
||||||
|
AdvSceneSwitcher.macroTab.edit.condition="Тип условия:"
|
||||||
|
AdvSceneSwitcher.macroTab.edit.action="Тип действия:"
|
||||||
|
AdvSceneSwitcher.macroTab.add="Добавить новый макрос"
|
||||||
|
AdvSceneSwitcher.macroTab.name="Имя:"
|
||||||
|
AdvSceneSwitcher.macroTab.defaultname="Макрос %1"
|
||||||
|
AdvSceneSwitcher.macroTab.exists="Имя макроса уже существует"
|
||||||
|
AdvSceneSwitcher.macroTab.copy="Создать копию"
|
||||||
|
; Macro Logic
|
||||||
|
AdvSceneSwitcher.logic.none="Игнорировать вход"
|
||||||
|
AdvSceneSwitcher.logic.and="И"
|
||||||
|
AdvSceneSwitcher.logic.or="Или"
|
||||||
|
AdvSceneSwitcher.logic.andNot="И не"
|
||||||
|
AdvSceneSwitcher.logic.orNot="Или нет"
|
||||||
|
AdvSceneSwitcher.logic.rootNone="Если"
|
||||||
|
AdvSceneSwitcher.logic.not="Если нет"
|
||||||
|
; Macro Conditions
|
||||||
|
AdvSceneSwitcher.condition.audio="Аудио"
|
||||||
|
AdvSceneSwitcher.ondition.audio.state.below="Ниже"
|
||||||
|
AdvSceneSwitcher.ondition.audio.state.above="Выше"
|
||||||
|
AdvSceneSwitcher.condition.audio.entry="Громкость {{audioSources}} равна {{condition}} {{volume}} в течении {{duration}} секунд"
|
||||||
|
AdvSceneSwitcher.condition.region="Область экрана"
|
||||||
|
AdvSceneSwitcher.condition.region.entry="Курсор находится в {{minX}} {{minY}} x {{maxX}} {{maxY}}"
|
||||||
|
AdvSceneSwitcher.condition.scene="Сцена"
|
||||||
|
AdvSceneSwitcher.condition.scene.type.current="Текущий"
|
||||||
|
AdvSceneSwitcher.condition.scene.type.previous="Предыдущий"
|
||||||
|
AdvSceneSwitcher.condition.scene.entry="{{sceneType}} сцена является {{scenes}} на {{duration}}"
|
||||||
|
AdvSceneSwitcher.condition.window="Окно"
|
||||||
|
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} существует и ..."
|
||||||
|
AdvSceneSwitcher.condition.window.entry.line2="... это {{fullscreen}} полноэкранный {{maximized}} максимизированный {{focused}} сфокусированный"
|
||||||
|
AdvSceneSwitcher.condition.file="Файл"
|
||||||
|
AdvSceneSwitcher.condition.file.entry.line1="Содержимое {{fileType}} {{filePath}} {{browseButton}} соответствует:"
|
||||||
|
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
|
||||||
|
AdvSceneSwitcher.condition.file.entry.line3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
|
||||||
|
AdvSceneSwitcher.condition.media="Медиа"
|
||||||
|
AdvSceneSwitcher.condition.media.entry="{{mediaSources}} состояние {{states}} и {{timeRestrictions}} {{time}}"
|
||||||
|
AdvSceneSwitcher.condition.video="Видео"
|
||||||
|
AdvSceneSwitcher.condition.video.condition.match="точно соответствует"
|
||||||
|
AdvSceneSwitcher.condition.video.condition.differ="не совпадает"
|
||||||
|
AdvSceneSwitcher.condition.video.condition.hasChanged="изменилось"
|
||||||
|
AdvSceneSwitcher.condition.video.condition.hasNotChanged="не изменилось"
|
||||||
|
AdvSceneSwitcher.condition.video.condition.noImage="не имеет вывода"
|
||||||
|
AdvSceneSwitcher.condition.video.askFileAction="Вы хотите использовать существующий файл или создать скриншот текущего выбранного источника?"
|
||||||
|
AdvSceneSwitcher.condition.video.askFileAction.file="Использовать существующий файл"
|
||||||
|
AdvSceneSwitcher.condition.video.askFileAction.screenshot="Создать скриншот"
|
||||||
|
AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{filePath}} {{browseButton}} для {{duration}}"
|
||||||
|
AdvSceneSwitcher.condition.stream="Потоковое вещание"
|
||||||
|
AdvSceneSwitcher.condition.stream.state.start="Поток запущен"
|
||||||
|
AdvSceneSwitcher.condition.stream.state.stop="Поток остановлен"
|
||||||
|
AdvSceneSwitcher.condition.stream.entry="{{streamState}} для {{duration}}"
|
||||||
|
AdvSceneSwitcher.condition.record="Запись"
|
||||||
|
AdvSceneSwitcher.condition.record.state.start="Запись запущена"
|
||||||
|
AdvSceneSwitcher.condition.record.state.pause="Запись приостановлена"
|
||||||
|
AdvSceneSwitcher.condition.record.state.stop="Запись остановлена"
|
||||||
|
AdvSceneSwitcher.condition.record.entry="{{recordState}} для {{duration}}"
|
||||||
|
AdvSceneSwitcher.condition.process="Процесс"
|
||||||
|
AdvSceneSwitcher.condition.process.entry="{{processes}} запущен {{focused}} и сфокусирован"
|
||||||
|
AdvSceneSwitcher.condition.idle="Простой"
|
||||||
|
AdvSceneSwitcher.condition.idle.entry="Не было ни клавиатуры, ни мыши в течении{{duration}}"
|
||||||
|
AdvSceneSwitcher.condition.pluginState="Состояние плагина"
|
||||||
|
AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="Автоматическая смена сцены была запущена в этом интервале"
|
||||||
|
AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
|
||||||
|
|
||||||
|
; Macro Actions
|
||||||
|
AdvSceneSwitcher.action.switchScene="Переключить сцену"
|
||||||
|
AdvSceneSwitcher.action.scene.entry="Перейти к сцене {{scenes}} используя {{transitions}} с продолжительностью {{duration}} секунд"
|
||||||
|
AdvSceneSwitcher.action.wait="Подождать"
|
||||||
|
AdvSceneSwitcher.action.wait.type.fixed="фиксированный"
|
||||||
|
AdvSceneSwitcher.action.wait.type.random="случайный"
|
||||||
|
AdvSceneSwitcher.action.wait.entry.fixed="Ожидать {{waitType}} в течении {{duration}}"
|
||||||
|
AdvSceneSwitcher.action.wait.entry.random="Ожидание {{waitType}} длительностью от {{duration}} до {{duration2}}"
|
||||||
|
AdvSceneSwitcher.action.audio="Аудио"
|
||||||
|
AdvSceneSwitcher.action.audio.type.mute="Замьютить"
|
||||||
|
AdvSceneSwitcher.action.audio.type.unmute="Размьютить"
|
||||||
|
AdvSceneSwitcher.action.audio.type.sourceVolume="Установить громкость источника"
|
||||||
|
AdvSceneSwitcher.action.audio.type.masterVolume="Установить главную громкость"
|
||||||
|
AdvSceneSwitcher.action.audio.entry="{{actions}} {{audioSources}} {{volume}}"
|
||||||
|
AdvSceneSwitcher.action.recording="Запись"
|
||||||
|
AdvSceneSwitcher.action.recording.type.stop="Остановить запись"
|
||||||
|
AdvSceneSwitcher.action.recording.type.start="Начать запись"
|
||||||
|
AdvSceneSwitcher.action.recording.type.pause="Пауза записи"
|
||||||
|
AdvSceneSwitcher.action.recording.type.unpause="Снять запись с паузы"
|
||||||
|
AdvSceneSwitcher.action.recording.pause.hint="Обратите внимание, что в зависимости от настроек записи вы можете не иметь возможности приостановить запись"
|
||||||
|
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}"
|
||||||
|
AdvSceneSwitcher.action.replay="Буфер воспроизведения"
|
||||||
|
AdvSceneSwitcher.action.replay.type.stop="Остановить буфер воспроизведения"
|
||||||
|
AdvSceneSwitcher.action.replay.type.start="Начать воспроизведение буфера"
|
||||||
|
AdvSceneSwitcher.action.replay.type.save="Сохранить буфер воспроизведения"
|
||||||
|
AdvSceneSwitcher.action.replay.entry="{{actions}}"
|
||||||
|
AdvSceneSwitcher.action.streaming="Потоковое вещание"
|
||||||
|
AdvSceneSwitcher.action.streaming.type.stop="Остановить потоковое вещание"
|
||||||
|
AdvSceneSwitcher.action.streaming.type.start="Начать потоковое вещание"
|
||||||
|
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
|
||||||
|
AdvSceneSwitcher.action.run="Запустить"
|
||||||
|
AdvSceneSwitcher.action.run.entry="Запустить {{filePath}} {{browseButton}}"
|
||||||
|
|
||||||
|
|
||||||
|
; Transition Tab
|
||||||
|
AdvSceneSwitcher.transitionTab.title="Переход"
|
||||||
|
AdvSceneSwitcher.transitionTab.setTransitionBy="При изменении переходов:"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionOverride="Установить переопределение переходов"
|
||||||
|
AdvSceneSwitcher.transitionTab.adjustActiveTransitionType="Изменить тип активного перехода"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionBehaviorSelectionError="Должна быть включена хотя бы одна опция:\n\n - Использовать переопределения переходов\n\n - Изменить тип активного перехода"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionForAToB="Использовать переход для автоматического переключения сцены со сцены A на сцену B"
|
||||||
|
AdvSceneSwitcher.transitionTab.transitionsHelp="<html><head/><body><p>Эти настройки <span style=\"font-style:italic;\">только</span> влияют на переходы, вызванные переключателем сцен - Проверьте <a href=\"https://obsproject.com/forum/resources/transition-table.1174/\"><span style=\" text-decoration: underline; color:#268bd2;\">Transition Table</span></a> если вы хотите настроить его для ручного изменения сцены.<br/>Настройки, определенные здесь, имеют приоритет над настройками перехода, сконфигурированными в других местах переключателя сцен.<br/><br/>Нажмите на символ плюса ниже, чтобы добавить новую запись.</p></body></html>"
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransition="Изменить переход, если сцена активна"
|
||||||
|
AdvSceneSwitcher.transitionTab.entry="Переход от {{scenes}} к {{scenes2}} с помощью {{transitions}} с длительностью {{duration}}"
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransitionEntry="Когда сцена {{scenes}} активна, изменить переход сцены по умолчанию на {{transitions}}"
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransitionsHelp="Нажмите на символ плюса, чтобы добавить запись."
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransition.delay="Переключить переход {{defTransitionDelay}} после смены сцены."
|
||||||
|
AdvSceneSwitcher.transitionTab.defaultTransition.delay.help="Задержка используется для того, чтобы избежать отмены переключения сцены, что может произойти, если тип перехода будет изменен, когда переход еще продолжается."
|
||||||
|
|
||||||
|
; Pause Scenes Tab
|
||||||
|
AdvSceneSwitcher.pauseTab.title="Пауза"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseOnScene="Приостановить Scene Switcher на сцене"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseInFocus1="Приостановить Scene Switcher когда "
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseInFocus2="находится в фокусе"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseTypeScene="сцена активна"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseTypeWindow="окно в фокусе"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseTargetAll="все"
|
||||||
|
AdvSceneSwitcher.pauseTab.pauseEntry="Пауза {{pauseTargets}} проверяет, когда {{pauseTypes}} {{scenes}} {{windows}}"
|
||||||
|
AdvSceneSwitcher.pauseTab.help="На этой вкладке вы можете настроить приостановку отдельных методов переключения, если сцена активна или окно находится в фокусе.\n\nНажмите на выделенный символ плюса, чтобы продолжить."
|
||||||
|
|
||||||
|
; Window Title Tab
|
||||||
|
AdvSceneSwitcher.windowTitleTab.title="Название"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.regexrDescription="<html><head/><body><p>Введите либо прямые заголовки окон, либо правильное регулярное выражение. Вы можете проверить синтаксис и соответствие регулярных выражений, используя <a href=\"https://regexr.com\"><span style=\" text-decoration: underline; color:#268bd2;\">RegExr</span></a></p></body></html>"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.stayInFocus1="Игнорировать имя этого окна"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.stayInFocus2=" "
|
||||||
|
AdvSceneSwitcher.windowTitleTab.fullscreen="if fullscreen"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.maximized="if maximized"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.focused="if focused"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.entry="{{windows}} {{scenes}} {{transitions}} {{fullscreen}} {{maximized}} {{focused}}"
|
||||||
|
AdvSceneSwitcher.windowTitleTab.windowsHelp="Переключение сцен на основе заголовков окон запущенных приложений.\nВы можете выбрать следующие дополнительные условия:\nОкно полноэкранное\nОкно максимизированное\nОкно сфокусированное\n\nНажмите на выделенный символ плюса, чтобы продолжить."
|
||||||
|
AdvSceneSwitcher.windowTitleTab.ignoreWindowsHelp="Если заголовок окна игнорируется, переключатель сцен будет действовать так, как будто ранее выбранное окно все еще в фокусе.\nЭто позволит вам избежать переключения сцен, если вы часто переключаетесь на другое окно, которое не должно вызывать смену сцены.\n\nВыберите окно или введите заголовок окна выше и нажмите на символ плюса ниже, чтобы добавить его в список."
|
||||||
|
|
||||||
|
; Executable Tab
|
||||||
|
AdvSceneSwitcher.executableTab.title="Исполняемый"
|
||||||
|
AdvSceneSwitcher.executableTab.implemented="Implemented by dasOven"
|
||||||
|
AdvSceneSwitcher.executableTab.requiresFocus="только если сфокусирован"
|
||||||
|
AdvSceneSwitcher.executableTab.entry="Когда {{processes}} запущены, переключить на {{scenes}} используя {{transitions}} {{requiresFocus}}"
|
||||||
|
AdvSceneSwitcher.executableTab.help="Эта вкладка позволит вам автоматически переключаться между сценами, если запущен процесс.\nЭто может быть полезно в ситуациях, когда имя окна может измениться или неизвестно.\n\nНажмите на выделенный символ плюса, чтобы продолжить."
|
||||||
|
|
||||||
|
; Screen Region Tab
|
||||||
|
AdvSceneSwitcher.screenRegionTab.title="Регион"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.currentPosition="Курсор в данный момент находится в:"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.showGuideFrames="Показать направляющие кадры"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.hideGuideFrames="Скрыть направляющие рамки"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.excludeScenes.None="Нет выбора"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.entry="Если курсор находится в {{minX}} {{minY}} x {{maxX}} {{maxY}} переключить на {{scenes}} используя {{transitions}} если не указано {{excludeScenes}}"
|
||||||
|
AdvSceneSwitcher.screenRegionTab.help="Эта вкладка позволит вам автоматически переключать сцены, основываясь на текущем положении курсора мыши.\n\nНажмите на выделенный символ плюса, чтобы продолжить."
|
||||||
|
|
||||||
|
; Media Tab
|
||||||
|
AdvSceneSwitcher.mediaTab.title="Медиа"
|
||||||
|
AdvSceneSwitcher.mediaTab.implemented="Implemented by Exeldro"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.none="Нет"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.playing="Играет"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.opening="Открытие"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.buffering="Буферизация"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.Paused="Приостановлено"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.stopped="Остановлено"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.ended="Закончилось"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.error="Ошибка"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.playedToEnd="Воспроизведено до конца"
|
||||||
|
AdvSceneSwitcher.mediaTab.states.any="Любой"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.none="Нет"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.shorter="Время короче"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.longer="Время больше"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter="Оставшееся время короче"
|
||||||
|
AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger="Время, оставшееся дольше"
|
||||||
|
AdvSceneSwitcher.mediaTab.entry="Когда состояние {{mediaSources}} равно {{states}} и {{timeRestrictions}} {{time}} переключиться на {{scenes}} используя {{transitions}}"
|
||||||
|
AdvSceneSwitcher.mediaTab.help="Эта вкладка позволит вам переключать сцены на основе состояний медиаисточников.\nНапример, вы можете автоматически переключиться на предыдущую сцену, когда выбранный медиаисточник закончил свое воспроизведение.\n\nНажмите на выделенный символ плюса, чтобы продолжить."
|
||||||
|
|
||||||
|
; File Tab
|
||||||
|
AdvSceneSwitcher.fileTab.title="Файл"
|
||||||
|
AdvSceneSwitcher.fileTab.readWriteSceneFile="Считать / записать сцену из / в файл"
|
||||||
|
AdvSceneSwitcher.fileTab.currentSceneOutputFile="Записать имя текущей сцены в этот файл:"
|
||||||
|
AdvSceneSwitcher.fileTab.switchSceneBaseOnFile="Включить переключение сцен на основе ввода файла"
|
||||||
|
AdvSceneSwitcher.fileTab.switchSceneNameInputFile="Считать имя сцены, на которую нужно переключиться, из этого файла:"
|
||||||
|
AdvSceneSwitcher.fileTab.switchSceneBaseOnFileContent="Переключать сцену на основе содержимого файла"
|
||||||
|
AdvSceneSwitcher.fileTab.remoteFileWarning="Обратите внимание, что при выборе опции remote переключатель сцен будет пытаться получить доступ к удаленному местоположению каждые x мс, как указано на вкладке Общие"
|
||||||
|
AdvSceneSwitcher.fileTab.remoteFileWarning1="Обратите внимание, что переключатель сцены будет пытаться получить доступ к удаленному местоположению каждые "
|
||||||
|
AdvSceneSwitcher.fileTab.remoteFileWarning2="ms"
|
||||||
|
AdvSceneSwitcher.fileTab.libcurlWarning="Не удалось загрузить libcurl! Доступ к удаленным файлам невозможен!"
|
||||||
|
AdvSceneSwitcher.fileTab.selectWrite="Выберите файл для записи в ..."
|
||||||
|
AdvSceneSwitcher.fileTab.selectRead="Выберите файл для чтения из ..."
|
||||||
|
AdvSceneSwitcher.fileTab.textFileType="Текстовые файлы (*.txt)"
|
||||||
|
AdvSceneSwitcher.fileTab.anyFileType="Любые файлы (*.*)"
|
||||||
|
AdvSceneSwitcher.fileTab.remote="удаленный файл"
|
||||||
|
AdvSceneSwitcher.fileTab.local="локальный файл"
|
||||||
|
AdvSceneSwitcher.fileTab.useRegExp="использовать регулярные выражения (сопоставление шаблонов)"
|
||||||
|
AdvSceneSwitcher.fileTab.checkfileContentTime="если дата модификации изменена"
|
||||||
|
AdvSceneSwitcher.fileTab.checkfileContent="если содержимое изменено"
|
||||||
|
AdvSceneSwitcher.fileTab.entry="Переключиться на {{scenes}} используя {{transitions}} если содержимое {{fileType}} {{filePath}} {{browseButton}} совпадает:"
|
||||||
|
AdvSceneSwitcher.fileTab.entry2="{{matchText}}"
|
||||||
|
AdvSceneSwitcher.fileTab.entry3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
|
||||||
|
AdvSceneSwitcher.fileTab.help="Эта вкладка позволит вам автоматически переключать сцены на основе содержимого удаленных или локальных файлов.\n\nНажмите на выделенный символ плюса, чтобы продолжить."
|
||||||
|
|
||||||
|
; Random Tab
|
||||||
|
AdvSceneSwitcher.randomTab.title="Рандом"
|
||||||
|
AdvSceneSwitcher.randomTab.randomDisabledWarning="Функциональность отключена - для активации выберите \"Если условие переключения не выполнено, переключиться на любую сцену на вкладке Random\" на вкладке Общие"
|
||||||
|
AdvSceneSwitcher.randomTab.entry="Если условие переключения не выполнено, переключиться на {{scenes}} используя {{transitions}} для {{delay}}"
|
||||||
|
AdvSceneSwitcher.randomTab.help="Переключатель сцен будет случайным образом выбирать запись на этой вкладке для переключения на заданное время.\nЗаметьте, что одна и та же запись не будет выбрана дважды подряд.\n\nНажмите на выделенный символ плюса, чтобы продолжить."
|
||||||
|
|
||||||
|
; Time Tab
|
||||||
|
AdvSceneSwitcher.timeTab.title="Время"
|
||||||
|
AdvSceneSwitcher.timeTab.anyDay="В любой день"
|
||||||
|
AdvSceneSwitcher.timeTab.mondays="По понедельникам"
|
||||||
|
AdvSceneSwitcher.timeTab.tuesdays="По вторникам"
|
||||||
|
AdvSceneSwitcher.timeTab.wednesdays="По средам"
|
||||||
|
AdvSceneSwitcher.timeTab.thursdays="По четвергам"
|
||||||
|
AdvSceneSwitcher.timeTab.fridays="По пятницам"
|
||||||
|
AdvSceneSwitcher.timeTab.saturdays="По субботам"
|
||||||
|
AdvSceneSwitcher.timeTab.sundays="По воскресеньям"
|
||||||
|
AdvSceneSwitcher.timeTab.afterstart="После начала потокового вещания/записи"
|
||||||
|
AdvSceneSwitcher.timeTab.afterstart.tip="Будет использоваться время относительно начала потокового вещания/записи"
|
||||||
|
AdvSceneSwitcher.timeTab.entry="{{triggers}} в {{time}} переключаются на {{scenes}} используя {{transitions}}"
|
||||||
|
AdvSceneSwitcher.timeTab.help="Эта вкладка позволит вам автоматически переключаться на другую сцену на основе текущего местного времени.\n\nЗаметьте, что переключатель сцен будет переключаться только в точное время, которое вы указали.\nУбедитесь, что вы настроили параметры приоритета на вкладке Общие по своему вкусу, чтобы выбранная временная точка не была пропущена из-за других методов переключения, имеющих более высокий приоритет.\n\nНажмите на выделенный символ плюса, чтобы продолжить."
|
||||||
|
|
||||||
|
; Idle Tab
|
||||||
|
AdvSceneSwitcher.idleTab.title="Бездействие"
|
||||||
|
AdvSceneSwitcher.idleTab.enable="Включить обнаружение простоя"
|
||||||
|
AdvSceneSwitcher.idleTab.idleswitch="После {{duration}} отсутствия ввода с клавиатуры или мыши переключиться на сцену {{scenes}} используя {{transitions}}"
|
||||||
|
AdvSceneSwitcher.idleTab.dontSwitchIfFocus1="Не переключаться, если"
|
||||||
|
AdvSceneSwitcher.idleTab.dontSwitchIfFocus2="находится в фокусе"
|
||||||
|
|
||||||
|
; Scene Sequence Tab
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.title="Последовательность"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.description="Последовательность автоматического переключения сцен может быть отменена либо паузой/остановкой переключателя сцен, либо ручным переключением на другую сцену"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.save="Сохранить последовательность сцен в файл"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.load="Загрузить последовательности сцен из файла"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.saveTitle="Сохранить последовательность сцен в файл ..."
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.loadTitle="Выберите файл для чтения последовательности сцен из файла ..."
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.loadFail="Advanced Scene Switcher не удалось импортировать настройки!"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="Настройки Advanced Scene Switcher импортированы успешно!"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.fileType="Текстовые файлы (*.txt)"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.interruptible="прервать"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="Другие методы переключения разрешены для прерывания этой последовательности сцен"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.entry="Когда {{startScenes}} активен, переключить на {{scenes}} после {{delay}} используя {{transitions}} {{interruptible}}"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.extendEdit="Расширить последовательность"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.extendEntry="После {{delay}} переключиться на {{scenes}} используя {{transitions}}"
|
||||||
|
AdvSceneSwitcher.sceneSequenceTab.help="Эта вкладка позволит вам автоматически переключаться на другую сцену, если сцена была активна в течение заданного периода времени.\nНапример, вы можете автоматически переключаться между двумя сценами.\n\nНажмите на выделенный символ плюса, чтобы продолжить."
|
||||||
|
|
||||||
|
; Audio Tab
|
||||||
|
AdvSceneSwitcher.audioTab.title="Аудио"
|
||||||
|
AdvSceneSwitcher.audioTab.condition.above="выше"
|
||||||
|
AdvSceneSwitcher.audioTab.condition.below="ниже"
|
||||||
|
AdvSceneSwitcher.audioTab.ignoreInactiveSource="если источник неактивен"
|
||||||
|
AdvSceneSwitcher.audioTab.entry="Когда громкость {{audioSources}} равна {{condition}} {{volumeWidget}} в течение {{duration}} секунд переключить на {{scenes}} используя {{transitions}} {{ignoreInactiveSource}}"
|
||||||
|
AdvSceneSwitcher.audioTab.multiMatchfallbackCondition="Если несколько записей совпадают ..."
|
||||||
|
AdvSceneSwitcher.audioTab.multiMatchfallback="... в течение {{duration}} секунд переключить на {{scenes}} используя {{transitions}}"
|
||||||
|
AdvSceneSwitcher.audioTab.help="Эта вкладка позволит вам переключать сцены в зависимости от громкости источников.\nНапример, вы можете автоматически переключиться на другую сцену, если громкость вашего микрофона достигнет определенного порога.\n\nНажмите на выделенный символ плюса, чтобы продолжить."
|
||||||
|
|
||||||
|
; Video Tab
|
||||||
|
AdvSceneSwitcher.videoTab.title="Видео"
|
||||||
|
AdvSceneSwitcher.videoTab.getScreenshot="Получить снимок экрана для выбранной записи"
|
||||||
|
AdvSceneSwitcher.videoTab.getScreenshotHelp="Получить скриншот источника видео текущей выбранной записи и автоматически установить его в качестве целевого изображени"
|
||||||
|
AdvSceneSwitcher.videoTab.condition.match="точно соответствует"
|
||||||
|
AdvSceneSwitcher.videoTab.condition.match.tooltip="Точное совпадение требует, чтобы целевое и исходное изображение имели одинаковое разрешение.\nДаже каждый пиксель должен совпадать, поэтому не рекомендуется использовать форматы изображений, которые используют сжатие (например, .JPG)!"
|
||||||
|
AdvSceneSwitcher.videoTab.condition.differ="не совпадает"
|
||||||
|
AdvSceneSwitcher.videoTab.condition.hasNotChanged="не изменилось"
|
||||||
|
AdvSceneSwitcher.videoTab.condition.hasChanged="изменилось"
|
||||||
|
AdvSceneSwitcher.videoTab.ignoreInactiveSource="если источник неактивен"
|
||||||
|
AdvSceneSwitcher.videoTab.entry="Когда {{videoSources}} {{condition}} {{filePath}} {{browseButton}} для {{duration}} переключиться на {{scenes}} используя {{transitions}} {{ignoreInactiveSource}}"
|
||||||
|
AdvSceneSwitcher.videoTab.help="<html><head/><body><p>Эта вкладка позволит вам переключать сцены на основе текущего видеовыхода выбранных источников.<br/>Обязательно проверьте <a href=\"https://obsproject.com/forum/resources/pixel-match-switcher.1202/\"><span style=\" text-decoration: underline; color:#268bd2;\">Pixel Match Switcher</span></a> для еще лучшей реализации этой функциональности.<br/><br/> Нажмите на выделенный символ плюса, чтобы продолжить.</p></body></html>"
|
||||||
|
|
||||||
|
; Network Tab
|
||||||
|
AdvSceneSwitcher.networkTab.title="Сеть"
|
||||||
|
AdvSceneSwitcher.networkTab.warning="Запуск сервера вне локальной сети позволит третьим лицам читать активную сцену."
|
||||||
|
AdvSceneSwitcher.networkTab.DisabledWarning="ту функциональность, к сожалению, пришлось отключить на macOS из-за несовместимости библиотек при параллельном запуске плагина obs-websocket."
|
||||||
|
AdvSceneSwitcher.networkTab.server="Запустить сервер (отправляет сообщения о переключении сцены всем подключенным клиентам)"
|
||||||
|
AdvSceneSwitcher.networkTab.server.port="Порт"
|
||||||
|
AdvSceneSwitcher.networkTab.server.lockToIPv4="Заблокировать сервер на использование только IPv4"
|
||||||
|
AdvSceneSwitcher.networkTab.server.restrictSendToAutomatedSwitches="Отправлять сообщения только для автоматических переключателей сцен"
|
||||||
|
AdvSceneSwitcher.networkTab.startFailed.message="Сервер WebSockets не удалось запустить, возможно потому, что:\n - TCP порт %1 может в настоящее время использоваться в другом месте в этой системе, возможно, другим приложением. Попробуйте установить другой TCP порт в настройках сервера WebSocket, или остановите любое приложение, которое может использовать этот порт.\n - Сообщение об ошибке: %2"
|
||||||
|
AdvSceneSwitcher.networkTab.server.status.currentStatus="Текущий статус"
|
||||||
|
AdvSceneSwitcher.networkTab.server.status.notRunning="Не запущен"
|
||||||
|
AdvSceneSwitcher.networkTab.server.status.starting="Запуск"
|
||||||
|
AdvSceneSwitcher.networkTab.server.status.running="Работает"
|
||||||
|
AdvSceneSwitcher.networkTab.server.restart="Перезапустить сервер"
|
||||||
|
AdvSceneSwitcher.networkTab.client="Запустить клиент (Получает сообщения о переключении сцен)"
|
||||||
|
AdvSceneSwitcher.networkTab.client.address="Имя хоста или IP-адрес"
|
||||||
|
AdvSceneSwitcher.networkTab.client.port="Порт"
|
||||||
|
AdvSceneSwitcher.networkTab.client.status.currentStatus="Текущий статус"
|
||||||
|
AdvSceneSwitcher.networkTab.client.status.disconnected="Отключено"
|
||||||
|
AdvSceneSwitcher.networkTab.client.status.connecting="Подключение"
|
||||||
|
AdvSceneSwitcher.networkTab.client.status.connected="Подключено"
|
||||||
|
AdvSceneSwitcher.networkTab.client.reconnect="Принудительное переподключение"
|
||||||
|
|
||||||
|
; Scene Group Tab
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.title="Группа сцен"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.list="Группы сцен"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit="Редактировать группы сцен"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.name="Имя:"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.type="Тип: {{type}}"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.type.count="Количество"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.type.time="Время"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.type.random="Случайно"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.count="Переход к следующей сцене в списке после {{count}} совпадений"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.time="Переход к следующей сцене в списке по истечении {{time}}"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.random="Выбирать следующую сцену в списке случайным образом"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.repeat="Начинать с начала, если достигнут конец списка сцен"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.edit.addScene="Добавить сцену"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.add="Добавить группу сцен"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.defaultname="Группа сцен %1"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.exists="Группа сцен или название сцены уже существует"
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.help="Группы сцен могут быть выбраны в качестве цели так же, как и обычные сцены.\n\nКак следует из названия, группа сцен представляет собой набор из нескольких сцен.\nГруппа сцен будет продвигаться по списку назначенных ей сцен в зависимости от настроенных параметров, которые можно найти справа.\n\nВы можете настроить группу сцен на переход к следующей сцене в списке:\nПосле определенного количества раз, когда группа сцен выбрана в качестве цели.\nПо истечении определенного времени.\nИли случайным образом.\n\nНапример, группа сцен, содержащая сцены ...\nScene 1\nScene 2\nScene 3 \n... активирует \"Scene 1\" в первый раз, когда он выбран в качестве цели.\nВо второй раз он активируется \"Scene 2\".\nОставшееся время \"Scene 3\" будет активирован.\n\nНажмите на выделенный символ плюса ниже, чтобы добавить новую группу сцен."
|
||||||
|
AdvSceneSwitcher.sceneGroupTab.scenes.help="Выберите группу сцен, которую вы хотите изменить слева.\n\nВыберите сцену для добавления в эту группу сцен, выбрав сцену выше и нажав на символ плюса ниже.\n\nСцена может быть добавлена несколько раз в одну и ту же группу сцен."
|
||||||
|
|
||||||
|
; Scene Trigger Tab
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.title="Триггеры сцены"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.none="--выбрать триггер--"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneActive="активен"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneInactive="не активен"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneLeave="переключился с"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.none="--выбрать действие--"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startRecording="начать запись"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.pauseRecording="приостановить запись"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.unpauseRecording="отменить паузу записи"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopRecording="остановить запись"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopStreaming="остановить потоковое вещание"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startStreaming="начать потоковое вещание"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startReplayBuffer="запустить буфер воспроизведения"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopReplayBuffer="остановить буфер воспроизведения"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.muteSource="отключить источник"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.unmuteSource="включить источник"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startSwitcher="запустить переключатель сцены"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopSwitcher="остановить переключатель сцены"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.entry="Когда {{scenes}} {{triggers}} {{actions}} {{audioSources}} после {{duration}}"
|
||||||
|
AdvSceneSwitcher.sceneTriggerTab.help="Эта вкладка позволяет запускать действия при изменении сцены, например, остановку записи или потоковой передачи."
|
||||||
|
|
||||||
|
; Hotkey
|
||||||
|
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Запустить Advanced Scene Switcher"
|
||||||
|
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="становить Advanced Scene Switcher"
|
||||||
|
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Переключить старт/стоп для Advanced Scene Switcher"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.askBackup="Обнаружена новая версия Advanced Scene Switcher.\nНужно ли создать резервную копию старых настроек?"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.close="Закрыть"
|
||||||
|
AdvSceneSwitcher.browse="Обзор"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.selectScene="--выбрать сцену--"
|
||||||
|
AdvSceneSwitcher.selectPreviousScene="Предыдущая сцена"
|
||||||
|
AdvSceneSwitcher.currentTransition="Текущий переход"
|
||||||
|
AdvSceneSwitcher.selectTransition="--выбрать переход--"
|
||||||
|
AdvSceneSwitcher.selectWindow="--выбрать окно--"
|
||||||
|
AdvSceneSwitcher.selectAudioSource="--выбрать источник звука--"
|
||||||
|
AdvSceneSwitcher.selectVideoSource="--sвыбрать источник видео--"
|
||||||
|
AdvSceneSwitcher.selectMediaSource="--выбрать источник мультимедиа--"
|
||||||
|
AdvSceneSwitcher.selectProcess="--выбрать процесс--"
|
||||||
|
AdvSceneSwitcher.enterPath="--ввести путь--"
|
||||||
|
AdvSceneSwitcher.enterText="--ввести текст--"
|
||||||
|
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="недействительные записи не будут сохранены"
|
||||||
|
AdvSceneSwitcher.selectWindowTip="Используйте \"OBS\" для указания окна OBS\nИспользуйте \"Переключение задач\"для указания ALT + TAB"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.status.active="Активный"
|
||||||
|
AdvSceneSwitcher.status.inactive="Неактивен"
|
||||||
|
|
||||||
|
AdvSceneSwitcher.unit.milliseconds="миллисекунды"
|
||||||
|
AdvSceneSwitcher.unit.secends="секунды"
|
||||||
|
AdvSceneSwitcher.unit.minutes="минуты"
|
||||||
|
AdvSceneSwitcher.unit.hours="часы"
|
||||||
3
data/res/time.svg
Normal file
3
data/res/time.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" viewBox="0 0 640 640" width="640" height="640"><defs><path d="M599.62 325.49C599.62 477.26 476.41 600.47 324.64 600.47C172.88 600.47 49.67 477.26 49.67 325.49C49.67 173.73 172.88 50.52 324.64 50.52C476.41 50.52 599.62 173.73 599.62 325.49Z" id="c3Wyq0kfYS"></path><mask id="maskanTyyngos" x="-20.33" y="-19.48" width="689.95" height="689.95" maskUnits="userSpaceOnUse"><rect x="-20.33" y="-19.48" width="689.95" height="689.95" fill="white"></rect><use xlink:href="#c3Wyq0kfYS" opacity="1" fill="black"></use></mask><path d="M334.97 96.07C339.51 96.07 343.2 99.75 343.2 104.3C343.2 151.24 343.2 283.84 343.2 330.78C343.2 335.32 339.51 339 334.97 339C329.2 339 320.09 339 314.31 339C309.77 339 306.09 335.32 306.09 330.78C306.09 283.84 306.09 151.24 306.09 104.3C306.09 99.75 309.77 96.07 314.31 96.07C320.09 96.07 329.2 96.07 334.97 96.07Z" id="fxMeu932c"></path><path d="M471.96 338.21C471.97 341.31 469.46 343.83 466.37 343.84C434.35 343.93 343.92 344.21 311.91 344.31C308.81 344.32 306.3 341.82 306.29 338.72C306.27 332.42 306.23 319.13 306.21 312.83C306.2 309.73 308.7 307.21 311.8 307.2C343.81 307.11 434.24 306.83 466.25 306.73C469.35 306.72 471.87 309.23 471.88 312.32C471.9 318.62 471.94 331.91 471.96 338.21Z" id="h65nGmP2BL"></path></defs><g><g><g><g mask="url(#maskanTyyngos)"><use xlink:href="#c3Wyq0kfYS" opacity="1" fill-opacity="0" stroke="#d2d2d2" stroke-width="70" stroke-opacity="1"></use></g></g><g><use xlink:href="#fxMeu932c" opacity="1" fill="#d2d2d2" fill-opacity="1"></use></g><g><use xlink:href="#h65nGmP2BL" opacity="1" fill="#d2d2d2" fill-opacity="1"></use></g></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -723,7 +723,7 @@
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>AdvSceneSwitcher.macroTab.edit</string>
|
<string>AdvSceneSwitcher.macroTab.edit</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_34" stretch="1,20,10">
|
<layout class="QVBoxLayout" name="verticalLayout_34">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0">
|
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0">
|
||||||
<item>
|
<item>
|
||||||
|
|
@ -752,184 +752,204 @@
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QScrollArea" name="macroConditions">
|
<widget class="QSplitter" name="splitter">
|
||||||
<property name="widgetResizable">
|
<property name="orientation">
|
||||||
<bool>true</bool>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="scrollAreaWidgetContents_2">
|
<widget class="QScrollArea" name="macroConditions">
|
||||||
<property name="geometry">
|
<property name="widgetResizable">
|
||||||
<rect>
|
<bool>true</bool>
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>767</width>
|
|
||||||
<height>293</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_35" stretch="10,1">
|
<widget class="QWidget" name="scrollAreaWidgetContents_2">
|
||||||
<item>
|
<property name="geometry">
|
||||||
<layout class="QGridLayout" name="gridLayout_27">
|
<rect>
|
||||||
<item row="0" column="0">
|
<x>0</x>
|
||||||
<widget class="QLabel" name="macroEditConditionHelp">
|
<y>0</y>
|
||||||
<property name="enabled">
|
<width>767</width>
|
||||||
<bool>false</bool>
|
<height>220</height>
|
||||||
</property>
|
</rect>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>AdvSceneSwitcher.macroTab.editConditionHelp</string>
|
<layout class="QVBoxLayout" name="verticalLayout_35" stretch="10,1">
|
||||||
</property>
|
<property name="sizeConstraint">
|
||||||
<property name="alignment">
|
<enum>QLayout::SetMinAndMaxSize</enum>
|
||||||
<set>Qt::AlignCenter</set>
|
</property>
|
||||||
</property>
|
<item>
|
||||||
<property name="wordWrap">
|
<layout class="QGridLayout" name="gridLayout_27">
|
||||||
<bool>true</bool>
|
<property name="sizeConstraint">
|
||||||
</property>
|
<enum>QLayout::SetMinAndMaxSize</enum>
|
||||||
</widget>
|
</property>
|
||||||
</item>
|
<item row="0" column="0">
|
||||||
<item row="0" column="0">
|
<widget class="QLabel" name="macroEditConditionHelp">
|
||||||
<layout class="QVBoxLayout" name="macroEditConditionLayout"/>
|
<property name="enabled">
|
||||||
</item>
|
<bool>false</bool>
|
||||||
</layout>
|
</property>
|
||||||
</item>
|
<property name="text">
|
||||||
<item>
|
<string>AdvSceneSwitcher.macroTab.editConditionHelp</string>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
</property>
|
||||||
<item>
|
<property name="alignment">
|
||||||
<widget class="QPushButton" name="conditionAdd">
|
<set>Qt::AlignCenter</set>
|
||||||
<property name="maximumSize">
|
</property>
|
||||||
<size>
|
<property name="wordWrap">
|
||||||
<width>22</width>
|
<bool>true</bool>
|
||||||
<height>22</height>
|
</property>
|
||||||
</size>
|
</widget>
|
||||||
</property>
|
</item>
|
||||||
<property name="flat">
|
<item row="0" column="0">
|
||||||
<bool>true</bool>
|
<layout class="QVBoxLayout" name="macroEditConditionLayout">
|
||||||
</property>
|
<property name="sizeConstraint">
|
||||||
<property name="themeID" stdset="0">
|
<enum>QLayout::SetFixedSize</enum>
|
||||||
<string notr="true">addIconSmall</string>
|
</property>
|
||||||
</property>
|
</layout>
|
||||||
</widget>
|
</item>
|
||||||
</item>
|
</layout>
|
||||||
<item>
|
</item>
|
||||||
<widget class="QPushButton" name="conditionRemove">
|
<item>
|
||||||
<property name="maximumSize">
|
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||||
<size>
|
<item>
|
||||||
<width>22</width>
|
<widget class="QPushButton" name="conditionAdd">
|
||||||
<height>22</height>
|
<property name="maximumSize">
|
||||||
</size>
|
<size>
|
||||||
</property>
|
<width>22</width>
|
||||||
<property name="flat">
|
<height>22</height>
|
||||||
<bool>true</bool>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="themeID" stdset="0">
|
<property name="flat">
|
||||||
<string notr="true">removeIconSmall</string>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
<property name="themeID" stdset="0">
|
||||||
</item>
|
<string notr="true">addIconSmall</string>
|
||||||
<item>
|
</property>
|
||||||
<spacer name="horizontalSpacer_15">
|
</widget>
|
||||||
<property name="orientation">
|
</item>
|
||||||
<enum>Qt::Horizontal</enum>
|
<item>
|
||||||
</property>
|
<widget class="QPushButton" name="conditionRemove">
|
||||||
<property name="sizeHint" stdset="0">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>40</width>
|
<width>22</width>
|
||||||
<height>20</height>
|
<height>22</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
<property name="flat">
|
||||||
</item>
|
<bool>true</bool>
|
||||||
</layout>
|
</property>
|
||||||
</item>
|
<property name="themeID" stdset="0">
|
||||||
</layout>
|
<string notr="true">removeIconSmall</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_15">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
<widget class="QScrollArea" name="macroActions">
|
||||||
</item>
|
<property name="widgetResizable">
|
||||||
<item>
|
<bool>true</bool>
|
||||||
<widget class="QScrollArea" name="macroActions">
|
|
||||||
<property name="widgetResizable">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<widget class="QWidget" name="scrollAreaWidgetContents_3">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>767</width>
|
|
||||||
<height>145</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_33" stretch="10,1">
|
<widget class="QWidget" name="scrollAreaWidgetContents_3">
|
||||||
<item>
|
<property name="geometry">
|
||||||
<layout class="QGridLayout" name="gridLayout_25">
|
<rect>
|
||||||
<item row="0" column="0">
|
<x>0</x>
|
||||||
<widget class="QLabel" name="macroEditActionHelp">
|
<y>0</y>
|
||||||
<property name="enabled">
|
<width>767</width>
|
||||||
<bool>false</bool>
|
<height>219</height>
|
||||||
</property>
|
</rect>
|
||||||
<property name="text">
|
</property>
|
||||||
<string>AdvSceneSwitcher.macroTab.editActionHelp</string>
|
<layout class="QVBoxLayout" name="verticalLayout_33" stretch="10,1">
|
||||||
</property>
|
<property name="sizeConstraint">
|
||||||
<property name="alignment">
|
<enum>QLayout::SetMinAndMaxSize</enum>
|
||||||
<set>Qt::AlignCenter</set>
|
</property>
|
||||||
</property>
|
<item>
|
||||||
<property name="wordWrap">
|
<layout class="QGridLayout" name="gridLayout_25">
|
||||||
<bool>true</bool>
|
<item row="0" column="0">
|
||||||
</property>
|
<widget class="QLabel" name="macroEditActionHelp">
|
||||||
</widget>
|
<property name="enabled">
|
||||||
</item>
|
<bool>false</bool>
|
||||||
<item row="0" column="0">
|
</property>
|
||||||
<layout class="QVBoxLayout" name="macroEditActionLayout"/>
|
<property name="text">
|
||||||
</item>
|
<string>AdvSceneSwitcher.macroTab.editActionHelp</string>
|
||||||
</layout>
|
</property>
|
||||||
</item>
|
<property name="alignment">
|
||||||
<item>
|
<set>Qt::AlignCenter</set>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_21">
|
</property>
|
||||||
<item>
|
<property name="wordWrap">
|
||||||
<widget class="QPushButton" name="actionAdd">
|
<bool>true</bool>
|
||||||
<property name="maximumSize">
|
</property>
|
||||||
<size>
|
</widget>
|
||||||
<width>22</width>
|
</item>
|
||||||
<height>22</height>
|
<item row="0" column="0">
|
||||||
</size>
|
<layout class="QVBoxLayout" name="macroEditActionLayout">
|
||||||
</property>
|
<property name="sizeConstraint">
|
||||||
<property name="flat">
|
<enum>QLayout::SetMinAndMaxSize</enum>
|
||||||
<bool>true</bool>
|
</property>
|
||||||
</property>
|
</layout>
|
||||||
<property name="themeID" stdset="0">
|
</item>
|
||||||
<string notr="true">addIconSmall</string>
|
</layout>
|
||||||
</property>
|
</item>
|
||||||
</widget>
|
<item>
|
||||||
</item>
|
<layout class="QHBoxLayout" name="horizontalLayout_21">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="actionRemove">
|
<widget class="QPushButton" name="actionAdd">
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>22</width>
|
<width>22</width>
|
||||||
<height>22</height>
|
<height>22</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="flat">
|
<property name="flat">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
<property name="themeID" stdset="0">
|
<property name="themeID" stdset="0">
|
||||||
<string notr="true">removeIconSmall</string>
|
<string notr="true">addIconSmall</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer_14">
|
<widget class="QPushButton" name="actionRemove">
|
||||||
<property name="orientation">
|
<property name="maximumSize">
|
||||||
<enum>Qt::Horizontal</enum>
|
<size>
|
||||||
</property>
|
<width>22</width>
|
||||||
<property name="sizeHint" stdset="0">
|
<height>22</height>
|
||||||
<size>
|
</size>
|
||||||
<width>40</width>
|
</property>
|
||||||
<height>20</height>
|
<property name="flat">
|
||||||
</size>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</spacer>
|
<property name="themeID" stdset="0">
|
||||||
</item>
|
<string notr="true">removeIconSmall</string>
|
||||||
</layout>
|
</property>
|
||||||
</item>
|
</widget>
|
||||||
</layout>
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_14">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
@ -3724,6 +3744,27 @@
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_31">
|
<layout class="QVBoxLayout" name="verticalLayout_31">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QGridLayout" name="gridLayout_24">
|
<layout class="QGridLayout" name="gridLayout_24">
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QCheckBox" name="restrictSend">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.networkTab.server.restrictSendToAutomatedSwitches</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_19">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.networkTab.server.status.currentStatus</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QLabel" name="serverStatus">
|
||||||
|
<property name="text">
|
||||||
|
<string>AdvSceneSwitcher.networkTab.server.status.notRunning</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QSpinBox" name="serverPort">
|
<widget class="QSpinBox" name="serverPort">
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
|
|
@ -3751,24 +3792,17 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="4" column="1">
|
||||||
<widget class="QLabel" name="label_19">
|
<widget class="QCheckBox" name="sendPreview">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>AdvSceneSwitcher.networkTab.server.status.currentStatus</string>
|
<string>AdvSceneSwitcher.networkTab.server.sendPreview</string>
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="1">
|
|
||||||
<widget class="QLabel" name="serverStatus">
|
|
||||||
<property name="text">
|
|
||||||
<string>AdvSceneSwitcher.networkTab.server.status.notRunning</string>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QCheckBox" name="restrictSend">
|
<widget class="QCheckBox" name="sendSceneChange">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>AdvSceneSwitcher.networkTab.server.restrictSendToAutomatedSwitches</string>
|
<string>AdvSceneSwitcher.networkTab.server.sendSceneChange</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <QtGui/qstandarditemmodel.h>
|
#include <QFileDialog>
|
||||||
#include <QPropertyAnimation>
|
|
||||||
#include <QGraphicsColorizeEffect>
|
|
||||||
#include <QMessageBox>
|
|
||||||
|
|
||||||
#include <obs-module.h>
|
#include <obs-module.h>
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
#include <util/util.hpp>
|
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/curl-helper.hpp"
|
#include "headers/curl-helper.hpp"
|
||||||
|
|
@ -73,331 +69,36 @@ void AdvSceneSwitcher::loadUI()
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* UI helpers
|
* Saving and loading
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
void AdvSceneSwitcher::addSelectionEntry(QComboBox *sel,
|
void AskBackup(obs_data_t *obj)
|
||||||
const char *description,
|
|
||||||
bool selectable, const char *tooltip)
|
|
||||||
{
|
{
|
||||||
sel->addItem(description);
|
bool backupSettings = DisplayMessage(
|
||||||
|
obs_module_text("AdvSceneSwitcher.askBackup"), true);
|
||||||
|
|
||||||
if (strcmp(tooltip, "") != 0) {
|
if (!backupSettings) {
|
||||||
sel->setItemData(0, tooltip, Qt::ToolTipRole);
|
|
||||||
}
|
|
||||||
|
|
||||||
QStandardItemModel *model =
|
|
||||||
qobject_cast<QStandardItemModel *>(sel->model());
|
|
||||||
QModelIndex firstIndex =
|
|
||||||
model->index(0, sel->modelColumn(), sel->rootModelIndex());
|
|
||||||
QStandardItem *firstItem = model->itemFromIndex(firstIndex);
|
|
||||||
if (!selectable) {
|
|
||||||
firstItem->setSelectable(false);
|
|
||||||
firstItem->setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
|
|
||||||
bool addSceneGroup,
|
|
||||||
bool addSelect,
|
|
||||||
std::string selectText,
|
|
||||||
bool selectable)
|
|
||||||
{
|
|
||||||
if (addSelect) {
|
|
||||||
if (selectText.empty()) {
|
|
||||||
addSelectionEntry(
|
|
||||||
sel,
|
|
||||||
obs_module_text("AdvSceneSwitcher.selectScene"),
|
|
||||||
selectable,
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
|
||||||
} else {
|
|
||||||
addSelectionEntry(sel, selectText.c_str(), selectable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BPtr<char *> scenes = obs_frontend_get_scene_names();
|
|
||||||
char **temp = scenes;
|
|
||||||
while (*temp) {
|
|
||||||
const char *name = *temp;
|
|
||||||
sel->addItem(name);
|
|
||||||
temp++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addPrevious) {
|
|
||||||
sel->addItem(obs_module_text(
|
|
||||||
"AdvSceneSwitcher.selectPreviousScene"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addSceneGroup) {
|
|
||||||
for (auto &sg : switcher->sceneGroups) {
|
|
||||||
sel->addItem(QString::fromStdString(sg.name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel,
|
|
||||||
bool addCurrent,
|
|
||||||
bool addSelect,
|
|
||||||
bool selectable)
|
|
||||||
{
|
|
||||||
if (addSelect) {
|
|
||||||
addSelectionEntry(
|
|
||||||
sel,
|
|
||||||
obs_module_text("AdvSceneSwitcher.selectTransition"),
|
|
||||||
selectable);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addCurrent) {
|
|
||||||
sel->addItem(
|
|
||||||
obs_module_text("AdvSceneSwitcher.currentTransition"));
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_frontend_source_list *transitions = new obs_frontend_source_list();
|
|
||||||
obs_frontend_get_transitions(transitions);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < transitions->sources.num; i++) {
|
|
||||||
const char *name =
|
|
||||||
obs_source_get_name(transitions->sources.array[i]);
|
|
||||||
sel->addItem(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_frontend_source_list_free(transitions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateWindowSelection(QComboBox *sel, bool addSelect)
|
|
||||||
{
|
|
||||||
if (addSelect) {
|
|
||||||
addSelectionEntry(
|
|
||||||
sel, obs_module_text("AdvSceneSwitcher.selectWindow"));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> windows;
|
|
||||||
GetWindowList(windows);
|
|
||||||
sort(windows.begin(), windows.end());
|
|
||||||
|
|
||||||
for (std::string &window : windows) {
|
|
||||||
sel->addItem(window.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
sel->setItemData(0, obs_module_text("AdvSceneSwitcher.selectWindowTip"),
|
|
||||||
Qt::ToolTipRole);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateAudioSelection(QComboBox *sel, bool addSelect)
|
|
||||||
{
|
|
||||||
if (addSelect) {
|
|
||||||
addSelectionEntry(
|
|
||||||
sel,
|
|
||||||
obs_module_text("AdvSceneSwitcher.selectAudioSource"),
|
|
||||||
false,
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
|
|
||||||
{
|
|
||||||
std::vector<std::string> *list =
|
|
||||||
reinterpret_cast<std::vector<std::string> *>(data);
|
|
||||||
uint32_t flags = obs_source_get_output_flags(source);
|
|
||||||
|
|
||||||
if ((flags & OBS_SOURCE_AUDIO) != 0) {
|
|
||||||
list->push_back(obs_source_get_name(source));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::string> audioSources;
|
|
||||||
obs_enum_sources(sourceEnum, &audioSources);
|
|
||||||
sort(audioSources.begin(), audioSources.end());
|
|
||||||
for (std::string &source : audioSources) {
|
|
||||||
sel->addItem(source.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateVideoSelection(QComboBox *sel, bool addScenes,
|
|
||||||
bool addSelect)
|
|
||||||
{
|
|
||||||
if (addSelect) {
|
|
||||||
addSelectionEntry(
|
|
||||||
sel,
|
|
||||||
obs_module_text("AdvSceneSwitcher.selectVideoSource"),
|
|
||||||
false,
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
|
|
||||||
{
|
|
||||||
std::vector<std::string> *list =
|
|
||||||
reinterpret_cast<std::vector<std::string> *>(data);
|
|
||||||
uint32_t flags = obs_source_get_output_flags(source);
|
|
||||||
std::string test = obs_source_get_name(source);
|
|
||||||
if ((flags & (OBS_SOURCE_VIDEO | OBS_SOURCE_ASYNC)) != 0) {
|
|
||||||
list->push_back(obs_source_get_name(source));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::string> videoSources;
|
|
||||||
obs_enum_sources(sourceEnum, &videoSources);
|
|
||||||
sort(videoSources.begin(), videoSources.end());
|
|
||||||
for (std::string &source : videoSources) {
|
|
||||||
sel->addItem(source.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addScenes) {
|
|
||||||
populateSceneSelection(sel, false, false, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateMediaSelection(QComboBox *sel, bool addSelect)
|
|
||||||
{
|
|
||||||
if (addSelect) {
|
|
||||||
addSelectionEntry(
|
|
||||||
sel,
|
|
||||||
obs_module_text("AdvSceneSwitcher.selectMediaSource"),
|
|
||||||
false,
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
|
|
||||||
}
|
|
||||||
|
|
||||||
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
|
|
||||||
{
|
|
||||||
std::vector<std::string> *list =
|
|
||||||
reinterpret_cast<std::vector<std::string> *>(data);
|
|
||||||
std::string sourceId = obs_source_get_id(source);
|
|
||||||
if (sourceId.compare("ffmpeg_source") == 0 ||
|
|
||||||
sourceId.compare("vlc_source") == 0) {
|
|
||||||
list->push_back(obs_source_get_name(source));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::string> mediaSources;
|
|
||||||
obs_enum_sources(sourceEnum, &mediaSources);
|
|
||||||
sort(mediaSources.begin(), mediaSources.end());
|
|
||||||
for (std::string &source : mediaSources) {
|
|
||||||
sel->addItem(source.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::populateProcessSelection(QComboBox *sel, bool addSelect)
|
|
||||||
{
|
|
||||||
if (addSelect) {
|
|
||||||
addSelectionEntry(
|
|
||||||
sel, obs_module_text("AdvSceneSwitcher.selectProcess"));
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList processes;
|
|
||||||
GetProcessList(processes);
|
|
||||||
processes.sort();
|
|
||||||
for (QString &process : processes)
|
|
||||||
sel->addItem(process);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::listAddClicked(QListWidget *list,
|
|
||||||
SwitchWidget *newWidget,
|
|
||||||
QPushButton *addButton,
|
|
||||||
QMetaObject::Connection *addHighlight)
|
|
||||||
{
|
|
||||||
if (!list || !newWidget) {
|
|
||||||
blog(LOG_WARNING,
|
|
||||||
"listAddClicked called without valid list or widget");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addButton && addHighlight) {
|
QString directory = QFileDialog::getSaveFileName(
|
||||||
addButton->disconnect(*addHighlight);
|
nullptr,
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle"),
|
||||||
|
QDir::currentPath(),
|
||||||
|
obs_module_text(
|
||||||
|
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType"));
|
||||||
|
if (directory.isEmpty()) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QListWidgetItem *item;
|
QFile file(directory);
|
||||||
item = new QListWidgetItem(list);
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||||
list->addItem(item);
|
return;
|
||||||
item->setSizeHint(newWidget->minimumSizeHint());
|
|
||||||
list->setItemWidget(item, newWidget);
|
|
||||||
|
|
||||||
list->scrollToItem(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AdvSceneSwitcher::listMoveUp(QListWidget *list)
|
|
||||||
{
|
|
||||||
int index = list->currentRow();
|
|
||||||
if (index == -1 || index == 0) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *row = list->itemWidget(list->currentItem());
|
obs_data_save_json(obj, file.fileName().toUtf8().constData());
|
||||||
QListWidgetItem *itemN = list->currentItem()->clone();
|
|
||||||
|
|
||||||
list->insertItem(index - 1, itemN);
|
|
||||||
list->setItemWidget(itemN, row);
|
|
||||||
|
|
||||||
list->takeItem(index + 1);
|
|
||||||
list->setCurrentRow(index - 1);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AdvSceneSwitcher::listMoveDown(QListWidget *list)
|
|
||||||
{
|
|
||||||
int index = list->currentRow();
|
|
||||||
if (index == -1 || index == list->count() - 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QWidget *row = list->itemWidget(list->currentItem());
|
|
||||||
QListWidgetItem *itemN = list->currentItem()->clone();
|
|
||||||
|
|
||||||
list->insertItem(index + 2, itemN);
|
|
||||||
list->setItemWidget(itemN, row);
|
|
||||||
|
|
||||||
list->takeItem(index);
|
|
||||||
list->setCurrentRow(index + 1);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMetaObject::Connection AdvSceneSwitcher::PulseWidget(QWidget *widget,
|
|
||||||
QColor endColor,
|
|
||||||
QColor startColor,
|
|
||||||
QString specifier)
|
|
||||||
{
|
|
||||||
if (switcher->disableHints) {
|
|
||||||
return QMetaObject::Connection();
|
|
||||||
}
|
|
||||||
|
|
||||||
widget->setStyleSheet(specifier + "{ \
|
|
||||||
border-style: outset; \
|
|
||||||
border-width: 2px; \
|
|
||||||
border-radius: 10px; \
|
|
||||||
border-color: rgb(0,0,0,0) \
|
|
||||||
}");
|
|
||||||
|
|
||||||
QGraphicsColorizeEffect *eEffect = new QGraphicsColorizeEffect(widget);
|
|
||||||
widget->setGraphicsEffect(eEffect);
|
|
||||||
QPropertyAnimation *paAnimation =
|
|
||||||
new QPropertyAnimation(eEffect, "color");
|
|
||||||
paAnimation->setStartValue(startColor);
|
|
||||||
paAnimation->setEndValue(endColor);
|
|
||||||
paAnimation->setDuration(1000);
|
|
||||||
// Play backwards to return to original state on timer end
|
|
||||||
paAnimation->setDirection(QAbstractAnimation::Backward);
|
|
||||||
|
|
||||||
auto con = QWidget::connect(
|
|
||||||
paAnimation, &QPropertyAnimation::finished, [paAnimation]() {
|
|
||||||
QTimer::singleShot(1000, [paAnimation] {
|
|
||||||
paAnimation->start();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
paAnimation->start();
|
|
||||||
|
|
||||||
return con;
|
|
||||||
}
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* Saving and loading
|
|
||||||
******************************************************************************/
|
|
||||||
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
||||||
{
|
{
|
||||||
if (saving) {
|
if (saving) {
|
||||||
|
|
@ -422,7 +123,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
||||||
obj = obs_data_create();
|
obj = obs_data_create();
|
||||||
}
|
}
|
||||||
if (switcher->versionChanged(obj, g_GIT_SHA1)) {
|
if (switcher->versionChanged(obj, g_GIT_SHA1)) {
|
||||||
AdvSceneSwitcher::AskBackup(obj);
|
AskBackup(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
switcher->loadSettings(obj);
|
switcher->loadSettings(obj);
|
||||||
|
|
@ -484,6 +185,7 @@ void SwitcherData::Thread()
|
||||||
}
|
}
|
||||||
|
|
||||||
vblog(LOG_INFO, "try to sleep for %ld", duration.count());
|
vblog(LOG_INFO, "try to sleep for %ld", duration.count());
|
||||||
|
setWaitScene();
|
||||||
cv.wait_for(lock, duration);
|
cv.wait_for(lock, duration);
|
||||||
|
|
||||||
startTime = std::chrono::high_resolution_clock::now();
|
startTime = std::chrono::high_resolution_clock::now();
|
||||||
|
|
@ -510,6 +212,7 @@ void SwitcherData::Thread()
|
||||||
vblog(LOG_INFO, "sleep for %ld before switching scene",
|
vblog(LOG_INFO, "sleep for %ld before switching scene",
|
||||||
duration.count());
|
duration.count());
|
||||||
|
|
||||||
|
setWaitScene();
|
||||||
cv.wait_for(lock, duration);
|
cv.wait_for(lock, duration);
|
||||||
|
|
||||||
if (stop) {
|
if (stop) {
|
||||||
|
|
@ -616,7 +319,7 @@ bool SwitcherData::checkForMatch(OBSWeakSource &scene,
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
void switchScene(sceneSwitchInfo sceneSwitch)
|
void switchScene(const sceneSwitchInfo &sceneSwitch)
|
||||||
{
|
{
|
||||||
if (!sceneSwitch.scene && switcher->verbose) {
|
if (!sceneSwitch.scene && switcher->verbose) {
|
||||||
blog(LOG_INFO, "nothing to switch to");
|
blog(LOG_INFO, "nothing to switch to");
|
||||||
|
|
@ -640,7 +343,7 @@ void switchScene(sceneSwitchInfo sceneSwitch)
|
||||||
blog(LOG_INFO, "switched scene");
|
blog(LOG_INFO, "switched scene");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->networkConfig.ServerEnabled) {
|
if (switcher->networkConfig.ShouldSendSceneChange()) {
|
||||||
switcher->server.sendMessage(sceneSwitch);
|
switcher->server.sendMessage(sceneSwitch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -648,6 +351,13 @@ void switchScene(sceneSwitchInfo sceneSwitch)
|
||||||
obs_source_release(source);
|
obs_source_release(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void switchPreviewScene(const OBSWeakSource &ws)
|
||||||
|
{
|
||||||
|
auto source = obs_weak_source_get_source(ws);
|
||||||
|
obs_frontend_set_current_preview_scene(source);
|
||||||
|
obs_source_release(source);
|
||||||
|
}
|
||||||
|
|
||||||
void SwitcherData::Start()
|
void SwitcherData::Start()
|
||||||
{
|
{
|
||||||
if (!(th && th->isRunning())) {
|
if (!(th && th->isRunning())) {
|
||||||
|
|
@ -669,6 +379,13 @@ void SwitcherData::Start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResetMacroCounters()
|
||||||
|
{
|
||||||
|
for (auto &m : switcher->macros) {
|
||||||
|
m.ResetCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SwitcherData::Stop()
|
void SwitcherData::Stop()
|
||||||
{
|
{
|
||||||
if (th && th->isRunning()) {
|
if (th && th->isRunning()) {
|
||||||
|
|
@ -680,12 +397,19 @@ void SwitcherData::Stop()
|
||||||
th = nullptr;
|
th = nullptr;
|
||||||
|
|
||||||
writeToStatusFile("Advanced Scene Switcher stopped");
|
writeToStatusFile("Advanced Scene Switcher stopped");
|
||||||
|
ResetMacroCounters();
|
||||||
}
|
}
|
||||||
|
|
||||||
server.stop();
|
server.stop();
|
||||||
client.disconnect();
|
client.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SwitcherData::setWaitScene()
|
||||||
|
{
|
||||||
|
waitScene = obs_frontend_get_current_scene();
|
||||||
|
obs_source_release(waitScene);
|
||||||
|
}
|
||||||
|
|
||||||
bool SwitcherData::sceneChangedDuringWait()
|
bool SwitcherData::sceneChangedDuringWait()
|
||||||
{
|
{
|
||||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
||||||
|
|
@ -713,11 +437,11 @@ extern "C" void FreeSceneSwitcher()
|
||||||
switcher = nullptr;
|
switcher = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleSceneChange(SwitcherData *s)
|
void handleSceneChange()
|
||||||
{
|
{
|
||||||
// Stop waiting if scene was changed
|
// Stop waiting if scene was changed
|
||||||
if (s->sceneChangedDuringWait()) {
|
if (switcher->sceneChangedDuringWait()) {
|
||||||
s->cv.notify_one();
|
switcher->cv.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set previous scene
|
// Set previous scene
|
||||||
|
|
@ -725,42 +449,52 @@ void handleSceneChange(SwitcherData *s)
|
||||||
obs_weak_source_t *ws = obs_source_get_weak_source(source);
|
obs_weak_source_t *ws = obs_source_get_weak_source(source);
|
||||||
obs_source_release(source);
|
obs_source_release(source);
|
||||||
obs_weak_source_release(ws);
|
obs_weak_source_release(ws);
|
||||||
if (source && s->previousSceneHelper != ws) {
|
if (source && switcher->previousSceneHelper != ws) {
|
||||||
s->previousScene = s->previousSceneHelper;
|
switcher->previousScene = switcher->previousSceneHelper;
|
||||||
s->previousSceneHelper = ws;
|
switcher->previousSceneHelper = ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
s->checkTriggers();
|
switcher->checkTriggers();
|
||||||
s->checkDefaultSceneTransitions();
|
switcher->checkDefaultSceneTransitions();
|
||||||
|
|
||||||
if (switcher->networkConfig.ServerEnabled &&
|
if (switcher->networkConfig.ShouldSendFrontendSceneChange()) {
|
||||||
switcher->networkConfig.SendAll) {
|
|
||||||
switcher->server.sendMessage({ws, nullptr, 0});
|
switcher->server.sendMessage({ws, nullptr, 0});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLiveTime(SwitcherData *s)
|
void setLiveTime()
|
||||||
{
|
{
|
||||||
s->liveTime = QDateTime::currentDateTime();
|
switcher->liveTime = QDateTime::currentDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
void resetLiveTime(SwitcherData *s)
|
void resetLiveTime()
|
||||||
{
|
{
|
||||||
s->liveTime = QDateTime();
|
switcher->liveTime = QDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkAutoStartRecording(SwitcherData *s)
|
void checkAutoStartRecording()
|
||||||
{
|
{
|
||||||
if (s->autoStartEvent == AutoStartEvent::RECORDING ||
|
if (switcher->autoStartEvent == AutoStartEvent::RECORDING ||
|
||||||
s->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
|
switcher->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
|
||||||
s->Start();
|
switcher->Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkAutoStartStreaming(SwitcherData *s)
|
void checkAutoStartStreaming()
|
||||||
{
|
{
|
||||||
if (s->autoStartEvent == AutoStartEvent::STREAMING ||
|
if (switcher->autoStartEvent == AutoStartEvent::STREAMING ||
|
||||||
s->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
|
switcher->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
|
||||||
s->Start();
|
switcher->Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void handlePeviewSceneChange()
|
||||||
|
{
|
||||||
|
if (switcher->networkConfig.ShouldSendPrviewSceneChange()) {
|
||||||
|
auto source = obs_frontend_get_current_preview_scene();
|
||||||
|
auto weak = obs_source_get_weak_source(source);
|
||||||
|
switcher->server.sendMessage({weak, nullptr, 0}, true);
|
||||||
|
obs_weak_source_release(weak);
|
||||||
|
obs_source_release(source);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note to future self:
|
// Note to future self:
|
||||||
|
|
@ -768,24 +502,31 @@ void checkAutoStartStreaming(SwitcherData *s)
|
||||||
// frontend functions such as obs_frontend_set_current_scene()
|
// frontend functions such as obs_frontend_set_current_scene()
|
||||||
static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
||||||
{
|
{
|
||||||
|
if (!switcher) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case OBS_FRONTEND_EVENT_EXIT:
|
case OBS_FRONTEND_EVENT_EXIT:
|
||||||
FreeSceneSwitcher();
|
FreeSceneSwitcher();
|
||||||
break;
|
break;
|
||||||
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
||||||
handleSceneChange((SwitcherData *)switcher);
|
handleSceneChange();
|
||||||
|
break;
|
||||||
|
case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED:
|
||||||
|
handlePeviewSceneChange();
|
||||||
break;
|
break;
|
||||||
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
|
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
|
||||||
setLiveTime((SwitcherData *)switcher);
|
setLiveTime();
|
||||||
checkAutoStartRecording((SwitcherData *)switcher);
|
checkAutoStartRecording();
|
||||||
break;
|
break;
|
||||||
case OBS_FRONTEND_EVENT_STREAMING_STARTED:
|
case OBS_FRONTEND_EVENT_STREAMING_STARTED:
|
||||||
setLiveTime((SwitcherData *)switcher);
|
setLiveTime();
|
||||||
checkAutoStartStreaming((SwitcherData *)switcher);
|
checkAutoStartStreaming();
|
||||||
break;
|
break;
|
||||||
case OBS_FRONTEND_EVENT_RECORDING_STOPPED:
|
case OBS_FRONTEND_EVENT_RECORDING_STOPPED:
|
||||||
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
|
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
|
||||||
resetLiveTime((SwitcherData *)switcher);
|
resetLiveTime();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "headers/duration-control.hpp"
|
#include "headers/duration-control.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
#include "obs-module.h"
|
#include "obs-module.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
@ -99,6 +100,8 @@ DurationSelection::DurationSelection(QWidget *parent, bool showUnitSelection)
|
||||||
SLOT(_UnitChanged(int)));
|
SLOT(_UnitChanged(int)));
|
||||||
|
|
||||||
QHBoxLayout *layout = new QHBoxLayout;
|
QHBoxLayout *layout = new QHBoxLayout;
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
layout->setSpacing(11);
|
||||||
layout->addWidget(_duration);
|
layout->addWidget(_duration);
|
||||||
if (showUnitSelection) {
|
if (showUnitSelection) {
|
||||||
layout->addWidget(_unitSelection);
|
layout->addWidget(_unitSelection);
|
||||||
|
|
@ -137,3 +140,131 @@ void DurationSelection::_UnitChanged(int idx)
|
||||||
|
|
||||||
emit UnitChanged(unit);
|
emit UnitChanged(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DurationConstraint::Save(obs_data_t *obj, const char *condName,
|
||||||
|
const char *secondsName, const char *unitName)
|
||||||
|
{
|
||||||
|
obs_data_set_int(obj, condName, static_cast<int>(_type));
|
||||||
|
_dur.Save(obj, secondsName, unitName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DurationConstraint::Load(obs_data_t *obj, const char *condName,
|
||||||
|
const char *secondsName, const char *unitName)
|
||||||
|
{
|
||||||
|
// For backwards compatability check if duration value exist without
|
||||||
|
// time constraint condition - if so assume DurationCondition::MORE
|
||||||
|
if (!obs_data_has_user_value(obj, condName) &&
|
||||||
|
obs_data_has_user_value(obj, secondsName)) {
|
||||||
|
obs_data_set_int(obj, condName,
|
||||||
|
static_cast<int>(DurationCondition::MORE));
|
||||||
|
}
|
||||||
|
|
||||||
|
_type = static_cast<DurationCondition>(obs_data_get_int(obj, condName));
|
||||||
|
_dur.Load(obj, secondsName, unitName);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DurationConstraint::DurationReached()
|
||||||
|
{
|
||||||
|
switch (_type) {
|
||||||
|
case DurationCondition::NONE:
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case DurationCondition::MORE:
|
||||||
|
return _dur.DurationReached();
|
||||||
|
break;
|
||||||
|
case DurationCondition::EQUAL:
|
||||||
|
if (_dur.DurationReached() && !_timeReached) {
|
||||||
|
_timeReached = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DurationCondition::LESS:
|
||||||
|
return !_dur.DurationReached();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DurationConstraint::Reset()
|
||||||
|
{
|
||||||
|
_timeReached = false;
|
||||||
|
_dur.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void populateConditions(QComboBox *list)
|
||||||
|
{
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.duration.condition.none"));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.duration.condition.more"));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.duration.condition.equal"));
|
||||||
|
list->addItem(
|
||||||
|
obs_module_text("AdvSceneSwitcher.duration.condition.less"));
|
||||||
|
}
|
||||||
|
|
||||||
|
DurationConstraintEdit::DurationConstraintEdit(QWidget *parent)
|
||||||
|
{
|
||||||
|
_condition = new QComboBox(parent);
|
||||||
|
_duration = new DurationSelection(parent);
|
||||||
|
_toggle = new QPushButton(parent);
|
||||||
|
_toggle->setMaximumSize(22, 22);
|
||||||
|
_toggle->setIcon(
|
||||||
|
QIcon(QString::fromStdString(getDataFilePath("res/time.svg"))));
|
||||||
|
populateConditions(_condition);
|
||||||
|
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(_ConditionChanged(int)));
|
||||||
|
QObject::connect(_duration, &DurationSelection::DurationChanged, this,
|
||||||
|
&DurationConstraintEdit::DurationChanged);
|
||||||
|
QObject::connect(_duration, &DurationSelection::UnitChanged, this,
|
||||||
|
&DurationConstraintEdit::UnitChanged);
|
||||||
|
QWidget::connect(_toggle, SIGNAL(clicked()), this,
|
||||||
|
SLOT(ToggleClicked()));
|
||||||
|
|
||||||
|
QHBoxLayout *layout = new QHBoxLayout;
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
layout->setSpacing(11);
|
||||||
|
layout->addWidget(_toggle);
|
||||||
|
layout->addWidget(_condition);
|
||||||
|
layout->addWidget(_duration);
|
||||||
|
setLayout(layout);
|
||||||
|
Collapse(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DurationConstraintEdit::SetValue(DurationConstraint &value)
|
||||||
|
{
|
||||||
|
_duration->SetDuration(value.GetDuration());
|
||||||
|
_condition->setCurrentIndex(static_cast<int>(value.GetCondition()));
|
||||||
|
_duration->setVisible(value.GetCondition() != DurationCondition::NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DurationConstraintEdit::SetUnit(DurationUnit u)
|
||||||
|
{
|
||||||
|
_duration->SetUnit(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DurationConstraintEdit::SetDuration(const Duration &d)
|
||||||
|
{
|
||||||
|
_duration->SetDuration(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DurationConstraintEdit::_ConditionChanged(int value)
|
||||||
|
{
|
||||||
|
auto cond = static_cast<DurationCondition>(value);
|
||||||
|
Collapse(cond == DurationCondition::NONE);
|
||||||
|
emit ConditionChanged(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DurationConstraintEdit::ToggleClicked()
|
||||||
|
{
|
||||||
|
Collapse(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DurationConstraintEdit::Collapse(bool collapse)
|
||||||
|
{
|
||||||
|
_toggle->setVisible(collapse);
|
||||||
|
_duration->setVisible(!collapse);
|
||||||
|
_condition->setVisible(!collapse);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
#include <QFileDialog>
|
|
||||||
|
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
#include "headers/version.h"
|
#include "headers/version.h"
|
||||||
|
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
QMetaObject::Connection inactivePluse;
|
QMetaObject::Connection inactivePluse;
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_close_clicked()
|
void AdvSceneSwitcher::on_close_clicked()
|
||||||
|
|
@ -156,8 +156,11 @@ void AdvSceneSwitcher::SetStopped()
|
||||||
obs_module_text("AdvSceneSwitcher.generalTab.status.start"));
|
obs_module_text("AdvSceneSwitcher.generalTab.status.start"));
|
||||||
ui->pluginRunningText->setText(
|
ui->pluginRunningText->setText(
|
||||||
obs_module_text("AdvSceneSwitcher.status.inactive"));
|
obs_module_text("AdvSceneSwitcher.status.inactive"));
|
||||||
inactivePluse = PulseWidget(ui->pluginRunningText, QColor(Qt::red),
|
if (!switcher->disableHints) {
|
||||||
QColor(0, 0, 0, 0), "QLabel ");
|
inactivePluse = PulseWidget(ui->pluginRunningText,
|
||||||
|
QColor(Qt::red), QColor(0, 0, 0, 0),
|
||||||
|
"QLabel ");
|
||||||
|
}
|
||||||
currentStatusActive = false;
|
currentStatusActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,34 +210,6 @@ void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
|
||||||
switcher->disableHints = state;
|
switcher->disableHints = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::AskBackup(obs_data_t *obj)
|
|
||||||
{
|
|
||||||
bool backupSettings = DisplayMessage(
|
|
||||||
obs_module_text("AdvSceneSwitcher.askBackup"), true);
|
|
||||||
|
|
||||||
if (!backupSettings) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString directory = QFileDialog::getSaveFileName(
|
|
||||||
nullptr,
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle"),
|
|
||||||
QDir::currentPath(),
|
|
||||||
obs_module_text(
|
|
||||||
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType"));
|
|
||||||
if (directory.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QFile file(directory);
|
|
||||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_data_save_json(obj, file.fileName().toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_exportSettings_clicked()
|
void AdvSceneSwitcher::on_exportSettings_clicked()
|
||||||
{
|
{
|
||||||
QString directory = QFileDialog::getSaveFileName(
|
QString directory = QFileDialog::getSaveFileName(
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include "ui_advanced-scene-switcher.h"
|
#include "ui_advanced-scene-switcher.h"
|
||||||
#endif
|
#endif
|
||||||
#include "switcher-data-structs.hpp"
|
#include "switcher-data-structs.hpp"
|
||||||
|
#include "platform-funcs.hpp"
|
||||||
|
|
||||||
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
|
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
|
||||||
#define vblog(level, msg, ...) \
|
#define vblog(level, msg, ...) \
|
||||||
|
|
@ -69,44 +70,10 @@ public:
|
||||||
void setTabOrder();
|
void setTabOrder();
|
||||||
void restoreWindowGeo();
|
void restoreWindowGeo();
|
||||||
|
|
||||||
static void AskBackup(obs_data_t *obj);
|
|
||||||
|
|
||||||
static void addSelectionEntry(QComboBox *sel, const char *description,
|
|
||||||
bool selectable = false,
|
|
||||||
const char *tooltip = "");
|
|
||||||
static void populateSceneSelection(QComboBox *sel,
|
|
||||||
bool addPrevious = false,
|
|
||||||
bool addSceneGroup = false,
|
|
||||||
bool addSelect = true,
|
|
||||||
std::string selectText = "",
|
|
||||||
bool selectable = false);
|
|
||||||
|
|
||||||
static void populateTransitionSelection(QComboBox *sel,
|
|
||||||
bool addCurrent = true,
|
|
||||||
bool addSelect = true,
|
|
||||||
bool selectable = false);
|
|
||||||
static void populateWindowSelection(QComboBox *sel,
|
|
||||||
bool addSelect = true);
|
|
||||||
static void populateAudioSelection(QComboBox *sel,
|
|
||||||
bool addSelect = true);
|
|
||||||
static void populateVideoSelection(QComboBox *sel,
|
|
||||||
bool addScenes = true,
|
|
||||||
bool addSelect = true);
|
|
||||||
static void populateMediaSelection(QComboBox *sel,
|
|
||||||
bool addSelect = true);
|
|
||||||
static void populateProcessSelection(QComboBox *sel,
|
|
||||||
bool addSelect = true);
|
|
||||||
QMetaObject::Connection PulseWidget(QWidget *widget, QColor endColor,
|
|
||||||
QColor = QColor(0, 0, 0, 0),
|
|
||||||
QString specifier = "QLabel ");
|
|
||||||
|
|
||||||
void listAddClicked(QListWidget *list, SwitchWidget *newWidget,
|
|
||||||
QPushButton *addButton = nullptr,
|
|
||||||
QMetaObject::Connection *addHighlight = nullptr);
|
|
||||||
bool listMoveUp(QListWidget *list);
|
|
||||||
bool listMoveDown(QListWidget *list);
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
void MacroAdded(const QString &name);
|
||||||
|
void MacroRemoved(const QString &name);
|
||||||
|
void MacroRenamed(const QString &oldName, const QString newName);
|
||||||
void SceneGroupAdded(const QString &name);
|
void SceneGroupAdded(const QString &name);
|
||||||
void SceneGroupRemoved(const QString &name);
|
void SceneGroupRemoved(const QString &name);
|
||||||
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
||||||
|
|
@ -137,6 +104,7 @@ public slots:
|
||||||
void on_macroDown_clicked();
|
void on_macroDown_clicked();
|
||||||
void on_macroName_editingFinished();
|
void on_macroName_editingFinished();
|
||||||
void on_macros_currentRowChanged(int idx);
|
void on_macros_currentRowChanged(int idx);
|
||||||
|
void on_macros_itemChanged(QListWidgetItem *);
|
||||||
void on_conditionAdd_clicked();
|
void on_conditionAdd_clicked();
|
||||||
void on_conditionRemove_clicked();
|
void on_conditionRemove_clicked();
|
||||||
void on_actionAdd_clicked();
|
void on_actionAdd_clicked();
|
||||||
|
|
@ -243,7 +211,9 @@ public slots:
|
||||||
void on_clientSettings_toggled(bool on);
|
void on_clientSettings_toggled(bool on);
|
||||||
void on_clientHostname_textChanged(const QString &text);
|
void on_clientHostname_textChanged(const QString &text);
|
||||||
void on_clientPort_valueChanged(int value);
|
void on_clientPort_valueChanged(int value);
|
||||||
|
void on_sendSceneChange_stateChanged(int state);
|
||||||
void on_restrictSend_stateChanged(int state);
|
void on_restrictSend_stateChanged(int state);
|
||||||
|
void on_sendPreview_stateChanged(int state);
|
||||||
void on_clientReconnect_clicked();
|
void on_clientReconnect_clicked();
|
||||||
void updateClientStatus();
|
void updateClientStatus();
|
||||||
|
|
||||||
|
|
@ -276,42 +246,17 @@ public slots:
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* Windowtitle helper
|
|
||||||
******************************************************************************/
|
|
||||||
void GetWindowList(std::vector<std::string> &windows);
|
|
||||||
void GetWindowList(QStringList &windows);
|
|
||||||
void GetCurrentWindowTitle(std::string &title);
|
|
||||||
bool isFullscreen(std::string &title);
|
|
||||||
bool isMaximized(std::string &title);
|
|
||||||
bool GetCurrentVirtualDesktop(long &desktop);
|
|
||||||
bool GetVirtualDesktopCount(long &ndesktops);
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* Screenregion helper
|
|
||||||
******************************************************************************/
|
|
||||||
std::pair<int, int> getCursorPos();
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* Idle detection helper
|
|
||||||
******************************************************************************/
|
|
||||||
int secondsSinceLastInput();
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
* Executable helper
|
|
||||||
******************************************************************************/
|
|
||||||
void GetProcessList(QStringList &processes);
|
|
||||||
bool isInFocus(const QString &executable);
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Sceneswitch helper
|
* Sceneswitch helper
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
void setNextTransition(sceneSwitchInfo &ssi, obs_source_t *currentSource,
|
void setNextTransition(const sceneSwitchInfo &ssi, obs_source_t *currentSource,
|
||||||
transitionData &td);
|
transitionData &td);
|
||||||
void overwriteTransitionOverride(sceneSwitchInfo ssi, transitionData &td);
|
void overwriteTransitionOverride(const sceneSwitchInfo &ssi,
|
||||||
void restoreTransitionOverride(obs_source_t *scene, transitionData td);
|
transitionData &td);
|
||||||
void switchScene(sceneSwitchInfo ssi);
|
void restoreTransitionOverride(obs_source_t *scene, const transitionData &td);
|
||||||
|
void switchScene(const sceneSwitchInfo &ssi);
|
||||||
|
void switchPreviewScene(const OBSWeakSource &ws);
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Main SwitcherData
|
* Main SwitcherData
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QDoubleSpinBox>
|
#include <QDoubleSpinBox>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
#include <QPushButton>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#include "obs-data.h"
|
#include "obs-data.h"
|
||||||
|
|
@ -53,3 +54,57 @@ private:
|
||||||
|
|
||||||
double _unitMultiplier;
|
double _unitMultiplier;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class DurationCondition {
|
||||||
|
NONE,
|
||||||
|
MORE,
|
||||||
|
EQUAL,
|
||||||
|
LESS,
|
||||||
|
};
|
||||||
|
|
||||||
|
class DurationConstraint {
|
||||||
|
public:
|
||||||
|
void Save(obs_data_t *obj, const char *condName = "time_constraint",
|
||||||
|
const char *secondsName = "seconds",
|
||||||
|
const char *unitName = "displayUnit");
|
||||||
|
void Load(obs_data_t *obj, const char *condName = "time_constraint",
|
||||||
|
const char *secondsName = "seconds",
|
||||||
|
const char *unitName = "displayUnit");
|
||||||
|
void SetCondition(DurationCondition cond) { _type = cond; }
|
||||||
|
void SetDuration(const Duration &dur) { _dur = dur; }
|
||||||
|
void SetValue(double value) { _dur.seconds = value; }
|
||||||
|
void SetUnit(DurationUnit u) { _dur.displayUnit = u; }
|
||||||
|
DurationCondition GetCondition() { return _type; }
|
||||||
|
Duration GetDuration() { return _dur; }
|
||||||
|
bool DurationReached();
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DurationCondition _type = DurationCondition::NONE;
|
||||||
|
Duration _dur;
|
||||||
|
bool _timeReached = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DurationConstraintEdit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
DurationConstraintEdit(QWidget *parent = nullptr);
|
||||||
|
void SetValue(DurationConstraint &value);
|
||||||
|
void SetUnit(DurationUnit u);
|
||||||
|
void SetDuration(const Duration &d);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void _ConditionChanged(int value);
|
||||||
|
void ToggleClicked();
|
||||||
|
signals:
|
||||||
|
void DurationChanged(double value);
|
||||||
|
void UnitChanged(DurationUnit u);
|
||||||
|
void ConditionChanged(DurationCondition value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Collapse(bool collapse);
|
||||||
|
|
||||||
|
DurationSelection *_duration;
|
||||||
|
QComboBox *_condition;
|
||||||
|
QPushButton *_toggle;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ public:
|
||||||
void LogAction();
|
void LogAction();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroAction> Create()
|
static std::shared_ptr<MacroAction> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroActionAudio>();
|
return std::make_shared<MacroActionAudio>();
|
||||||
|
|
@ -27,7 +27,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroActionAudioEdit : public QWidget {
|
class MacroActionAudioEdit : public QWidget {
|
||||||
|
|
@ -37,6 +37,7 @@ public:
|
||||||
MacroActionAudioEdit(
|
MacroActionAudioEdit(
|
||||||
QWidget *parent,
|
QWidget *parent,
|
||||||
std::shared_ptr<MacroActionAudio> entryData = nullptr);
|
std::shared_ptr<MacroActionAudio> entryData = nullptr);
|
||||||
|
void SetWidgetVisibility();
|
||||||
void UpdateEntryData();
|
void UpdateEntryData();
|
||||||
static QWidget *Create(QWidget *parent,
|
static QWidget *Create(QWidget *parent,
|
||||||
std::shared_ptr<MacroAction> action)
|
std::shared_ptr<MacroAction> action)
|
||||||
|
|
|
||||||
|
|
@ -20,14 +20,16 @@ struct MacroActionInfo {
|
||||||
class MacroActionFactory {
|
class MacroActionFactory {
|
||||||
public:
|
public:
|
||||||
MacroActionFactory() = delete;
|
MacroActionFactory() = delete;
|
||||||
static bool Register(int id, MacroActionInfo);
|
static bool Register(const std::string &id, MacroActionInfo);
|
||||||
static std::shared_ptr<MacroAction> Create(const int id);
|
static std::shared_ptr<MacroAction> Create(const std::string &id);
|
||||||
static QWidget *CreateWidget(const int id, QWidget *parent,
|
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||||
std::shared_ptr<MacroAction> action);
|
std::shared_ptr<MacroAction> action);
|
||||||
static auto GetActionTypes() { return _methods; }
|
static auto GetActionTypes() { return _methods; }
|
||||||
|
static std::string GetActionName(const std::string &id);
|
||||||
|
static std::string GetIdByName(const QString &name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::map<int, MacroActionInfo> _methods;
|
static std::map<std::string, MacroActionInfo> _methods;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroActionEdit : public QWidget {
|
class MacroActionEdit : public QWidget {
|
||||||
|
|
@ -35,13 +37,13 @@ class MacroActionEdit : public QWidget {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MacroActionEdit(QWidget *parent = nullptr,
|
MacroActionEdit(QWidget *parent = nullptr,
|
||||||
std::shared_ptr<MacroAction> * = nullptr, int type = 0,
|
std::shared_ptr<MacroAction> * = nullptr,
|
||||||
|
const std::string &id = "scene_switch",
|
||||||
bool startCollapsed = false);
|
bool startCollapsed = false);
|
||||||
void UpdateEntryData(int type);
|
void UpdateEntryData(const std::string &id, bool collapse);
|
||||||
void Collapse(bool collapsed);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void ActionSelectionChanged(int idx);
|
void ActionSelectionChanged(const QString &text);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QComboBox *_actionSelection;
|
QComboBox *_actionSelection;
|
||||||
|
|
|
||||||
61
src/headers/macro-action-filter.hpp
Normal file
61
src/headers/macro-action-filter.hpp
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include "macro-action-edit.hpp"
|
||||||
|
|
||||||
|
enum class FilterAction {
|
||||||
|
ENABLE,
|
||||||
|
DISABLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionFilter : public MacroAction {
|
||||||
|
public:
|
||||||
|
bool PerformAction();
|
||||||
|
void LogAction();
|
||||||
|
bool Save(obs_data_t *obj);
|
||||||
|
bool Load(obs_data_t *obj);
|
||||||
|
std::string GetId() { return id; };
|
||||||
|
static std::shared_ptr<MacroAction> Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<MacroActionFilter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSWeakSource _source;
|
||||||
|
OBSWeakSource _filter;
|
||||||
|
FilterAction _action = FilterAction::ENABLE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool _registered;
|
||||||
|
static const std::string id;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionFilterEdit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroActionFilterEdit(
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<MacroActionFilter> entryData = nullptr);
|
||||||
|
void UpdateEntryData();
|
||||||
|
static QWidget *Create(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroAction> action)
|
||||||
|
{
|
||||||
|
return new MacroActionFilterEdit(
|
||||||
|
parent,
|
||||||
|
std::dynamic_pointer_cast<MacroActionFilter>(action));
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void SourceChanged(const QString &text);
|
||||||
|
void FilterChanged(const QString &text);
|
||||||
|
void ActionChanged(int value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QComboBox *_sources;
|
||||||
|
QComboBox *_filters;
|
||||||
|
QComboBox *_actions;
|
||||||
|
std::shared_ptr<MacroActionFilter> _entryData;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHBoxLayout *_mainLayout;
|
||||||
|
bool _loading = true;
|
||||||
|
};
|
||||||
60
src/headers/macro-action-macro.hpp
Normal file
60
src/headers/macro-action-macro.hpp
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QDoubleSpinBox>
|
||||||
|
#include "macro-action-edit.hpp"
|
||||||
|
#include "macro-selection.hpp"
|
||||||
|
|
||||||
|
enum class PerformMacroAction {
|
||||||
|
PAUSE,
|
||||||
|
UNPAUSE,
|
||||||
|
RESET_COUNTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionMacro : public MacroRefAction {
|
||||||
|
public:
|
||||||
|
bool PerformAction();
|
||||||
|
void LogAction();
|
||||||
|
bool Save(obs_data_t *obj);
|
||||||
|
bool Load(obs_data_t *obj);
|
||||||
|
std::string GetId() { return id; };
|
||||||
|
static std::shared_ptr<MacroAction> Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<MacroActionMacro>();
|
||||||
|
}
|
||||||
|
|
||||||
|
PerformMacroAction _action = PerformMacroAction::PAUSE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool _registered;
|
||||||
|
static const std::string id;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionMacroEdit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroActionMacroEdit(
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<MacroActionMacro> entryData = nullptr);
|
||||||
|
void UpdateEntryData();
|
||||||
|
static QWidget *Create(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroAction> action)
|
||||||
|
{
|
||||||
|
return new MacroActionMacroEdit(
|
||||||
|
parent,
|
||||||
|
std::dynamic_pointer_cast<MacroActionMacro>(action));
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void MacroChanged(const QString &text);
|
||||||
|
void MacroRemove(const QString &name);
|
||||||
|
void ActionChanged(int value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MacroSelection *_macros;
|
||||||
|
QComboBox *_actions;
|
||||||
|
std::shared_ptr<MacroActionMacro> _entryData;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHBoxLayout *_mainLayout;
|
||||||
|
bool _loading = true;
|
||||||
|
};
|
||||||
62
src/headers/macro-action-media.hpp
Normal file
62
src/headers/macro-action-media.hpp
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include "macro-action-edit.hpp"
|
||||||
|
|
||||||
|
enum class MediaAction {
|
||||||
|
PLAY,
|
||||||
|
PAUSE,
|
||||||
|
STOP,
|
||||||
|
RESTART,
|
||||||
|
NEXT,
|
||||||
|
PREVIOUS,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionMedia : public MacroAction {
|
||||||
|
public:
|
||||||
|
bool PerformAction();
|
||||||
|
void LogAction();
|
||||||
|
bool Save(obs_data_t *obj);
|
||||||
|
bool Load(obs_data_t *obj);
|
||||||
|
std::string GetId() { return id; };
|
||||||
|
static std::shared_ptr<MacroAction> Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<MacroActionMedia>();
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSWeakSource _mediaSource;
|
||||||
|
MediaAction _action = MediaAction::PLAY;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool _registered;
|
||||||
|
static const std::string id;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionMediaEdit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroActionMediaEdit(
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<MacroActionMedia> entryData = nullptr);
|
||||||
|
void UpdateEntryData();
|
||||||
|
static QWidget *Create(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroAction> action)
|
||||||
|
{
|
||||||
|
return new MacroActionMediaEdit(
|
||||||
|
parent,
|
||||||
|
std::dynamic_pointer_cast<MacroActionMedia>(action));
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void SourceChanged(const QString &text);
|
||||||
|
void ActionChanged(int value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QComboBox *_mediaSources;
|
||||||
|
QComboBox *_actions;
|
||||||
|
std::shared_ptr<MacroActionMedia> _entryData;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHBoxLayout *_mainLayout;
|
||||||
|
bool _loading = true;
|
||||||
|
};
|
||||||
55
src/headers/macro-action-plugin-state.hpp
Normal file
55
src/headers/macro-action-plugin-state.hpp
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QDoubleSpinBox>
|
||||||
|
#include "macro-action-edit.hpp"
|
||||||
|
|
||||||
|
enum class PluginStateAction {
|
||||||
|
STOP,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionPluginState : public MacroAction {
|
||||||
|
public:
|
||||||
|
bool PerformAction();
|
||||||
|
void LogAction();
|
||||||
|
bool Save(obs_data_t *obj);
|
||||||
|
bool Load(obs_data_t *obj);
|
||||||
|
std::string GetId() { return id; };
|
||||||
|
static std::shared_ptr<MacroAction> Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<MacroActionPluginState>();
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginStateAction _action = PluginStateAction::STOP;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool _registered;
|
||||||
|
static const std::string id;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionPluginStateEdit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroActionPluginStateEdit(
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<MacroActionPluginState> entryData = nullptr);
|
||||||
|
void UpdateEntryData();
|
||||||
|
static QWidget *Create(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroAction> action)
|
||||||
|
{
|
||||||
|
return new MacroActionPluginStateEdit(
|
||||||
|
parent,
|
||||||
|
std::dynamic_pointer_cast<MacroActionPluginState>(
|
||||||
|
action));
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void ActionChanged(int value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QComboBox *_actions;
|
||||||
|
std::shared_ptr<MacroActionPluginState> _entryData;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHBoxLayout *_mainLayout;
|
||||||
|
bool _loading = true;
|
||||||
|
};
|
||||||
|
|
@ -16,7 +16,7 @@ public:
|
||||||
void LogAction();
|
void LogAction();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroAction> Create()
|
static std::shared_ptr<MacroAction> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroActionRecord>();
|
return std::make_shared<MacroActionRecord>();
|
||||||
|
|
@ -26,7 +26,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroActionRecordEdit : public QWidget {
|
class MacroActionRecordEdit : public QWidget {
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ public:
|
||||||
void LogAction();
|
void LogAction();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroAction> Create()
|
static std::shared_ptr<MacroAction> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroActionReplayBuffer>();
|
return std::make_shared<MacroActionReplayBuffer>();
|
||||||
|
|
@ -33,7 +33,7 @@ private:
|
||||||
Duration _duration;
|
Duration _duration;
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroActionReplayBufferEdit : public QWidget {
|
class MacroActionReplayBufferEdit : public QWidget {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ public:
|
||||||
void LogAction();
|
void LogAction();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroAction> Create()
|
static std::shared_ptr<MacroAction> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroActionRun>();
|
return std::make_shared<MacroActionRun>();
|
||||||
|
|
@ -20,7 +20,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroActionRunEdit : public QWidget {
|
class MacroActionRunEdit : public QWidget {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ public:
|
||||||
void LogAction();
|
void LogAction();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
|
|
||||||
static std::shared_ptr<MacroAction> Create()
|
static std::shared_ptr<MacroAction> Create()
|
||||||
{
|
{
|
||||||
|
|
@ -21,7 +21,7 @@ private:
|
||||||
const char *getType() { return "MacroActionSwitchScene"; }
|
const char *getType() { return "MacroActionSwitchScene"; }
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroActionSwitchSceneEdit : public SwitchWidget {
|
class MacroActionSwitchSceneEdit : public SwitchWidget {
|
||||||
62
src/headers/macro-action-scene-visibility.hpp
Normal file
62
src/headers/macro-action-scene-visibility.hpp
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include "macro-action-edit.hpp"
|
||||||
|
|
||||||
|
enum class SceneVisibilityAction {
|
||||||
|
SHOW,
|
||||||
|
HIDE,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionSceneVisibility : public MacroAction {
|
||||||
|
public:
|
||||||
|
bool PerformAction();
|
||||||
|
void LogAction();
|
||||||
|
bool Save(obs_data_t *obj);
|
||||||
|
bool Load(obs_data_t *obj);
|
||||||
|
std::string GetId() { return id; };
|
||||||
|
static std::shared_ptr<MacroAction> Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<MacroActionSceneVisibility>();
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSWeakSource _scene;
|
||||||
|
OBSWeakSource _source;
|
||||||
|
SceneVisibilityAction _action = SceneVisibilityAction::SHOW;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool _registered;
|
||||||
|
static const std::string id;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionSceneVisibilityEdit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroActionSceneVisibilityEdit(
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<MacroActionSceneVisibility> entryData = nullptr);
|
||||||
|
void UpdateEntryData();
|
||||||
|
static QWidget *Create(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroAction> action)
|
||||||
|
{
|
||||||
|
return new MacroActionSceneVisibilityEdit(
|
||||||
|
parent,
|
||||||
|
std::dynamic_pointer_cast<MacroActionSceneVisibility>(
|
||||||
|
action));
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void SceneChanged(const QString &text);
|
||||||
|
void SourceChanged(const QString &text);
|
||||||
|
void ActionChanged(int value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QComboBox *_scenes;
|
||||||
|
QComboBox *_sources;
|
||||||
|
QComboBox *_actions;
|
||||||
|
std::shared_ptr<MacroActionSceneVisibility> _entryData;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHBoxLayout *_mainLayout;
|
||||||
|
bool _loading = true;
|
||||||
|
};
|
||||||
70
src/headers/macro-action-source.hpp
Normal file
70
src/headers/macro-action-source.hpp
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
#pragma once
|
||||||
|
#include "macro-action-edit.hpp"
|
||||||
|
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
|
||||||
|
enum class SourceAction {
|
||||||
|
ENABLE,
|
||||||
|
DISABLE,
|
||||||
|
SETTINGS,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionSource : public MacroAction {
|
||||||
|
public:
|
||||||
|
bool PerformAction();
|
||||||
|
void LogAction();
|
||||||
|
bool Save(obs_data_t *obj);
|
||||||
|
bool Load(obs_data_t *obj);
|
||||||
|
std::string GetId() { return id; };
|
||||||
|
static std::shared_ptr<MacroAction> Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<MacroActionSource>();
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSWeakSource _source;
|
||||||
|
std::string _settings = "";
|
||||||
|
SourceAction _action = SourceAction::ENABLE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool _registered;
|
||||||
|
static const std::string id;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroActionSourceEdit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroActionSourceEdit(
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<MacroActionSource> entryData = nullptr);
|
||||||
|
void UpdateEntryData();
|
||||||
|
static QWidget *Create(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroAction> action)
|
||||||
|
{
|
||||||
|
return new MacroActionSourceEdit(
|
||||||
|
parent,
|
||||||
|
std::dynamic_pointer_cast<MacroActionSource>(action));
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void SourceChanged(const QString &text);
|
||||||
|
void ActionChanged(int value);
|
||||||
|
void GetSettingsClicked();
|
||||||
|
void SettingsChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QComboBox *_sources;
|
||||||
|
QComboBox *_actions;
|
||||||
|
QPushButton *_getSettings;
|
||||||
|
QPlainTextEdit *_settings;
|
||||||
|
QLabel *_warning;
|
||||||
|
std::shared_ptr<MacroActionSource> _entryData;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetWidgetVisibility(bool);
|
||||||
|
QHBoxLayout *_mainLayout;
|
||||||
|
bool _loading = true;
|
||||||
|
};
|
||||||
|
|
@ -14,7 +14,7 @@ public:
|
||||||
void LogAction();
|
void LogAction();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroAction> Create()
|
static std::shared_ptr<MacroAction> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroActionStream>();
|
return std::make_shared<MacroActionStream>();
|
||||||
|
|
@ -28,7 +28,7 @@ private:
|
||||||
Duration _retryCooldown;
|
Duration _retryCooldown;
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroActionStreamEdit : public QWidget {
|
class MacroActionStreamEdit : public QWidget {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ public:
|
||||||
bool PerformAction();
|
bool PerformAction();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroAction> Create()
|
static std::shared_ptr<MacroAction> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroActionWait>();
|
return std::make_shared<MacroActionWait>();
|
||||||
|
|
@ -24,7 +24,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroActionWaitEdit : public QWidget {
|
class MacroActionWaitEdit : public QWidget {
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,6 @@
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
#include "duration-control.hpp"
|
|
||||||
|
|
||||||
enum class AudioCondition {
|
enum class AudioCondition {
|
||||||
ABOVE,
|
ABOVE,
|
||||||
BELOW,
|
BELOW,
|
||||||
|
|
@ -19,7 +17,7 @@ public:
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroCondition> Create()
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroConditionAudio>();
|
return std::make_shared<MacroConditionAudio>();
|
||||||
|
|
@ -33,13 +31,12 @@ public:
|
||||||
OBSWeakSource _audioSource;
|
OBSWeakSource _audioSource;
|
||||||
int _volume = 0;
|
int _volume = 0;
|
||||||
AudioCondition _condition = AudioCondition::ABOVE;
|
AudioCondition _condition = AudioCondition::ABOVE;
|
||||||
Duration _duration;
|
|
||||||
obs_volmeter_t *_volmeter = nullptr;
|
obs_volmeter_t *_volmeter = nullptr;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
float _peak = -std::numeric_limits<float>::infinity();
|
float _peak = -std::numeric_limits<float>::infinity();
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionAudioEdit : public QWidget {
|
class MacroConditionAudioEdit : public QWidget {
|
||||||
|
|
@ -63,13 +60,11 @@ private slots:
|
||||||
void SourceChanged(const QString &text);
|
void SourceChanged(const QString &text);
|
||||||
void VolumeThresholdChanged(int vol);
|
void VolumeThresholdChanged(int vol);
|
||||||
void ConditionChanged(int cond);
|
void ConditionChanged(int cond);
|
||||||
void DurationChanged(double seconds);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QComboBox *_audioSources;
|
QComboBox *_audioSources;
|
||||||
QComboBox *_condition;
|
QComboBox *_condition;
|
||||||
QSpinBox *_volume;
|
QSpinBox *_volume;
|
||||||
DurationSelection *_duration;
|
|
||||||
VolControl *_volMeter = nullptr;
|
VolControl *_volMeter = nullptr;
|
||||||
std::shared_ptr<MacroConditionAudio> _entryData;
|
std::shared_ptr<MacroConditionAudio> _entryData;
|
||||||
|
|
||||||
|
|
|
||||||
70
src/headers/macro-condition-counter.hpp
Normal file
70
src/headers/macro-condition-counter.hpp
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
#pragma once
|
||||||
|
#include "macro.hpp"
|
||||||
|
#include "macro-selection.hpp"
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QSpinBox>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
enum class CounterCondition {
|
||||||
|
BELOW,
|
||||||
|
ABOVE,
|
||||||
|
EQUAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroConditionCounter : public MacroRefCondition {
|
||||||
|
public:
|
||||||
|
bool CheckCondition();
|
||||||
|
bool Save(obs_data_t *obj);
|
||||||
|
bool Load(obs_data_t *obj);
|
||||||
|
std::string GetId() { return id; };
|
||||||
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<MacroConditionCounter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
CounterCondition _condition = CounterCondition::BELOW;
|
||||||
|
int _count = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool _registered;
|
||||||
|
static const std::string id;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroConditionCounterEdit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroConditionCounterEdit(
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<MacroConditionCounter> cond = nullptr);
|
||||||
|
void UpdateEntryData();
|
||||||
|
static QWidget *Create(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroCondition> cond)
|
||||||
|
{
|
||||||
|
return new MacroConditionCounterEdit(
|
||||||
|
parent,
|
||||||
|
std::dynamic_pointer_cast<MacroConditionCounter>(cond));
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void MacroChanged(const QString &text);
|
||||||
|
void MacroRemove(const QString &name);
|
||||||
|
void CountChanged(int value);
|
||||||
|
void ConditionChanged(int cond);
|
||||||
|
void ResetClicked();
|
||||||
|
void UpdateCount();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MacroSelection *_macros;
|
||||||
|
QComboBox *_conditions;
|
||||||
|
QSpinBox *_count;
|
||||||
|
QLabel *_currentCount;
|
||||||
|
QPushButton *_resetCount;
|
||||||
|
std::unique_ptr<QTimer> _timer;
|
||||||
|
std::shared_ptr<MacroConditionCounter> _entryData;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ResetTimer();
|
||||||
|
bool _loading = true;
|
||||||
|
};
|
||||||
|
|
@ -15,19 +15,23 @@ struct MacroConditionInfo {
|
||||||
TCreateMethod _createFunc;
|
TCreateMethod _createFunc;
|
||||||
TCreateWidgetMethod _createWidgetFunc;
|
TCreateWidgetMethod _createWidgetFunc;
|
||||||
std::string _name;
|
std::string _name;
|
||||||
|
bool _useDurationConstraint = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionFactory {
|
class MacroConditionFactory {
|
||||||
public:
|
public:
|
||||||
MacroConditionFactory() = delete;
|
MacroConditionFactory() = delete;
|
||||||
static bool Register(int id, MacroConditionInfo);
|
static bool Register(const std::string &, MacroConditionInfo);
|
||||||
static std::shared_ptr<MacroCondition> Create(const int id);
|
static std::shared_ptr<MacroCondition> Create(const std::string &);
|
||||||
static QWidget *CreateWidget(const int id, QWidget *parent,
|
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||||
std::shared_ptr<MacroCondition>);
|
std::shared_ptr<MacroCondition>);
|
||||||
static auto GetConditionTypes() { return _methods; }
|
static auto GetConditionTypes() { return _methods; }
|
||||||
|
static std::string GetConditionName(const std::string &);
|
||||||
|
static std::string GetIdByName(const QString &name);
|
||||||
|
static bool UsesDurationConstraint(const std::string &id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::map<int, MacroConditionInfo> _methods;
|
static std::map<std::string, MacroConditionInfo> _methods;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionEdit : public QWidget {
|
class MacroConditionEdit : public QWidget {
|
||||||
|
|
@ -36,20 +40,23 @@ class MacroConditionEdit : public QWidget {
|
||||||
public:
|
public:
|
||||||
MacroConditionEdit(QWidget *parent = nullptr,
|
MacroConditionEdit(QWidget *parent = nullptr,
|
||||||
std::shared_ptr<MacroCondition> * = nullptr,
|
std::shared_ptr<MacroCondition> * = nullptr,
|
||||||
int type = 0, bool root = true,
|
const std::string &id = "scene", bool root = true,
|
||||||
bool startCollapsed = false);
|
bool startCollapsed = false);
|
||||||
bool IsRootNode();
|
bool IsRootNode();
|
||||||
void UpdateEntryData(int type);
|
void UpdateEntryData(const std::string &id, bool collapse);
|
||||||
void Collapse(bool collapsed);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void LogicSelectionChanged(int idx);
|
void LogicSelectionChanged(int idx);
|
||||||
void ConditionSelectionChanged(int idx);
|
void ConditionSelectionChanged(const QString &text);
|
||||||
|
void DurationChanged(double seconds);
|
||||||
|
void DurationConditionChanged(DurationCondition cond);
|
||||||
|
void DurationUnitChanged(DurationUnit unit);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QComboBox *_logicSelection;
|
QComboBox *_logicSelection;
|
||||||
QComboBox *_conditionSelection;
|
QComboBox *_conditionSelection;
|
||||||
Section *_section;
|
Section *_section;
|
||||||
|
DurationConstraintEdit *_dur;
|
||||||
|
|
||||||
std::shared_ptr<MacroCondition> *_entryData;
|
std::shared_ptr<MacroCondition> *_entryData;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ public:
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroCondition> Create()
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroConditionFile>();
|
return std::make_shared<MacroConditionFile>();
|
||||||
|
|
@ -39,7 +39,7 @@ private:
|
||||||
QDateTime _lastMod;
|
QDateTime _lastMod;
|
||||||
size_t _lastHash = 0;
|
size_t _lastHash = 0;
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionFileEdit : public QWidget {
|
class MacroConditionFileEdit : public QWidget {
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
|
#include "duration-control.hpp"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include "duration-control.hpp"
|
|
||||||
|
|
||||||
class MacroConditionIdle : public MacroCondition {
|
class MacroConditionIdle : public MacroCondition {
|
||||||
public:
|
public:
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroCondition> Create()
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroConditionIdle>();
|
return std::make_shared<MacroConditionIdle>();
|
||||||
|
|
@ -19,7 +20,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionIdleEdit : public QWidget {
|
class MacroConditionIdleEdit : public QWidget {
|
||||||
|
|
|
||||||
52
src/headers/macro-condition-interval.hpp
Normal file
52
src/headers/macro-condition-interval.hpp
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#pragma once
|
||||||
|
#include "macro.hpp"
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include "duration-control.hpp"
|
||||||
|
|
||||||
|
class MacroConditionInterval : public MacroCondition {
|
||||||
|
public:
|
||||||
|
bool CheckCondition();
|
||||||
|
bool Save(obs_data_t *obj);
|
||||||
|
bool Load(obs_data_t *obj);
|
||||||
|
std::string GetId() { return id; };
|
||||||
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<MacroConditionInterval>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Duration _duration;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool _registered;
|
||||||
|
static const std::string id;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroConditionIntervalEdit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroConditionIntervalEdit(
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<MacroConditionInterval> cond = nullptr);
|
||||||
|
void UpdateEntryData();
|
||||||
|
static QWidget *Create(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroCondition> cond)
|
||||||
|
{
|
||||||
|
return new MacroConditionIntervalEdit(
|
||||||
|
parent,
|
||||||
|
std::dynamic_pointer_cast<MacroConditionInterval>(
|
||||||
|
cond));
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void DurationChanged(double seconds);
|
||||||
|
void DurationUnitChanged(DurationUnit unit);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DurationSelection *_duration;
|
||||||
|
std::shared_ptr<MacroConditionInterval> _entryData;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _loading = true;
|
||||||
|
};
|
||||||
|
|
@ -39,7 +39,7 @@ public:
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroCondition> Create()
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroConditionMedia>();
|
return std::make_shared<MacroConditionMedia>();
|
||||||
|
|
@ -65,7 +65,7 @@ private:
|
||||||
bool _playedToEnd = false;
|
bool _playedToEnd = false;
|
||||||
|
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionMediaEdit : public QWidget {
|
class MacroConditionMediaEdit : public QWidget {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ public:
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroCondition> Create()
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroConditionPluginState>();
|
return std::make_shared<MacroConditionPluginState>();
|
||||||
|
|
@ -22,7 +22,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionPluginStateEdit : public QWidget {
|
class MacroConditionPluginStateEdit : public QWidget {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ public:
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroCondition> Create()
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroConditionProcess>();
|
return std::make_shared<MacroConditionProcess>();
|
||||||
|
|
@ -19,7 +19,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionProcessEdit : public QWidget {
|
class MacroConditionProcessEdit : public QWidget {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include "duration-control.hpp"
|
|
||||||
|
|
||||||
enum class RecordState {
|
enum class RecordState {
|
||||||
STOP,
|
STOP,
|
||||||
|
|
@ -15,18 +14,17 @@ public:
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroCondition> Create()
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroConditionRecord>();
|
return std::make_shared<MacroConditionRecord>();
|
||||||
}
|
}
|
||||||
|
|
||||||
RecordState _recordState;
|
RecordState _recordState;
|
||||||
Duration _duration;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionRecordEdit : public QWidget {
|
class MacroConditionRecordEdit : public QWidget {
|
||||||
|
|
@ -47,12 +45,9 @@ public:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void StateChanged(int value);
|
void StateChanged(int value);
|
||||||
void DurationChanged(double seconds);
|
|
||||||
void DurationUnitChanged(DurationUnit unit);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QComboBox *_recordState;
|
QComboBox *_recordState;
|
||||||
DurationSelection *_duration;
|
|
||||||
std::shared_ptr<MacroConditionRecord> _entryData;
|
std::shared_ptr<MacroConditionRecord> _entryData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ public:
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroCondition> Create()
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroConditionRegion>();
|
return std::make_shared<MacroConditionRegion>();
|
||||||
|
|
@ -18,7 +18,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionRegionEdit : public QWidget {
|
class MacroConditionRegionEdit : public QWidget {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include "duration-control.hpp"
|
|
||||||
|
|
||||||
enum class SceneType {
|
enum class SceneType {
|
||||||
CURRENT,
|
CURRENT,
|
||||||
|
|
@ -14,7 +13,7 @@ public:
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroCondition> Create()
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroConditionScene>();
|
return std::make_shared<MacroConditionScene>();
|
||||||
|
|
@ -22,11 +21,10 @@ public:
|
||||||
|
|
||||||
OBSWeakSource _scene;
|
OBSWeakSource _scene;
|
||||||
SceneType _type;
|
SceneType _type;
|
||||||
Duration _duration;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionSceneEdit : public QWidget {
|
class MacroConditionSceneEdit : public QWidget {
|
||||||
|
|
@ -48,13 +46,10 @@ public:
|
||||||
private slots:
|
private slots:
|
||||||
void SceneChanged(const QString &text);
|
void SceneChanged(const QString &text);
|
||||||
void TypeChanged(int value);
|
void TypeChanged(int value);
|
||||||
void DurationChanged(double seconds);
|
|
||||||
void DurationUnitChanged(DurationUnit unit);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QComboBox *_sceneSelection;
|
QComboBox *_sceneSelection;
|
||||||
QComboBox *_sceneType;
|
QComboBox *_sceneType;
|
||||||
DurationSelection *_duration;
|
|
||||||
std::shared_ptr<MacroConditionScene> _entryData;
|
std::shared_ptr<MacroConditionScene> _entryData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
68
src/headers/macro-condition-source.hpp
Normal file
68
src/headers/macro-condition-source.hpp
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
#pragma once
|
||||||
|
#include "macro.hpp"
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
|
enum class SourceCondition {
|
||||||
|
ACTIVE,
|
||||||
|
SHOWING,
|
||||||
|
SETTINGS,
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroConditionSource : public MacroCondition {
|
||||||
|
public:
|
||||||
|
bool CheckCondition();
|
||||||
|
bool Save(obs_data_t *obj);
|
||||||
|
bool Load(obs_data_t *obj);
|
||||||
|
std::string GetId() { return id; };
|
||||||
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
|
{
|
||||||
|
return std::make_shared<MacroConditionSource>();
|
||||||
|
}
|
||||||
|
|
||||||
|
OBSWeakSource _source = nullptr;
|
||||||
|
SourceCondition _condition = SourceCondition::ACTIVE;
|
||||||
|
std::string _settings = "";
|
||||||
|
bool _regex = false;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool _registered;
|
||||||
|
static const std::string id;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroConditionSourceEdit : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroConditionSourceEdit(
|
||||||
|
QWidget *parent,
|
||||||
|
std::shared_ptr<MacroConditionSource> cond = nullptr);
|
||||||
|
void UpdateEntryData();
|
||||||
|
static QWidget *Create(QWidget *parent,
|
||||||
|
std::shared_ptr<MacroCondition> cond)
|
||||||
|
{
|
||||||
|
return new MacroConditionSourceEdit(
|
||||||
|
parent,
|
||||||
|
std::dynamic_pointer_cast<MacroConditionSource>(cond));
|
||||||
|
}
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void SourceChanged(const QString &text);
|
||||||
|
void ConditionChanged(int cond);
|
||||||
|
void GetSettingsClicked();
|
||||||
|
void SettingsChanged();
|
||||||
|
void RegexChanged(int);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QComboBox *_sources;
|
||||||
|
QComboBox *_conditions;
|
||||||
|
QPushButton *_getSettings;
|
||||||
|
QPlainTextEdit *_settings;
|
||||||
|
QCheckBox *_regex;
|
||||||
|
|
||||||
|
std::shared_ptr<MacroConditionSource> _entryData;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetSettingsSelectionVisible(bool visible);
|
||||||
|
bool _loading = true;
|
||||||
|
};
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include "duration-control.hpp"
|
|
||||||
|
|
||||||
enum class StreamState {
|
enum class StreamState {
|
||||||
STOP,
|
STOP,
|
||||||
|
|
@ -14,18 +13,17 @@ public:
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroCondition> Create()
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroConditionStream>();
|
return std::make_shared<MacroConditionStream>();
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamState _streamState;
|
StreamState _streamState;
|
||||||
Duration _duration;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionStreamEdit : public QWidget {
|
class MacroConditionStreamEdit : public QWidget {
|
||||||
|
|
@ -46,12 +44,9 @@ public:
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void StateChanged(int value);
|
void StateChanged(int value);
|
||||||
void DurationChanged(double seconds);
|
|
||||||
void DurationUnitChanged(DurationUnit unit);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QComboBox *_streamState;
|
QComboBox *_streamState;
|
||||||
DurationSelection *_duration;
|
|
||||||
std::shared_ptr<MacroConditionStream> _entryData;
|
std::shared_ptr<MacroConditionStream> _entryData;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "macro.hpp"
|
#include "macro.hpp"
|
||||||
|
#include "screenshot-helper.hpp"
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include "duration-control.hpp"
|
|
||||||
#include "screenshot-helper.hpp"
|
|
||||||
|
|
||||||
enum class VideoCondition {
|
enum class VideoCondition {
|
||||||
MATCH,
|
MATCH,
|
||||||
|
|
@ -19,7 +19,7 @@ public:
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
QImage GetMatchImage() { return _matchImage; };
|
QImage GetMatchImage() { return _matchImage; };
|
||||||
static std::shared_ptr<MacroCondition> Create()
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
{
|
{
|
||||||
|
|
@ -30,7 +30,6 @@ public:
|
||||||
|
|
||||||
OBSWeakSource _videoSource;
|
OBSWeakSource _videoSource;
|
||||||
VideoCondition _condition = VideoCondition::MATCH;
|
VideoCondition _condition = VideoCondition::MATCH;
|
||||||
Duration _duration;
|
|
||||||
std::string _file = obs_module_text("AdvSceneSwitcher.enterPath");
|
std::string _file = obs_module_text("AdvSceneSwitcher.enterPath");
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -39,7 +38,7 @@ private:
|
||||||
std::unique_ptr<AdvSSScreenshotObj> _screenshotData = nullptr;
|
std::unique_ptr<AdvSSScreenshotObj> _screenshotData = nullptr;
|
||||||
QImage _matchImage;
|
QImage _matchImage;
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionVideoEdit : public QWidget {
|
class MacroConditionVideoEdit : public QWidget {
|
||||||
|
|
@ -66,12 +65,9 @@ private slots:
|
||||||
void ConditionChanged(int cond);
|
void ConditionChanged(int cond);
|
||||||
void FilePathChanged();
|
void FilePathChanged();
|
||||||
void BrowseButtonClicked();
|
void BrowseButtonClicked();
|
||||||
void DurationChanged(double seconds);
|
|
||||||
void DurationUnitChanged(DurationUnit unit);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QComboBox *_videoSelection;
|
QComboBox *_videoSelection;
|
||||||
DurationSelection *_duration;
|
|
||||||
QComboBox *_condition;
|
QComboBox *_condition;
|
||||||
QLineEdit *_filePath;
|
QLineEdit *_filePath;
|
||||||
QPushButton *_browseButton;
|
QPushButton *_browseButton;
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ public:
|
||||||
bool CheckCondition();
|
bool CheckCondition();
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
int GetId() { return id; };
|
std::string GetId() { return id; };
|
||||||
static std::shared_ptr<MacroCondition> Create()
|
static std::shared_ptr<MacroCondition> Create()
|
||||||
{
|
{
|
||||||
return std::make_shared<MacroConditionWindow>();
|
return std::make_shared<MacroConditionWindow>();
|
||||||
|
|
@ -27,7 +27,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static bool _registered;
|
static bool _registered;
|
||||||
static const int id;
|
static const std::string id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroConditionWindowEdit : public QWidget {
|
class MacroConditionWindowEdit : public QWidget {
|
||||||
|
|
|
||||||
17
src/headers/macro-selection.hpp
Normal file
17
src/headers/macro-selection.hpp
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QComboBox>
|
||||||
|
|
||||||
|
class Macro;
|
||||||
|
|
||||||
|
class MacroSelection : public QComboBox {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacroSelection(QWidget *parent);
|
||||||
|
void SetCurrentMacro(Macro *);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void MacroAdd(const QString &name);
|
||||||
|
void MacroRemove(const QString &name);
|
||||||
|
void MacroRename(const QString &oldName, const QString &newName);
|
||||||
|
};
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "duration-control.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
#include <obs-module.h>
|
#include <obs-module.h>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
constexpr auto macro_func = 10;
|
constexpr auto macro_func = 10;
|
||||||
constexpr auto default_priority_10 = macro_func;
|
constexpr auto default_priority_10 = macro_func;
|
||||||
|
|
@ -38,14 +41,23 @@ public:
|
||||||
virtual bool CheckCondition() = 0;
|
virtual bool CheckCondition() = 0;
|
||||||
virtual bool Save(obs_data_t *obj) = 0;
|
virtual bool Save(obs_data_t *obj) = 0;
|
||||||
virtual bool Load(obs_data_t *obj) = 0;
|
virtual bool Load(obs_data_t *obj) = 0;
|
||||||
virtual int GetId() = 0;
|
virtual std::string GetId() = 0;
|
||||||
|
|
||||||
LogicType GetLogicType() { return _logic; }
|
LogicType GetLogicType() { return _logic; }
|
||||||
void SetLogicType(LogicType logic) { _logic = logic; }
|
void SetLogicType(LogicType logic) { _logic = logic; }
|
||||||
|
|
||||||
static const std::map<LogicType, LogicTypeInfo> logicTypes;
|
static const std::map<LogicType, LogicTypeInfo> logicTypes;
|
||||||
|
|
||||||
|
bool DurationReached() { return _duration.DurationReached(); }
|
||||||
|
void ResetDuration() { _duration.Reset(); }
|
||||||
|
DurationConstraint GetDurationConstraint() { return _duration; }
|
||||||
|
void SetDurationConstraint(const DurationConstraint &dur);
|
||||||
|
void SetDurationCondition(DurationCondition cond);
|
||||||
|
void SetDurationUnit(DurationUnit u);
|
||||||
|
void SetDuration(double seconds);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LogicType _logic;
|
LogicType _logic;
|
||||||
|
DurationConstraint _duration;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacroAction {
|
class MacroAction {
|
||||||
|
|
@ -53,21 +65,24 @@ public:
|
||||||
virtual bool PerformAction() = 0;
|
virtual bool PerformAction() = 0;
|
||||||
virtual bool Save(obs_data_t *obj) = 0;
|
virtual bool Save(obs_data_t *obj) = 0;
|
||||||
virtual bool Load(obs_data_t *obj) = 0;
|
virtual bool Load(obs_data_t *obj) = 0;
|
||||||
virtual int GetId() = 0;
|
virtual std::string GetId() = 0;
|
||||||
virtual void LogAction();
|
virtual void LogAction();
|
||||||
};
|
};
|
||||||
|
|
||||||
class Macro {
|
class Macro {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Macro(std::string name = "");
|
Macro(const std::string &name = "");
|
||||||
virtual ~Macro();
|
virtual ~Macro();
|
||||||
|
|
||||||
bool CeckMatch();
|
bool CeckMatch();
|
||||||
bool PerformAction();
|
bool PerformAction();
|
||||||
bool Matched() { return _matched; }
|
bool Matched() { return _matched; }
|
||||||
std::string Name() { return _name; }
|
std::string Name() { return _name; }
|
||||||
void SetName(std::string name) { _name = name; }
|
void SetName(const std::string &name);
|
||||||
|
void SetPaused(bool pause = true) { _paused = pause; }
|
||||||
|
bool Paused() { return _paused; }
|
||||||
|
int GetCount() { return _count; };
|
||||||
|
void ResetCount() { _count = 0; };
|
||||||
std::deque<std::shared_ptr<MacroCondition>> &Conditions()
|
std::deque<std::shared_ptr<MacroCondition>> &Conditions()
|
||||||
{
|
{
|
||||||
return _conditions;
|
return _conditions;
|
||||||
|
|
@ -76,13 +91,56 @@ public:
|
||||||
|
|
||||||
bool Save(obs_data_t *obj);
|
bool Save(obs_data_t *obj);
|
||||||
bool Load(obs_data_t *obj);
|
bool Load(obs_data_t *obj);
|
||||||
|
// Some macros can refer to other macros, which are not yet loaded.
|
||||||
|
// Use this function to set these references after loading is complete.
|
||||||
|
void ResolveMacroRef();
|
||||||
|
|
||||||
// Helper function for plugin state condition regarding scene change
|
// Helper function for plugin state condition regarding scene change
|
||||||
bool SwitchesScene();
|
bool SwitchesScene();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void SetupHotkeys();
|
||||||
|
void ClearHotkeys();
|
||||||
|
void SetHotkeysDesc();
|
||||||
|
|
||||||
std::string _name = "";
|
std::string _name = "";
|
||||||
std::deque<std::shared_ptr<MacroCondition>> _conditions;
|
std::deque<std::shared_ptr<MacroCondition>> _conditions;
|
||||||
std::deque<std::shared_ptr<MacroAction>> _actions;
|
std::deque<std::shared_ptr<MacroAction>> _actions;
|
||||||
bool _matched = false;
|
bool _matched = false;
|
||||||
|
bool _paused = false;
|
||||||
|
int _count = 0;
|
||||||
|
obs_hotkey_id _pauseHotkey = OBS_INVALID_HOTKEY_ID;
|
||||||
|
obs_hotkey_id _unpauseHotkey = OBS_INVALID_HOTKEY_ID;
|
||||||
|
};
|
||||||
|
|
||||||
|
Macro *GetMacroByName(const char *name);
|
||||||
|
Macro *GetMacroByQString(const QString &name);
|
||||||
|
|
||||||
|
class MacroRef {
|
||||||
|
public:
|
||||||
|
MacroRef(){};
|
||||||
|
MacroRef(std::string name);
|
||||||
|
void UpdateRef();
|
||||||
|
void UpdateRef(std::string name);
|
||||||
|
void UpdateRef(QString name);
|
||||||
|
void Save(obs_data_t *obj);
|
||||||
|
void Load(obs_data_t *obj);
|
||||||
|
Macro *get();
|
||||||
|
Macro *operator->();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string _name = "";
|
||||||
|
Macro *_ref = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroRefCondition : public MacroCondition {
|
||||||
|
public:
|
||||||
|
void ResolveMacroRef();
|
||||||
|
MacroRef _macro;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MacroRefAction : public MacroAction {
|
||||||
|
public:
|
||||||
|
void ResolveMacroRef();
|
||||||
|
MacroRef _macro;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
11
src/headers/platform-funcs.hpp
Normal file
11
src/headers/platform-funcs.hpp
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void GetWindowList(std::vector<std::string> &windows);
|
||||||
|
void GetWindowList(QStringList &windows);
|
||||||
|
void GetCurrentWindowTitle(std::string &title);
|
||||||
|
bool isFullscreen(const std::string &title);
|
||||||
|
bool isMaximized(const std::string &title);
|
||||||
|
std::pair<int, int> getCursorPos();
|
||||||
|
int secondsSinceLastInput();
|
||||||
|
void GetProcessList(QStringList &processes);
|
||||||
|
bool isInFocus(const QString &executable);
|
||||||
|
|
@ -40,9 +40,9 @@ struct SceneGroup {
|
||||||
int lastRandomScene = -1;
|
int lastRandomScene = -1;
|
||||||
|
|
||||||
inline SceneGroup(){};
|
inline SceneGroup(){};
|
||||||
inline SceneGroup(std::string name_) : name(name_){};
|
inline SceneGroup(const std::string &name_) : name(name_){};
|
||||||
inline SceneGroup(std::string name_, AdvanceCondition type_,
|
inline SceneGroup(const std::string &name_, AdvanceCondition type_,
|
||||||
std::vector<OBSWeakSource> scenes_, int count_,
|
const std::vector<OBSWeakSource> &scenes_, int count_,
|
||||||
double time_, bool repeat_)
|
double time_, bool repeat_)
|
||||||
: name(name_),
|
: name(name_),
|
||||||
type(type_),
|
type(type_),
|
||||||
|
|
|
||||||
|
|
@ -14,18 +14,31 @@ public:
|
||||||
explicit Section(const int animationDuration = 300,
|
explicit Section(const int animationDuration = 300,
|
||||||
QWidget *parent = 0);
|
QWidget *parent = 0);
|
||||||
|
|
||||||
void SetContent(QWidget *w);
|
void SetContent(QWidget *w, bool collapsed = true);
|
||||||
void AddHeaderWidget(QWidget *);
|
void AddHeaderWidget(QWidget *);
|
||||||
|
|
||||||
public slots:
|
protected:
|
||||||
void Collapse(bool collapsed);
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void AnimationFinished();
|
||||||
|
void Collapse(bool collapse);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void SetupAnimations();
|
||||||
|
void CleanUpPreviousContent();
|
||||||
|
|
||||||
QGridLayout *_mainLayout;
|
QGridLayout *_mainLayout;
|
||||||
QHBoxLayout *_headerWidgetLayout;
|
QHBoxLayout *_headerWidgetLayout;
|
||||||
QToolButton *_toggleButton;
|
QToolButton *_toggleButton;
|
||||||
QFrame *_headerLine;
|
QFrame *_headerLine;
|
||||||
QParallelAnimationGroup *_toggleAnimation = nullptr;
|
QParallelAnimationGroup *_toggleAnimation = nullptr;
|
||||||
|
QParallelAnimationGroup *_contentAnimation = nullptr;
|
||||||
QScrollArea *_contentArea = nullptr;
|
QScrollArea *_contentArea = nullptr;
|
||||||
|
QWidget *_content = nullptr;
|
||||||
int _animationDuration;
|
int _animationDuration;
|
||||||
|
std::atomic_bool _transitioning = {false};
|
||||||
|
std::atomic_bool _collapsed = {false};
|
||||||
|
int _headerHeight = 0;
|
||||||
|
int _contentHeight = 0;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,10 @@ public:
|
||||||
|
|
||||||
std::string GetClientUri();
|
std::string GetClientUri();
|
||||||
|
|
||||||
|
bool ShouldSendSceneChange();
|
||||||
|
bool ShouldSendFrontendSceneChange();
|
||||||
|
bool ShouldSendPrviewSceneChange();
|
||||||
|
|
||||||
// Server
|
// Server
|
||||||
bool ServerEnabled;
|
bool ServerEnabled;
|
||||||
uint64_t ServerPort;
|
uint64_t ServerPort;
|
||||||
|
|
@ -42,7 +46,9 @@ public:
|
||||||
bool ClientEnabled;
|
bool ClientEnabled;
|
||||||
std::string Address;
|
std::string Address;
|
||||||
uint64_t ClientPort;
|
uint64_t ClientPort;
|
||||||
bool SendAll;
|
bool SendSceneChange;
|
||||||
|
bool SendSceneChangeAll;
|
||||||
|
bool SendPreview;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WSServer : public QObject {
|
class WSServer : public QObject {
|
||||||
|
|
@ -53,7 +59,7 @@ public:
|
||||||
virtual ~WSServer();
|
virtual ~WSServer();
|
||||||
void start(quint16 port, bool lockToIPv4);
|
void start(quint16 port, bool lockToIPv4);
|
||||||
void stop();
|
void stop();
|
||||||
void sendMessage(sceneSwitchInfo sceneSwitch);
|
void sendMessage(sceneSwitchInfo sceneSwitch, bool preview = false);
|
||||||
QThreadPool *threadPool() { return &_threadPool; }
|
QThreadPool *threadPool() { return &_threadPool; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -192,6 +192,7 @@ struct SwitcherData {
|
||||||
void Start();
|
void Start();
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
|
void setWaitScene();
|
||||||
bool sceneChangedDuringWait();
|
bool sceneChangedDuringWait();
|
||||||
|
|
||||||
bool prioFuncsValid();
|
bool prioFuncsValid();
|
||||||
|
|
@ -200,7 +201,7 @@ struct SwitcherData {
|
||||||
void resetTabOrder();
|
void resetTabOrder();
|
||||||
|
|
||||||
void writeSceneInfoToFile();
|
void writeSceneInfoToFile();
|
||||||
void writeToStatusFile(QString status);
|
void writeToStatusFile(const QString &msg);
|
||||||
|
|
||||||
bool checkForMatch(OBSWeakSource &scene, OBSWeakSource &transition,
|
bool checkForMatch(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||||
int &linger, bool &setPreviousSceneAsMatch,
|
int &linger, bool &setPreviousSceneAsMatch,
|
||||||
|
|
@ -253,7 +254,7 @@ struct SwitcherData {
|
||||||
void saveNetworkSwitches(obs_data_t *obj);
|
void saveNetworkSwitches(obs_data_t *obj);
|
||||||
void saveGeneralSettings(obs_data_t *obj);
|
void saveGeneralSettings(obs_data_t *obj);
|
||||||
void saveHotkeys(obs_data_t *obj);
|
void saveHotkeys(obs_data_t *obj);
|
||||||
void saveVersion(obs_data_t *obj, std::string currentVersion);
|
void saveVersion(obs_data_t *obj, const std::string ¤tVersion);
|
||||||
|
|
||||||
void loadSettings(obs_data_t *obj);
|
void loadSettings(obs_data_t *obj);
|
||||||
void loadMacros(obs_data_t *obj);
|
void loadMacros(obs_data_t *obj);
|
||||||
|
|
|
||||||
|
|
@ -1,118 +1,28 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QTextStream>
|
|
||||||
#include <QLayout>
|
#include <QLayout>
|
||||||
#include <QLabel>
|
#include <QComboBox>
|
||||||
#include <QMessageBox>
|
#include <QMetaObject>
|
||||||
#include <unordered_map>
|
#include <QListWidget>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QColor>
|
||||||
#include <obs.hpp>
|
#include <obs.hpp>
|
||||||
#include <obs-module.h>
|
|
||||||
#include <obs-frontend-api.h>
|
#include <obs-frontend-api.h>
|
||||||
|
#include <deque>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include "scene-group.hpp"
|
||||||
|
|
||||||
static inline bool WeakSourceValid(obs_weak_source_t *ws)
|
bool WeakSourceValid(obs_weak_source_t *ws);
|
||||||
{
|
std::string GetWeakSourceName(obs_weak_source_t *weak_source);
|
||||||
obs_source_t *source = obs_weak_source_get_source(ws);
|
OBSWeakSource GetWeakSourceByName(const char *name);
|
||||||
if (source) {
|
OBSWeakSource GetWeakSourceByQString(const QString &name);
|
||||||
obs_source_release(source);
|
OBSWeakSource GetWeakTransitionByName(const char *transitionName);
|
||||||
}
|
OBSWeakSource GetWeakTransitionByQString(const QString &name);
|
||||||
return !!source;
|
OBSWeakSource GetWeakFilterByName(OBSWeakSource source, const char *name);
|
||||||
}
|
OBSWeakSource GetWeakFilterByQString(OBSWeakSource source, const QString &name);
|
||||||
|
bool compareIgnoringLineEnding(QString &s1, QString &s2);
|
||||||
static inline std::string GetWeakSourceName(obs_weak_source_t *weak_source)
|
std::string getSourceSettings(OBSWeakSource ws);
|
||||||
{
|
std::string getDataFilePath(const std::string &file);
|
||||||
std::string name;
|
|
||||||
|
|
||||||
obs_source_t *source = obs_weak_source_get_source(weak_source);
|
|
||||||
if (source) {
|
|
||||||
name = obs_source_get_name(source);
|
|
||||||
obs_source_release(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline OBSWeakSource GetWeakSourceByName(const char *name)
|
|
||||||
{
|
|
||||||
OBSWeakSource weak;
|
|
||||||
obs_source_t *source = obs_get_source_by_name(name);
|
|
||||||
if (source) {
|
|
||||||
weak = obs_source_get_weak_source(source);
|
|
||||||
obs_weak_source_release(weak);
|
|
||||||
obs_source_release(source);
|
|
||||||
}
|
|
||||||
|
|
||||||
return weak;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline OBSWeakSource GetWeakSourceByQString(const QString &name)
|
|
||||||
{
|
|
||||||
return GetWeakSourceByName(name.toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline OBSWeakSource GetWeakTransitionByName(const char *transitionName)
|
|
||||||
{
|
|
||||||
OBSWeakSource weak;
|
|
||||||
obs_source_t *source = nullptr;
|
|
||||||
|
|
||||||
if (strcmp(transitionName, "Default") == 0) {
|
|
||||||
source = obs_frontend_get_current_transition();
|
|
||||||
weak = obs_source_get_weak_source(source);
|
|
||||||
obs_source_release(source);
|
|
||||||
obs_weak_source_release(weak);
|
|
||||||
return weak;
|
|
||||||
}
|
|
||||||
|
|
||||||
obs_frontend_source_list *transitions = new obs_frontend_source_list();
|
|
||||||
obs_frontend_get_transitions(transitions);
|
|
||||||
bool match = false;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < transitions->sources.num; i++) {
|
|
||||||
const char *name =
|
|
||||||
obs_source_get_name(transitions->sources.array[i]);
|
|
||||||
if (strcmp(transitionName, name) == 0) {
|
|
||||||
match = true;
|
|
||||||
source = transitions->sources.array[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (match) {
|
|
||||||
weak = obs_source_get_weak_source(source);
|
|
||||||
obs_weak_source_release(weak);
|
|
||||||
}
|
|
||||||
obs_frontend_source_list_free(transitions);
|
|
||||||
|
|
||||||
return weak;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline OBSWeakSource GetWeakTransitionByQString(const QString &name)
|
|
||||||
{
|
|
||||||
return GetWeakTransitionByName(name.toUtf8().constData());
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::string
|
|
||||||
getNextDelim(std::string text,
|
|
||||||
std::unordered_map<std::string, QWidget *> placeholders)
|
|
||||||
{
|
|
||||||
size_t pos = std::string::npos;
|
|
||||||
std::string res = "";
|
|
||||||
|
|
||||||
for (const auto &ph : placeholders) {
|
|
||||||
size_t newPos = text.find(ph.first);
|
|
||||||
if (newPos <= pos) {
|
|
||||||
pos = newPos;
|
|
||||||
res = ph.first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pos == std::string::npos) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Populate layout with labels and widgets based on provided text
|
* Populate layout with labels and widgets based on provided text
|
||||||
|
|
@ -122,95 +32,32 @@ getNextDelim(std::string text,
|
||||||
* @param placeholders Map containing a mapping of placeholder strings to widgets.
|
* @param placeholders Map containing a mapping of placeholder strings to widgets.
|
||||||
* @param addStretch Add addStretch() to layout.
|
* @param addStretch Add addStretch() to layout.
|
||||||
*/
|
*/
|
||||||
static inline void
|
void placeWidgets(std::string text, QBoxLayout *layout,
|
||||||
placeWidgets(std::string text, QBoxLayout *layout,
|
std::unordered_map<std::string, QWidget *> placeholders,
|
||||||
std::unordered_map<std::string, QWidget *> placeholders,
|
bool addStretch = true);
|
||||||
bool addStretch = true)
|
void clearLayout(QLayout *layout);
|
||||||
{
|
QMetaObject::Connection PulseWidget(QWidget *widget, QColor endColor,
|
||||||
std::vector<std::pair<std::string, QWidget *>> labelsWidgetsPairs;
|
QColor = QColor(0, 0, 0, 0),
|
||||||
|
QString specifier = "QLabel ");
|
||||||
std::string delim = getNextDelim(text, placeholders);
|
void listAddClicked(QListWidget *list, QWidget *newWidget,
|
||||||
while (delim != "") {
|
QPushButton *addButton = nullptr,
|
||||||
size_t pos = text.find(delim);
|
QMetaObject::Connection *addHighlight = nullptr);
|
||||||
if (pos != std::string::npos) {
|
bool listMoveUp(QListWidget *list);
|
||||||
labelsWidgetsPairs.emplace_back(text.substr(0, pos),
|
bool listMoveDown(QListWidget *list);
|
||||||
placeholders[delim]);
|
bool DisplayMessage(const QString &msg, bool question = false);
|
||||||
text.erase(0, pos + delim.length());
|
void addSelectionEntry(QComboBox *sel, const char *description,
|
||||||
}
|
bool selectable = false, const char *tooltip = "");
|
||||||
delim = getNextDelim(text, placeholders);
|
void populateTransitionSelection(QComboBox *sel, bool addCurrent = true,
|
||||||
}
|
bool addSelect = true,
|
||||||
|
bool selectable = false);
|
||||||
if (text != "") {
|
void populateWindowSelection(QComboBox *sel, bool addSelect = true);
|
||||||
labelsWidgetsPairs.emplace_back(text, nullptr);
|
void populateAudioSelection(QComboBox *sel, bool addSelect = true);
|
||||||
}
|
void populateVideoSelection(QComboBox *sel, bool addSelect = true);
|
||||||
|
void populateMediaSelection(QComboBox *sel, bool addSelect = true);
|
||||||
for (auto &lw : labelsWidgetsPairs) {
|
void populateProcessSelection(QComboBox *sel, bool addSelect = true);
|
||||||
if (lw.first != "") {
|
void populateSourceSelection(QComboBox *list, bool addSelect = true);
|
||||||
layout->addWidget(new QLabel(lw.first.c_str()));
|
void populateSceneSelection(QComboBox *sel, bool addPrevious = false,
|
||||||
}
|
bool addSceneGroup = false,
|
||||||
if (lw.second) {
|
std::deque<SceneGroup> *sceneGroups = nullptr,
|
||||||
layout->addWidget(lw.second);
|
bool addSelect = true, std::string selectText = "",
|
||||||
}
|
bool selectable = false);
|
||||||
}
|
|
||||||
if (addStretch) {
|
|
||||||
layout->addStretch();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void clearLayout(QLayout *layout)
|
|
||||||
{
|
|
||||||
QLayoutItem *item;
|
|
||||||
while ((item = layout->takeAt(0))) {
|
|
||||||
if (item->layout()) {
|
|
||||||
clearLayout(item->layout());
|
|
||||||
delete item->layout();
|
|
||||||
}
|
|
||||||
if (item->widget()) {
|
|
||||||
delete item->widget();
|
|
||||||
}
|
|
||||||
delete item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool compareIgnoringLineEnding(QString &s1, QString &s2)
|
|
||||||
{
|
|
||||||
// Let QT deal with different types of lineendings
|
|
||||||
QTextStream s1stream(&s1);
|
|
||||||
QTextStream s2stream(&s2);
|
|
||||||
|
|
||||||
while (!s1stream.atEnd() || !s2stream.atEnd()) {
|
|
||||||
QString s1s = s1stream.readLine();
|
|
||||||
QString s2s = s2stream.readLine();
|
|
||||||
if (s1s != s2s) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!s1stream.atEnd() && !s2stream.atEnd()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool DisplayMessage(QString msg, bool question = false)
|
|
||||||
{
|
|
||||||
if (question) {
|
|
||||||
QMessageBox::StandardButton reply;
|
|
||||||
reply = QMessageBox::question(
|
|
||||||
nullptr, "Advanced Scene Switcher", msg,
|
|
||||||
QMessageBox::Yes | QMessageBox::No);
|
|
||||||
if (reply == QMessageBox::Yes) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
QMessageBox Msgbox;
|
|
||||||
Msgbox.setWindowTitle("Advanced Scene Switcher");
|
|
||||||
Msgbox.setText(msg);
|
|
||||||
Msgbox.exec();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -253,7 +253,7 @@ std::pair<int, int> getCursorPos()
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isMaximized(std::string &title)
|
bool isMaximized(const std::string &title)
|
||||||
{
|
{
|
||||||
if (!ewmhIsSupported())
|
if (!ewmhIsSupported())
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -302,7 +302,7 @@ bool isMaximized(std::string &title)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFullscreen(std::string &title)
|
bool isFullscreen(const std::string &title)
|
||||||
{
|
{
|
||||||
if (!ewmhIsSupported())
|
if (!ewmhIsSupported())
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
const int MacroActionAudio::id = 2;
|
const std::string MacroActionAudio::id = "audio";
|
||||||
|
|
||||||
bool MacroActionAudio::_registered = MacroActionFactory::Register(
|
bool MacroActionAudio::_registered = MacroActionFactory::Register(
|
||||||
MacroActionAudio::id,
|
MacroActionAudio::id,
|
||||||
|
|
@ -94,7 +94,7 @@ MacroActionAudioEdit::MacroActionAudioEdit(
|
||||||
_volumePercent->setSuffix("%");
|
_volumePercent->setSuffix("%");
|
||||||
|
|
||||||
populateActionSelection(_actions);
|
populateActionSelection(_actions);
|
||||||
AdvSceneSwitcher::populateAudioSelection(_audioSources);
|
populateAudioSelection(_audioSources);
|
||||||
|
|
||||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(ActionChanged(int)));
|
SLOT(ActionChanged(int)));
|
||||||
|
|
@ -130,17 +130,8 @@ bool hasSourceControl(AudioAction action)
|
||||||
return action != AudioAction::MASTER_VOLUME;
|
return action != AudioAction::MASTER_VOLUME;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionAudioEdit::UpdateEntryData()
|
void MacroActionAudioEdit::SetWidgetVisibility()
|
||||||
{
|
{
|
||||||
if (!_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_audioSources->setCurrentText(
|
|
||||||
GetWeakSourceName(_entryData->_audioSource).c_str());
|
|
||||||
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
|
||||||
_volumePercent->setValue(_entryData->_volume);
|
|
||||||
|
|
||||||
if (hasVolumeControl(_entryData->_action)) {
|
if (hasVolumeControl(_entryData->_action)) {
|
||||||
_volumePercent->show();
|
_volumePercent->show();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -154,6 +145,20 @@ void MacroActionAudioEdit::UpdateEntryData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroActionAudioEdit::UpdateEntryData()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_audioSources->setCurrentText(
|
||||||
|
GetWeakSourceName(_entryData->_audioSource).c_str());
|
||||||
|
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||||
|
_volumePercent->setValue(_entryData->_volume);
|
||||||
|
|
||||||
|
SetWidgetVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
void MacroActionAudioEdit::SourceChanged(const QString &text)
|
void MacroActionAudioEdit::SourceChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (_loading || !_entryData) {
|
if (_loading || !_entryData) {
|
||||||
|
|
@ -172,7 +177,7 @@ void MacroActionAudioEdit::ActionChanged(int value)
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
_entryData->_action = static_cast<AudioAction>(value);
|
_entryData->_action = static_cast<AudioAction>(value);
|
||||||
UpdateEntryData();
|
SetWidgetVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionAudioEdit::VolumeChanged(int value)
|
void MacroActionAudioEdit::VolumeChanged(int value)
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
#include "headers/macro-action-edit.hpp"
|
#include "headers/macro-action-edit.hpp"
|
||||||
#include "headers/macro-action-switch-scene.hpp"
|
#include "headers/macro-action-scene-switch.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
std::map<int, MacroActionInfo> MacroActionFactory::_methods;
|
std::map<std::string, MacroActionInfo> MacroActionFactory::_methods;
|
||||||
|
|
||||||
bool MacroActionFactory::Register(int id, MacroActionInfo info)
|
bool MacroActionFactory::Register(const std::string &id, MacroActionInfo info)
|
||||||
{
|
{
|
||||||
if (auto it = _methods.find(id); it == _methods.end()) {
|
if (auto it = _methods.find(id); it == _methods.end()) {
|
||||||
_methods[id] = info;
|
_methods[id] = info;
|
||||||
|
|
@ -14,7 +14,7 @@ bool MacroActionFactory::Register(int id, MacroActionInfo info)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MacroAction> MacroActionFactory::Create(const int id)
|
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id)
|
||||||
{
|
{
|
||||||
if (auto it = _methods.find(id); it != _methods.end())
|
if (auto it = _methods.find(id); it != _methods.end())
|
||||||
return it->second._createFunc();
|
return it->second._createFunc();
|
||||||
|
|
@ -22,7 +22,8 @@ std::shared_ptr<MacroAction> MacroActionFactory::Create(const int id)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *MacroActionFactory::CreateWidget(const int id, QWidget *parent,
|
QWidget *MacroActionFactory::CreateWidget(const std::string &id,
|
||||||
|
QWidget *parent,
|
||||||
std::shared_ptr<MacroAction> action)
|
std::shared_ptr<MacroAction> action)
|
||||||
{
|
{
|
||||||
if (auto it = _methods.find(id); it != _methods.end())
|
if (auto it = _methods.find(id); it != _methods.end())
|
||||||
|
|
@ -31,6 +32,24 @@ QWidget *MacroActionFactory::CreateWidget(const int id, QWidget *parent,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string MacroActionFactory::GetActionName(const std::string &id)
|
||||||
|
{
|
||||||
|
if (auto it = _methods.find(id); it != _methods.end()) {
|
||||||
|
return it->second._name;
|
||||||
|
}
|
||||||
|
return "unknown action";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MacroActionFactory::GetIdByName(const QString &name)
|
||||||
|
{
|
||||||
|
for (auto it : _methods) {
|
||||||
|
if (name == obs_module_text(it.second._name.c_str())) {
|
||||||
|
return it.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
static inline void populateActionSelection(QComboBox *list)
|
static inline void populateActionSelection(QComboBox *list)
|
||||||
{
|
{
|
||||||
for (auto entry : MacroActionFactory::GetActionTypes()) {
|
for (auto entry : MacroActionFactory::GetActionTypes()) {
|
||||||
|
|
@ -40,14 +59,15 @@ static inline void populateActionSelection(QComboBox *list)
|
||||||
|
|
||||||
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||||
std::shared_ptr<MacroAction> *entryData,
|
std::shared_ptr<MacroAction> *entryData,
|
||||||
int type, bool startCollapsed)
|
const std::string &id, bool startCollapsed)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
_actionSelection = new QComboBox();
|
_actionSelection = new QComboBox();
|
||||||
_section = new Section(300);
|
_section = new Section(300);
|
||||||
|
|
||||||
QWidget::connect(_actionSelection, SIGNAL(currentIndexChanged(int)),
|
QWidget::connect(_actionSelection,
|
||||||
this, SLOT(ActionSelectionChanged(int)));
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
|
SLOT(ActionSelectionChanged(const QString &)));
|
||||||
|
|
||||||
populateActionSelection(_actionSelection);
|
populateActionSelection(_actionSelection);
|
||||||
|
|
||||||
|
|
@ -58,38 +78,34 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
UpdateEntryData(type);
|
UpdateEntryData(id, startCollapsed);
|
||||||
|
|
||||||
_loading = false;
|
_loading = false;
|
||||||
_section->Collapse(startCollapsed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionEdit::ActionSelectionChanged(int idx)
|
void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||||
{
|
{
|
||||||
if (_loading || !_entryData) {
|
if (_loading || !_entryData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string id = MacroActionFactory::GetIdByName(text);
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
_entryData->reset();
|
_entryData->reset();
|
||||||
*_entryData = MacroActionFactory::Create(idx);
|
*_entryData = MacroActionFactory::Create(id);
|
||||||
auto widget =
|
auto widget =
|
||||||
MacroActionFactory::CreateWidget(idx, window(), *_entryData);
|
MacroActionFactory::CreateWidget(id, window(), *_entryData);
|
||||||
_section->SetContent(widget);
|
_section->SetContent(widget, false);
|
||||||
_section->Collapse(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroActionEdit::UpdateEntryData(int type)
|
void MacroActionEdit::UpdateEntryData(const std::string &id, bool collapse)
|
||||||
{
|
{
|
||||||
_actionSelection->setCurrentIndex(type);
|
_actionSelection->setCurrentText(
|
||||||
|
obs_module_text(MacroActionFactory::GetActionName(id).c_str()));
|
||||||
auto widget =
|
auto widget =
|
||||||
MacroActionFactory::CreateWidget(type, window(), *_entryData);
|
MacroActionFactory::CreateWidget(id, window(), *_entryData);
|
||||||
_section->SetContent(widget);
|
_section->SetContent(widget, collapse);
|
||||||
}
|
|
||||||
|
|
||||||
void MacroActionEdit::Collapse(bool collapsed)
|
|
||||||
{
|
|
||||||
_section->Collapse(collapsed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_actionAdd_clicked()
|
void AdvSceneSwitcher::on_actionAdd_clicked()
|
||||||
|
|
@ -98,12 +114,16 @@ void AdvSceneSwitcher::on_actionAdd_clicked()
|
||||||
if (!macro) {
|
if (!macro) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MacroActionSwitchScene temp;
|
||||||
|
std::string id = temp.GetId();
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
macro->Actions().emplace_back(MacroActionFactory::Create(0));
|
macro->Actions().emplace_back(MacroActionFactory::Create(id));
|
||||||
auto newEntry = new MacroActionEdit(this, ¯o->Actions().back(), 0);
|
auto newEntry =
|
||||||
|
new MacroActionEdit(this, ¯o->Actions().back(), id, false);
|
||||||
ui->macroEditActionLayout->addWidget(newEntry);
|
ui->macroEditActionLayout->addWidget(newEntry);
|
||||||
ui->macroEditActionHelp->setVisible(false);
|
ui->macroEditActionHelp->setVisible(false);
|
||||||
newEntry->Collapse(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_actionRemove_clicked()
|
void AdvSceneSwitcher::on_actionRemove_clicked()
|
||||||
|
|
|
||||||
203
src/macro-action-filter.cpp
Normal file
203
src/macro-action-filter.cpp
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
#include "headers/macro-action-filter.hpp"
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
const std::string MacroActionFilter::id = "filter";
|
||||||
|
|
||||||
|
bool MacroActionFilter::_registered = MacroActionFactory::Register(
|
||||||
|
MacroActionFilter::id,
|
||||||
|
{MacroActionFilter::Create, MacroActionFilterEdit::Create,
|
||||||
|
"AdvSceneSwitcher.action.filter"});
|
||||||
|
|
||||||
|
const static std::map<FilterAction, std::string> actionTypes = {
|
||||||
|
{FilterAction::ENABLE, "AdvSceneSwitcher.action.filter.type.enable"},
|
||||||
|
{FilterAction::DISABLE, "AdvSceneSwitcher.action.filter.type.disable"},
|
||||||
|
};
|
||||||
|
|
||||||
|
bool MacroActionFilter::PerformAction()
|
||||||
|
{
|
||||||
|
auto s = obs_weak_source_get_source(_filter);
|
||||||
|
switch (_action) {
|
||||||
|
case FilterAction::ENABLE:
|
||||||
|
obs_source_set_enabled(s, true);
|
||||||
|
break;
|
||||||
|
case FilterAction::DISABLE:
|
||||||
|
obs_source_set_enabled(s, false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
obs_source_release(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionFilter::LogAction()
|
||||||
|
{
|
||||||
|
auto it = actionTypes.find(_action);
|
||||||
|
if (it != actionTypes.end()) {
|
||||||
|
vblog(LOG_INFO,
|
||||||
|
"performed action \"%s\" for filter \"%s\" on source \"%s\"",
|
||||||
|
it->second.c_str(), GetWeakSourceName(_filter).c_str(),
|
||||||
|
GetWeakSourceName(_source).c_str());
|
||||||
|
} else {
|
||||||
|
blog(LOG_WARNING, "ignored unknown filter action %d",
|
||||||
|
static_cast<int>(_action));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionFilter::Save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroAction::Save(obj);
|
||||||
|
obs_data_set_string(obj, "source", GetWeakSourceName(_source).c_str());
|
||||||
|
obs_data_set_string(obj, "filter", GetWeakSourceName(_filter).c_str());
|
||||||
|
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionFilter::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroAction::Load(obj);
|
||||||
|
const char *sourceName = obs_data_get_string(obj, "source");
|
||||||
|
_source = GetWeakSourceByName(sourceName);
|
||||||
|
const char *filterName = obs_data_get_string(obj, "filter");
|
||||||
|
_filter = GetWeakFilterByQString(_source, filterName);
|
||||||
|
_action = static_cast<FilterAction>(obs_data_get_int(obj, "action"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void populateActionSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
for (auto entry : actionTypes) {
|
||||||
|
list->addItem(obs_module_text(entry.second.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void populateFilters(QComboBox *list,
|
||||||
|
OBSWeakSource weakSource = nullptr)
|
||||||
|
{
|
||||||
|
auto enumFilters = [](obs_source_t *, obs_source_t *filter, void *ptr) {
|
||||||
|
QComboBox *list = reinterpret_cast<QComboBox *>(ptr);
|
||||||
|
auto name = obs_source_get_name(filter);
|
||||||
|
list->addItem(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto s = obs_weak_source_get_source(weakSource);
|
||||||
|
obs_source_enum_filters(s, enumFilters, list);
|
||||||
|
list->model()->sort(0);
|
||||||
|
addSelectionEntry(list,
|
||||||
|
obs_module_text("AdvSceneSwitcher.selectFilter"));
|
||||||
|
obs_source_release(s);
|
||||||
|
list->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void hasFilterEnum(obs_source_t *, obs_source_t *filter,
|
||||||
|
void *ptr)
|
||||||
|
{
|
||||||
|
if (!filter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool *hasFilter = reinterpret_cast<bool *>(ptr);
|
||||||
|
*hasFilter = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void populateSourcesWithFilter(QComboBox *list)
|
||||||
|
{
|
||||||
|
auto enumSourcesWithFilters = [](void *param, obs_source_t *source) {
|
||||||
|
if (!source) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
QComboBox *list = reinterpret_cast<QComboBox *>(param);
|
||||||
|
bool hasFilter = false;
|
||||||
|
obs_source_enum_filters(source, hasFilterEnum, &hasFilter);
|
||||||
|
if (hasFilter) {
|
||||||
|
list->addItem(obs_source_get_name(source));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
obs_enum_sources(enumSourcesWithFilters, list);
|
||||||
|
obs_enum_scenes(enumSourcesWithFilters, list);
|
||||||
|
list->model()->sort(0);
|
||||||
|
addSelectionEntry(list,
|
||||||
|
obs_module_text("AdvSceneSwitcher.selectSource"));
|
||||||
|
list->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroActionFilterEdit::MacroActionFilterEdit(
|
||||||
|
QWidget *parent, std::shared_ptr<MacroActionFilter> entryData)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
_sources = new QComboBox();
|
||||||
|
_filters = new QComboBox();
|
||||||
|
_actions = new QComboBox();
|
||||||
|
|
||||||
|
populateActionSelection(_actions);
|
||||||
|
populateSourcesWithFilter(_sources);
|
||||||
|
|
||||||
|
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ActionChanged(int)));
|
||||||
|
QWidget::connect(_sources, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(SourceChanged(const QString &)));
|
||||||
|
QWidget::connect(_filters, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(FilterChanged(const QString &)));
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{sources}}", _sources},
|
||||||
|
{"{{filters}}", _filters},
|
||||||
|
{"{{actions}}", _actions},
|
||||||
|
};
|
||||||
|
placeWidgets(obs_module_text("AdvSceneSwitcher.action.filter.entry"),
|
||||||
|
mainLayout, widgetPlaceholders);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
_entryData = entryData;
|
||||||
|
UpdateEntryData();
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionFilterEdit::UpdateEntryData()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||||
|
_sources->setCurrentText(
|
||||||
|
GetWeakSourceName(_entryData->_source).c_str());
|
||||||
|
populateFilters(_filters, _entryData->_source);
|
||||||
|
_filters->setCurrentText(
|
||||||
|
GetWeakSourceName(_entryData->_filter).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionFilterEdit::SourceChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_source = GetWeakSourceByQString(text);
|
||||||
|
}
|
||||||
|
_filters->clear();
|
||||||
|
populateFilters(_filters, _entryData->_source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionFilterEdit::FilterChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_filter = GetWeakFilterByQString(_entryData->_source, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionFilterEdit::ActionChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_action = static_cast<FilterAction>(value);
|
||||||
|
}
|
||||||
152
src/macro-action-macro.cpp
Normal file
152
src/macro-action-macro.cpp
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
#include "headers/macro-action-macro.hpp"
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
const std::string MacroActionMacro::id = "macro";
|
||||||
|
|
||||||
|
bool MacroActionMacro::_registered = MacroActionFactory::Register(
|
||||||
|
MacroActionMacro::id,
|
||||||
|
{MacroActionMacro::Create, MacroActionMacroEdit::Create,
|
||||||
|
"AdvSceneSwitcher.action.macro"});
|
||||||
|
|
||||||
|
const static std::map<PerformMacroAction, std::string> actionTypes = {
|
||||||
|
{PerformMacroAction::PAUSE, "AdvSceneSwitcher.action.macro.type.pause"},
|
||||||
|
{PerformMacroAction::UNPAUSE,
|
||||||
|
"AdvSceneSwitcher.action.macro.type.unpause"},
|
||||||
|
{PerformMacroAction::RESET_COUNTER,
|
||||||
|
"AdvSceneSwitcher.action.macro.type.resetCounter"},
|
||||||
|
};
|
||||||
|
|
||||||
|
bool MacroActionMacro::PerformAction()
|
||||||
|
{
|
||||||
|
if (!_macro.get()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_action) {
|
||||||
|
case PerformMacroAction::PAUSE:
|
||||||
|
_macro->SetPaused();
|
||||||
|
break;
|
||||||
|
case PerformMacroAction::UNPAUSE:
|
||||||
|
_macro->SetPaused(false);
|
||||||
|
break;
|
||||||
|
case PerformMacroAction::RESET_COUNTER:
|
||||||
|
_macro->ResetCount();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMacro::LogAction()
|
||||||
|
{
|
||||||
|
if (!_macro.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (_action) {
|
||||||
|
case PerformMacroAction::PAUSE:
|
||||||
|
vblog(LOG_INFO, "paused \"%s\"", _macro->Name().c_str());
|
||||||
|
break;
|
||||||
|
case PerformMacroAction::UNPAUSE:
|
||||||
|
vblog(LOG_INFO, "unpaused \"%s\"", _macro->Name().c_str());
|
||||||
|
break;
|
||||||
|
case PerformMacroAction::RESET_COUNTER:
|
||||||
|
vblog(LOG_INFO, "reset counter for \"%s\"",
|
||||||
|
_macro->Name().c_str());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionMacro::Save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroAction::Save(obj);
|
||||||
|
_macro.Save(obj);
|
||||||
|
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionMacro::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroAction::Load(obj);
|
||||||
|
_macro.Load(obj);
|
||||||
|
_action = static_cast<PerformMacroAction>(
|
||||||
|
obs_data_get_int(obj, "action"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void populateActionSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
for (auto entry : actionTypes) {
|
||||||
|
list->addItem(obs_module_text(entry.second.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroActionMacroEdit::MacroActionMacroEdit(
|
||||||
|
QWidget *parent, std::shared_ptr<MacroActionMacro> entryData)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
_macros = new MacroSelection(parent);
|
||||||
|
_actions = new QComboBox();
|
||||||
|
|
||||||
|
populateActionSelection(_actions);
|
||||||
|
|
||||||
|
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(MacroChanged(const QString &)));
|
||||||
|
QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this,
|
||||||
|
SLOT(MacroRemove(const QString &)));
|
||||||
|
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ActionChanged(int)));
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{actions}}", _actions},
|
||||||
|
{"{{macros}}", _macros},
|
||||||
|
};
|
||||||
|
placeWidgets(obs_module_text("AdvSceneSwitcher.action.macro.entry"),
|
||||||
|
mainLayout, widgetPlaceholders);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
_entryData = entryData;
|
||||||
|
UpdateEntryData();
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMacroEdit::UpdateEntryData()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||||
|
_macros->SetCurrentMacro(_entryData->_macro.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMacroEdit::MacroChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_macro.UpdateRef(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMacroEdit::ActionChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_action = static_cast<PerformMacroAction>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMacroEdit::MacroRemove(const QString &name)
|
||||||
|
{
|
||||||
|
UNUSED_PARAMETER(name);
|
||||||
|
if (_entryData) {
|
||||||
|
_entryData->_macro.UpdateRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
153
src/macro-action-media.cpp
Normal file
153
src/macro-action-media.cpp
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
#include "headers/macro-action-media.hpp"
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
const std::string MacroActionMedia::id = "media";
|
||||||
|
|
||||||
|
bool MacroActionMedia::_registered = MacroActionFactory::Register(
|
||||||
|
MacroActionMedia::id,
|
||||||
|
{MacroActionMedia::Create, MacroActionMediaEdit::Create,
|
||||||
|
"AdvSceneSwitcher.action.media"});
|
||||||
|
|
||||||
|
const static std::map<MediaAction, std::string> actionTypes = {
|
||||||
|
{MediaAction::PLAY, "AdvSceneSwitcher.action.media.type.play"},
|
||||||
|
{MediaAction::PAUSE, "AdvSceneSwitcher.action.media.type.pause"},
|
||||||
|
{MediaAction::STOP, "AdvSceneSwitcher.action.media.type.stop"},
|
||||||
|
{MediaAction::RESTART, "AdvSceneSwitcher.action.media.type.restart"},
|
||||||
|
{MediaAction::NEXT, "AdvSceneSwitcher.action.media.type.next"},
|
||||||
|
{MediaAction::PREVIOUS, "AdvSceneSwitcher.action.media.type.previous"},
|
||||||
|
};
|
||||||
|
|
||||||
|
bool MacroActionMedia::PerformAction()
|
||||||
|
{
|
||||||
|
auto source = obs_weak_source_get_source(_mediaSource);
|
||||||
|
obs_media_state state = obs_source_media_get_state(source);
|
||||||
|
switch (_action) {
|
||||||
|
case MediaAction::PLAY:
|
||||||
|
if (state == OBS_MEDIA_STATE_STOPPED ||
|
||||||
|
state == OBS_MEDIA_STATE_ENDED) {
|
||||||
|
obs_source_media_restart(source);
|
||||||
|
} else {
|
||||||
|
obs_source_media_play_pause(source, false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MediaAction::PAUSE:
|
||||||
|
obs_source_media_play_pause(source, true);
|
||||||
|
break;
|
||||||
|
case MediaAction::STOP:
|
||||||
|
obs_source_media_stop(source);
|
||||||
|
break;
|
||||||
|
case MediaAction::RESTART:
|
||||||
|
obs_source_media_restart(source);
|
||||||
|
break;
|
||||||
|
case MediaAction::NEXT:
|
||||||
|
obs_source_media_next(source);
|
||||||
|
break;
|
||||||
|
case MediaAction::PREVIOUS:
|
||||||
|
obs_source_media_previous(source);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
obs_source_release(source);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMedia::LogAction()
|
||||||
|
{
|
||||||
|
auto it = actionTypes.find(_action);
|
||||||
|
if (it != actionTypes.end()) {
|
||||||
|
vblog(LOG_INFO, "performed action \"%s\" for source \"%s\"",
|
||||||
|
it->second.c_str(),
|
||||||
|
GetWeakSourceName(_mediaSource).c_str());
|
||||||
|
} else {
|
||||||
|
blog(LOG_WARNING, "ignored unknown media action %d",
|
||||||
|
static_cast<int>(_action));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionMedia::Save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroAction::Save(obj);
|
||||||
|
obs_data_set_string(obj, "mediaSource",
|
||||||
|
GetWeakSourceName(_mediaSource).c_str());
|
||||||
|
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionMedia::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroAction::Load(obj);
|
||||||
|
const char *MediaSourceName = obs_data_get_string(obj, "mediaSource");
|
||||||
|
_mediaSource = GetWeakSourceByName(MediaSourceName);
|
||||||
|
_action = static_cast<MediaAction>(obs_data_get_int(obj, "action"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void populateActionSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
for (auto entry : actionTypes) {
|
||||||
|
list->addItem(obs_module_text(entry.second.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroActionMediaEdit::MacroActionMediaEdit(
|
||||||
|
QWidget *parent, std::shared_ptr<MacroActionMedia> entryData)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
_mediaSources = new QComboBox();
|
||||||
|
_actions = new QComboBox();
|
||||||
|
|
||||||
|
populateActionSelection(_actions);
|
||||||
|
populateMediaSelection(_mediaSources);
|
||||||
|
|
||||||
|
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ActionChanged(int)));
|
||||||
|
QWidget::connect(_mediaSources,
|
||||||
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
|
SLOT(SourceChanged(const QString &)));
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{mediaSources}}", _mediaSources},
|
||||||
|
{"{{actions}}", _actions},
|
||||||
|
};
|
||||||
|
placeWidgets(obs_module_text("AdvSceneSwitcher.action.media.entry"),
|
||||||
|
mainLayout, widgetPlaceholders);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
_entryData = entryData;
|
||||||
|
UpdateEntryData();
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMediaEdit::UpdateEntryData()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_mediaSources->setCurrentText(
|
||||||
|
GetWeakSourceName(_entryData->_mediaSource).c_str());
|
||||||
|
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMediaEdit::SourceChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_mediaSource = GetWeakSourceByQString(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionMediaEdit::ActionChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_action = static_cast<MediaAction>(value);
|
||||||
|
}
|
||||||
114
src/macro-action-plugin-state.cpp
Normal file
114
src/macro-action-plugin-state.cpp
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
#include "headers/macro-action-plugin-state.hpp"
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
const std::string MacroActionPluginState::id = "plugin_state";
|
||||||
|
|
||||||
|
bool MacroActionPluginState::_registered = MacroActionFactory::Register(
|
||||||
|
MacroActionPluginState::id,
|
||||||
|
{MacroActionPluginState::Create, MacroActionPluginStateEdit::Create,
|
||||||
|
"AdvSceneSwitcher.action.PluginState"});
|
||||||
|
|
||||||
|
const static std::map<PluginStateAction, std::string> actionTypes = {
|
||||||
|
{PluginStateAction::STOP,
|
||||||
|
"AdvSceneSwitcher.action.pluginState.type.stop"},
|
||||||
|
};
|
||||||
|
|
||||||
|
void stopPlugin()
|
||||||
|
{
|
||||||
|
std::thread t([]() { switcher->Stop(); });
|
||||||
|
t.detach();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionPluginState::PerformAction()
|
||||||
|
{
|
||||||
|
switch (_action) {
|
||||||
|
case PluginStateAction::STOP:
|
||||||
|
stopPlugin();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionPluginState::LogAction()
|
||||||
|
{
|
||||||
|
auto it = actionTypes.find(_action);
|
||||||
|
switch (_action) {
|
||||||
|
case PluginStateAction::STOP:
|
||||||
|
blog(LOG_INFO, "stop() called by macro", it->second.c_str());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
blog(LOG_WARNING, "ignored unknown pluginState action %d",
|
||||||
|
static_cast<int>(_action));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionPluginState::Save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroAction::Save(obj);
|
||||||
|
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionPluginState::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroAction::Load(obj);
|
||||||
|
_action =
|
||||||
|
static_cast<PluginStateAction>(obs_data_get_int(obj, "action"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void populateActionSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
for (auto entry : actionTypes) {
|
||||||
|
list->addItem(obs_module_text(entry.second.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroActionPluginStateEdit::MacroActionPluginStateEdit(
|
||||||
|
QWidget *parent, std::shared_ptr<MacroActionPluginState> entryData)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
_actions = new QComboBox();
|
||||||
|
|
||||||
|
populateActionSelection(_actions);
|
||||||
|
|
||||||
|
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ActionChanged(int)));
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{actions}}", _actions},
|
||||||
|
};
|
||||||
|
placeWidgets(
|
||||||
|
obs_module_text("AdvSceneSwitcher.action.pluginState.entry"),
|
||||||
|
mainLayout, widgetPlaceholders);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
_entryData = entryData;
|
||||||
|
UpdateEntryData();
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionPluginStateEdit::UpdateEntryData()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionPluginStateEdit::ActionChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_action = static_cast<PluginStateAction>(value);
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
const int MacroActionRecord::id = 4;
|
const std::string MacroActionRecord::id = "recording";
|
||||||
|
|
||||||
bool MacroActionRecord::_registered = MacroActionFactory::Register(
|
bool MacroActionRecord::_registered = MacroActionFactory::Register(
|
||||||
MacroActionRecord::id,
|
MacroActionRecord::id,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
const int MacroActionReplayBuffer::id = 5;
|
const std::string MacroActionReplayBuffer::id = "replay_buffer";
|
||||||
|
|
||||||
bool MacroActionReplayBuffer::_registered = MacroActionFactory::Register(
|
bool MacroActionReplayBuffer::_registered = MacroActionFactory::Register(
|
||||||
MacroActionReplayBuffer::id,
|
MacroActionReplayBuffer::id,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
|
||||||
const int MacroActionRun::id = 6;
|
const std::string MacroActionRun::id = "run";
|
||||||
|
|
||||||
bool MacroActionRun::_registered = MacroActionFactory::Register(
|
bool MacroActionRun::_registered = MacroActionFactory::Register(
|
||||||
MacroActionRun::id, {MacroActionRun::Create, MacroActionRunEdit::Create,
|
MacroActionRun::id, {MacroActionRun::Create, MacroActionRunEdit::Create,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#include "headers/macro-action-switch-scene.hpp"
|
#include "headers/macro-action-scene-switch.hpp"
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
const int MacroActionSwitchScene::id = 0;
|
const std::string MacroActionSwitchScene::id = "scene_switch";
|
||||||
|
|
||||||
bool MacroActionSwitchScene::_registered = MacroActionFactory::Register(
|
bool MacroActionSwitchScene::_registered = MacroActionFactory::Register(
|
||||||
MacroActionSwitchScene::id,
|
MacroActionSwitchScene::id,
|
||||||
212
src/macro-action-scene-visibility.cpp
Normal file
212
src/macro-action-scene-visibility.cpp
Normal file
|
|
@ -0,0 +1,212 @@
|
||||||
|
#include "headers/macro-action-scene-visibility.hpp"
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
const std::string MacroActionSceneVisibility::id = "scene_visibility";
|
||||||
|
|
||||||
|
bool MacroActionSceneVisibility::_registered = MacroActionFactory::Register(
|
||||||
|
MacroActionSceneVisibility::id,
|
||||||
|
{MacroActionSceneVisibility::Create,
|
||||||
|
MacroActionSceneVisibilityEdit::Create,
|
||||||
|
"AdvSceneSwitcher.action.sceneVisibility"});
|
||||||
|
|
||||||
|
const static std::map<SceneVisibilityAction, std::string> actionTypes = {
|
||||||
|
{SceneVisibilityAction::SHOW,
|
||||||
|
"AdvSceneSwitcher.action.sceneVisibility.type.show"},
|
||||||
|
{SceneVisibilityAction::HIDE,
|
||||||
|
"AdvSceneSwitcher.action.sceneVisibility.type.hide"},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VisInfo {
|
||||||
|
std::string name;
|
||||||
|
bool visible;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool visibilityEnum(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
|
||||||
|
{
|
||||||
|
VisInfo *vInfo = reinterpret_cast<VisInfo *>(ptr);
|
||||||
|
auto sourceName = obs_source_get_name(obs_sceneitem_get_source(item));
|
||||||
|
if (vInfo->name == sourceName) {
|
||||||
|
obs_sceneitem_set_visible(item, vInfo->visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obs_sceneitem_is_group(item)) {
|
||||||
|
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
|
||||||
|
obs_scene_enum_items(scene, visibilityEnum, ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionSceneVisibility::PerformAction()
|
||||||
|
{
|
||||||
|
auto s = obs_weak_source_get_source(_scene);
|
||||||
|
auto scene = obs_scene_from_source(s);
|
||||||
|
auto sourceName = GetWeakSourceName(_source);
|
||||||
|
VisInfo vInfo = {sourceName, _action == SceneVisibilityAction::SHOW};
|
||||||
|
|
||||||
|
switch (_action) {
|
||||||
|
case SceneVisibilityAction::SHOW:
|
||||||
|
obs_scene_enum_items(scene, visibilityEnum, &vInfo);
|
||||||
|
break;
|
||||||
|
case SceneVisibilityAction::HIDE:
|
||||||
|
obs_scene_enum_items(scene, visibilityEnum, &vInfo);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
obs_source_release(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSceneVisibility::LogAction()
|
||||||
|
{
|
||||||
|
auto it = actionTypes.find(_action);
|
||||||
|
if (it != actionTypes.end()) {
|
||||||
|
vblog(LOG_INFO,
|
||||||
|
"performed action \"%s\" for source \"%s\" on scene \"%s\"",
|
||||||
|
it->second.c_str(), GetWeakSourceName(_scene).c_str(),
|
||||||
|
GetWeakSourceName(_scene).c_str());
|
||||||
|
} else {
|
||||||
|
blog(LOG_WARNING, "ignored unknown SceneVisibility action %d",
|
||||||
|
static_cast<int>(_action));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionSceneVisibility::Save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroAction::Save(obj);
|
||||||
|
obs_data_set_string(obj, "scene", GetWeakSourceName(_scene).c_str());
|
||||||
|
obs_data_set_string(obj, "source", GetWeakSourceName(_source).c_str());
|
||||||
|
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionSceneVisibility::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroAction::Load(obj);
|
||||||
|
const char *sceneName = obs_data_get_string(obj, "scene");
|
||||||
|
_scene = GetWeakSourceByName(sceneName);
|
||||||
|
const char *sourceName = obs_data_get_string(obj, "source");
|
||||||
|
_source = GetWeakSourceByName(sourceName);
|
||||||
|
_action = static_cast<SceneVisibilityAction>(
|
||||||
|
obs_data_get_int(obj, "action"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void populateActionSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
for (auto entry : actionTypes) {
|
||||||
|
list->addItem(obs_module_text(entry.second.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool enumItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
|
||||||
|
{
|
||||||
|
std::set<QString> *names = reinterpret_cast<std::set<QString> *>(ptr);
|
||||||
|
|
||||||
|
if (obs_sceneitem_is_group(item)) {
|
||||||
|
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
|
||||||
|
obs_scene_enum_items(scene, enumItem, ptr);
|
||||||
|
}
|
||||||
|
auto name = obs_source_get_name(obs_sceneitem_get_source(item));
|
||||||
|
names->emplace(name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void populateSceneItems(QComboBox *list,
|
||||||
|
OBSWeakSource sceneWeakSource = nullptr)
|
||||||
|
{
|
||||||
|
std::set<QString> names;
|
||||||
|
auto s = obs_weak_source_get_source(sceneWeakSource);
|
||||||
|
auto scene = obs_scene_from_source(s);
|
||||||
|
obs_scene_enum_items(scene, enumItem, &names);
|
||||||
|
obs_source_release(s);
|
||||||
|
|
||||||
|
for (auto &name : names) {
|
||||||
|
list->addItem(name);
|
||||||
|
}
|
||||||
|
list->model()->sort(0);
|
||||||
|
addSelectionEntry(list, obs_module_text("AdvSceneSwitcher.selectItem"));
|
||||||
|
list->setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroActionSceneVisibilityEdit::MacroActionSceneVisibilityEdit(
|
||||||
|
QWidget *parent, std::shared_ptr<MacroActionSceneVisibility> entryData)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
_scenes = new QComboBox();
|
||||||
|
_sources = new QComboBox();
|
||||||
|
_actions = new QComboBox();
|
||||||
|
|
||||||
|
populateActionSelection(_actions);
|
||||||
|
populateSceneSelection(_scenes);
|
||||||
|
|
||||||
|
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ActionChanged(int)));
|
||||||
|
QWidget::connect(_scenes, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(SceneChanged(const QString &)));
|
||||||
|
QWidget::connect(_sources, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(SourceChanged(const QString &)));
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{scenes}}", _scenes},
|
||||||
|
{"{{sources}}", _sources},
|
||||||
|
{"{{actions}}", _actions},
|
||||||
|
};
|
||||||
|
placeWidgets(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.action.SceneVisibility.entry"),
|
||||||
|
mainLayout, widgetPlaceholders);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
_entryData = entryData;
|
||||||
|
UpdateEntryData();
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSceneVisibilityEdit::UpdateEntryData()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||||
|
_scenes->setCurrentText(GetWeakSourceName(_entryData->_scene).c_str());
|
||||||
|
populateSceneItems(_sources, _entryData->_scene);
|
||||||
|
_sources->setCurrentText(
|
||||||
|
GetWeakSourceName(_entryData->_source).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSceneVisibilityEdit::SceneChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_scene = GetWeakSourceByQString(text);
|
||||||
|
}
|
||||||
|
_sources->clear();
|
||||||
|
populateSceneItems(_sources, _entryData->_scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSceneVisibilityEdit::SourceChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_source = GetWeakSourceByQString(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSceneVisibilityEdit::ActionChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_action = static_cast<SceneVisibilityAction>(value);
|
||||||
|
}
|
||||||
201
src/macro-action-source.cpp
Normal file
201
src/macro-action-source.cpp
Normal file
|
|
@ -0,0 +1,201 @@
|
||||||
|
#include "headers/macro-action-source.hpp"
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
const std::string MacroActionSource::id = "source";
|
||||||
|
|
||||||
|
bool MacroActionSource::_registered = MacroActionFactory::Register(
|
||||||
|
MacroActionSource::id,
|
||||||
|
{MacroActionSource::Create, MacroActionSourceEdit::Create,
|
||||||
|
"AdvSceneSwitcher.action.source"});
|
||||||
|
|
||||||
|
const static std::map<SourceAction, std::string> actionTypes = {
|
||||||
|
{SourceAction::ENABLE, "AdvSceneSwitcher.action.source.type.enable"},
|
||||||
|
{SourceAction::DISABLE, "AdvSceneSwitcher.action.source.type.disable"},
|
||||||
|
{SourceAction::SETTINGS,
|
||||||
|
"AdvSceneSwitcher.action.source.type.settings"},
|
||||||
|
};
|
||||||
|
|
||||||
|
void setSourceSettings(obs_source_t *s, const std::string &settings)
|
||||||
|
{
|
||||||
|
if (settings.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_data_t *data = obs_data_create_from_json(settings.c_str());
|
||||||
|
if (!data) {
|
||||||
|
blog(LOG_WARNING, "invalid source settings provided: \n%s",
|
||||||
|
settings.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
obs_source_update(s, data);
|
||||||
|
obs_data_release(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionSource::PerformAction()
|
||||||
|
{
|
||||||
|
auto s = obs_weak_source_get_source(_source);
|
||||||
|
switch (_action) {
|
||||||
|
case SourceAction::ENABLE:
|
||||||
|
obs_source_set_enabled(s, true);
|
||||||
|
break;
|
||||||
|
case SourceAction::DISABLE:
|
||||||
|
obs_source_set_enabled(s, false);
|
||||||
|
break;
|
||||||
|
case SourceAction::SETTINGS:
|
||||||
|
setSourceSettings(s, _settings);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
obs_source_release(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSource::LogAction()
|
||||||
|
{
|
||||||
|
auto it = actionTypes.find(_action);
|
||||||
|
if (it != actionTypes.end()) {
|
||||||
|
vblog(LOG_INFO, "performed action \"%s\" for Source \"%s\"",
|
||||||
|
it->second.c_str(), GetWeakSourceName(_source).c_str());
|
||||||
|
} else {
|
||||||
|
blog(LOG_WARNING, "ignored unknown source action %d",
|
||||||
|
static_cast<int>(_action));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionSource::Save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroAction::Save(obj);
|
||||||
|
obs_data_set_string(obj, "source", GetWeakSourceName(_source).c_str());
|
||||||
|
obs_data_set_int(obj, "action", static_cast<int>(_action));
|
||||||
|
obs_data_set_string(obj, "settings", _settings.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroActionSource::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroAction::Load(obj);
|
||||||
|
const char *sourceName = obs_data_get_string(obj, "source");
|
||||||
|
_source = GetWeakSourceByName(sourceName);
|
||||||
|
_action = static_cast<SourceAction>(obs_data_get_int(obj, "action"));
|
||||||
|
_settings = obs_data_get_string(obj, "settings");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void populateActionSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
for (auto entry : actionTypes) {
|
||||||
|
list->addItem(obs_module_text(entry.second.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroActionSourceEdit::MacroActionSourceEdit(
|
||||||
|
QWidget *parent, std::shared_ptr<MacroActionSource> entryData)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
_sources = new QComboBox();
|
||||||
|
_actions = new QComboBox();
|
||||||
|
_getSettings = new QPushButton(
|
||||||
|
obs_module_text("AdvSceneSwitcher.action.source.getSettings"));
|
||||||
|
_settings = new QPlainTextEdit();
|
||||||
|
_warning = new QLabel(
|
||||||
|
obs_module_text("AdvSceneSwitcher.action.source.warning"));
|
||||||
|
|
||||||
|
populateActionSelection(_actions);
|
||||||
|
populateSourceSelection(_sources);
|
||||||
|
|
||||||
|
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ActionChanged(int)));
|
||||||
|
QWidget::connect(_sources, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(SourceChanged(const QString &)));
|
||||||
|
QWidget::connect(_getSettings, SIGNAL(clicked()), this,
|
||||||
|
SLOT(GetSettingsClicked()));
|
||||||
|
QWidget::connect(_settings, SIGNAL(textChanged()), this,
|
||||||
|
SLOT(SettingsChanged()));
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
QHBoxLayout *entryLayout = new QHBoxLayout;
|
||||||
|
QHBoxLayout *buttonLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{sources}}", _sources},
|
||||||
|
{"{{actions}}", _actions},
|
||||||
|
{"{{settings}}", _settings},
|
||||||
|
{"{{getSettings}}", _getSettings},
|
||||||
|
};
|
||||||
|
placeWidgets(obs_module_text("AdvSceneSwitcher.action.source.entry"),
|
||||||
|
entryLayout, widgetPlaceholders);
|
||||||
|
mainLayout->addLayout(entryLayout);
|
||||||
|
mainLayout->addWidget(_warning);
|
||||||
|
mainLayout->addWidget(_settings);
|
||||||
|
buttonLayout->addWidget(_getSettings);
|
||||||
|
buttonLayout->addStretch();
|
||||||
|
mainLayout->addLayout(buttonLayout);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
_entryData = entryData;
|
||||||
|
UpdateEntryData();
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSourceEdit::UpdateEntryData()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
|
||||||
|
_sources->setCurrentText(
|
||||||
|
GetWeakSourceName(_entryData->_source).c_str());
|
||||||
|
_settings->setPlainText(QString::fromStdString(_entryData->_settings));
|
||||||
|
SetWidgetVisibility(_entryData->_action == SourceAction::SETTINGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSourceEdit::SourceChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_source = GetWeakSourceByQString(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSourceEdit::ActionChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_action = static_cast<SourceAction>(value);
|
||||||
|
SetWidgetVisibility(_entryData->_action == SourceAction::SETTINGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSourceEdit::GetSettingsClicked()
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData || !_entryData->_source) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_settings->setPlainText(
|
||||||
|
QString::fromStdString(getSourceSettings(_entryData->_source)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSourceEdit::SettingsChanged()
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_settings = _settings->toPlainText().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroActionSourceEdit::SetWidgetVisibility(bool showSettings)
|
||||||
|
{
|
||||||
|
_settings->setVisible(showSettings);
|
||||||
|
_getSettings->setVisible(showSettings);
|
||||||
|
_warning->setVisible(!showSettings);
|
||||||
|
adjustSize();
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
const int MacroActionStream::id = 3;
|
const std::string MacroActionStream::id = "streaming";
|
||||||
|
|
||||||
bool MacroActionStream::_registered = MacroActionFactory::Register(
|
bool MacroActionStream::_registered = MacroActionFactory::Register(
|
||||||
MacroActionStream::id,
|
MacroActionStream::id,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
const int MacroActionWait::id = 1;
|
const std::string MacroActionWait::id = "wait";
|
||||||
|
|
||||||
bool MacroActionWait::_registered = MacroActionFactory::Register(
|
bool MacroActionWait::_registered = MacroActionFactory::Register(
|
||||||
MacroActionWait::id,
|
MacroActionWait::id,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
const int MacroConditionAudio::id = 3;
|
const std::string MacroConditionAudio::id = "audio";
|
||||||
|
|
||||||
bool MacroConditionAudio::_registered = MacroConditionFactory::Register(
|
bool MacroConditionAudio::_registered = MacroConditionFactory::Register(
|
||||||
MacroConditionAudio::id,
|
MacroConditionAudio::id,
|
||||||
|
|
@ -11,8 +11,8 @@ bool MacroConditionAudio::_registered = MacroConditionFactory::Register(
|
||||||
"AdvSceneSwitcher.condition.audio"});
|
"AdvSceneSwitcher.condition.audio"});
|
||||||
|
|
||||||
static std::map<AudioCondition, std::string> audioConditionTypes = {
|
static std::map<AudioCondition, std::string> audioConditionTypes = {
|
||||||
{AudioCondition::ABOVE, "AdvSceneSwitcher.ondition.audio.state.above"},
|
{AudioCondition::ABOVE, "AdvSceneSwitcher.condition.audio.state.above"},
|
||||||
{AudioCondition::BELOW, "AdvSceneSwitcher.ondition.audio.state.below"},
|
{AudioCondition::BELOW, "AdvSceneSwitcher.condition.audio.state.below"},
|
||||||
};
|
};
|
||||||
|
|
||||||
MacroConditionAudio::~MacroConditionAudio()
|
MacroConditionAudio::~MacroConditionAudio()
|
||||||
|
|
@ -35,11 +35,7 @@ bool MacroConditionAudio::CheckCondition()
|
||||||
// Reset for next check
|
// Reset for next check
|
||||||
_peak = -std::numeric_limits<float>::infinity();
|
_peak = -std::numeric_limits<float>::infinity();
|
||||||
|
|
||||||
if (!volumeThresholdreached) {
|
return volumeThresholdreached;
|
||||||
_duration.Reset();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return _duration.DurationReached();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionAudio::Save(obs_data_t *obj)
|
bool MacroConditionAudio::Save(obs_data_t *obj)
|
||||||
|
|
@ -49,7 +45,6 @@ bool MacroConditionAudio::Save(obs_data_t *obj)
|
||||||
GetWeakSourceName(_audioSource).c_str());
|
GetWeakSourceName(_audioSource).c_str());
|
||||||
obs_data_set_int(obj, "volume", _volume);
|
obs_data_set_int(obj, "volume", _volume);
|
||||||
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
||||||
_duration.Save(obj);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,12 +70,9 @@ bool MacroConditionAudio::Load(obs_data_t *obj)
|
||||||
MacroCondition::Load(obj);
|
MacroCondition::Load(obj);
|
||||||
const char *audioSourceName = obs_data_get_string(obj, "audioSource");
|
const char *audioSourceName = obs_data_get_string(obj, "audioSource");
|
||||||
_audioSource = GetWeakSourceByName(audioSourceName);
|
_audioSource = GetWeakSourceByName(audioSourceName);
|
||||||
|
|
||||||
_volume = obs_data_get_int(obj, "volume");
|
_volume = obs_data_get_int(obj, "volume");
|
||||||
_condition =
|
_condition =
|
||||||
static_cast<AudioCondition>(obs_data_get_int(obj, "condition"));
|
static_cast<AudioCondition>(obs_data_get_int(obj, "condition"));
|
||||||
_duration.Load(obj);
|
|
||||||
|
|
||||||
_volmeter = AddVolmeterToSource(this, _audioSource);
|
_volmeter = AddVolmeterToSource(this, _audioSource);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -123,7 +115,6 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
||||||
_audioSources = new QComboBox();
|
_audioSources = new QComboBox();
|
||||||
_condition = new QComboBox();
|
_condition = new QComboBox();
|
||||||
_volume = new QSpinBox();
|
_volume = new QSpinBox();
|
||||||
_duration = new DurationSelection(parent, false);
|
|
||||||
|
|
||||||
_volume->setSuffix("%");
|
_volume->setSuffix("%");
|
||||||
_volume->setMaximum(100);
|
_volume->setMaximum(100);
|
||||||
|
|
@ -133,13 +124,11 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
||||||
SLOT(VolumeThresholdChanged(int)));
|
SLOT(VolumeThresholdChanged(int)));
|
||||||
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(ConditionChanged(int)));
|
SLOT(ConditionChanged(int)));
|
||||||
QWidget::connect(_duration, SIGNAL(DurationChanged(double)), this,
|
|
||||||
SLOT(DurationChanged(double)));
|
|
||||||
QWidget::connect(_audioSources,
|
QWidget::connect(_audioSources,
|
||||||
SIGNAL(currentTextChanged(const QString &)), this,
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
SLOT(SourceChanged(const QString &)));
|
SLOT(SourceChanged(const QString &)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateAudioSelection(_audioSources);
|
populateAudioSelection(_audioSources);
|
||||||
populateConditionSelection(_condition);
|
populateConditionSelection(_condition);
|
||||||
|
|
||||||
QHBoxLayout *switchLayout = new QHBoxLayout;
|
QHBoxLayout *switchLayout = new QHBoxLayout;
|
||||||
|
|
@ -147,7 +136,7 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
||||||
{"{{audioSources}}", _audioSources},
|
{"{{audioSources}}", _audioSources},
|
||||||
{"{{volume}}", _volume},
|
{"{{volume}}", _volume},
|
||||||
{"{{condition}}", _condition},
|
{"{{condition}}", _condition},
|
||||||
{"{{duration}}", _duration}};
|
};
|
||||||
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.audio.entry"),
|
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.audio.entry"),
|
||||||
switchLayout, widgetPlaceholders);
|
switchLayout, widgetPlaceholders);
|
||||||
|
|
||||||
|
|
@ -214,16 +203,6 @@ void MacroConditionAudioEdit::ConditionChanged(int cond)
|
||||||
_entryData->_condition = static_cast<AudioCondition>(cond);
|
_entryData->_condition = static_cast<AudioCondition>(cond);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionAudioEdit::DurationChanged(double seconds)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
_entryData->_duration.seconds = seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionAudioEdit::UpdateEntryData()
|
void MacroConditionAudioEdit::UpdateEntryData()
|
||||||
{
|
{
|
||||||
if (!_entryData) {
|
if (!_entryData) {
|
||||||
|
|
@ -234,6 +213,5 @@ void MacroConditionAudioEdit::UpdateEntryData()
|
||||||
GetWeakSourceName(_entryData->_audioSource).c_str());
|
GetWeakSourceName(_entryData->_audioSource).c_str());
|
||||||
_volume->setValue(_entryData->_volume);
|
_volume->setValue(_entryData->_volume);
|
||||||
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||||
_duration->SetDuration(_entryData->_duration);
|
|
||||||
UpdateVolmeterSource();
|
UpdateVolmeterSource();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
194
src/macro-condition-counter.cpp
Normal file
194
src/macro-condition-counter.cpp
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
#include "headers/macro-condition-edit.hpp"
|
||||||
|
#include "headers/macro-condition-counter.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
|
const std::string MacroConditionCounter::id = "counter";
|
||||||
|
|
||||||
|
bool MacroConditionCounter::_registered = MacroConditionFactory::Register(
|
||||||
|
MacroConditionCounter::id,
|
||||||
|
{MacroConditionCounter::Create, MacroConditionCounterEdit::Create,
|
||||||
|
"AdvSceneSwitcher.condition.counter"});
|
||||||
|
|
||||||
|
static std::map<CounterCondition, std::string> counterConditionTypes = {
|
||||||
|
{CounterCondition::BELOW,
|
||||||
|
"AdvSceneSwitcher.condition.counter.type.below"},
|
||||||
|
{CounterCondition::ABOVE,
|
||||||
|
"AdvSceneSwitcher.condition.counter.type.above"},
|
||||||
|
{CounterCondition::EQUAL,
|
||||||
|
"AdvSceneSwitcher.condition.counter.type.equal"},
|
||||||
|
};
|
||||||
|
|
||||||
|
bool MacroConditionCounter::CheckCondition()
|
||||||
|
{
|
||||||
|
if (!_macro.get()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_condition) {
|
||||||
|
case CounterCondition::BELOW:
|
||||||
|
return _macro->GetCount() < _count;
|
||||||
|
case CounterCondition::ABOVE:
|
||||||
|
return _macro->GetCount() > _count;
|
||||||
|
case CounterCondition::EQUAL:
|
||||||
|
return _macro->GetCount() == _count;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionCounter::Save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroCondition::Save(obj);
|
||||||
|
_macro.Save(obj);
|
||||||
|
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
||||||
|
obs_data_set_int(obj, "count", _count);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionCounter::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroCondition::Load(obj);
|
||||||
|
_macro.Load(obj);
|
||||||
|
_condition = static_cast<CounterCondition>(
|
||||||
|
obs_data_get_int(obj, "condition"));
|
||||||
|
_count = obs_data_get_int(obj, "count");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void populateConditionSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
for (auto entry : counterConditionTypes) {
|
||||||
|
list->addItem(obs_module_text(entry.second.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroConditionCounterEdit::MacroConditionCounterEdit(
|
||||||
|
QWidget *parent, std::shared_ptr<MacroConditionCounter> entryData)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
_macros = new MacroSelection(parent);
|
||||||
|
_conditions = new QComboBox();
|
||||||
|
_count = new QSpinBox();
|
||||||
|
_currentCount = new QLabel();
|
||||||
|
_resetCount = new QPushButton(
|
||||||
|
obs_module_text("AdvSceneSwitcher.condition.counter.reset"));
|
||||||
|
|
||||||
|
_count->setMaximum(10000000);
|
||||||
|
populateConditionSelection(_conditions);
|
||||||
|
|
||||||
|
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(MacroChanged(const QString &)));
|
||||||
|
QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this,
|
||||||
|
SLOT(MacroRemove(const QString &)));
|
||||||
|
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ConditionChanged(int)));
|
||||||
|
QWidget::connect(_count, SIGNAL(valueChanged(int)), this,
|
||||||
|
SLOT(CountChanged(int)));
|
||||||
|
QWidget::connect(_resetCount, SIGNAL(clicked()), this,
|
||||||
|
SLOT(ResetClicked()));
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
QHBoxLayout *line1Layout = new QHBoxLayout;
|
||||||
|
QHBoxLayout *line2Layout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{macros}}", _macros},
|
||||||
|
{"{{conditions}}", _conditions},
|
||||||
|
{"{{count}}", _count},
|
||||||
|
{"{{currentCount}}", _currentCount},
|
||||||
|
{"{{resetCount}}", _resetCount},
|
||||||
|
};
|
||||||
|
placeWidgets(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.counter.entry.line1"),
|
||||||
|
line1Layout, widgetPlaceholders);
|
||||||
|
placeWidgets(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.counter.entry.line2"),
|
||||||
|
line2Layout, widgetPlaceholders);
|
||||||
|
mainLayout->addLayout(line1Layout);
|
||||||
|
mainLayout->addLayout(line2Layout);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
_entryData = entryData;
|
||||||
|
UpdateEntryData();
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionCounterEdit::UpdateEntryData()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_macros->SetCurrentMacro(_entryData->_macro.get());
|
||||||
|
_conditions->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||||
|
_count->setValue(_entryData->_count);
|
||||||
|
ResetTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionCounterEdit::MacroChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_macro.UpdateRef(text);
|
||||||
|
ResetTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionCounterEdit::CountChanged(int value)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_count = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionCounterEdit::ConditionChanged(int cond)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_condition = static_cast<CounterCondition>(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionCounterEdit::MacroRemove(const QString &name)
|
||||||
|
{
|
||||||
|
UNUSED_PARAMETER(name);
|
||||||
|
if (_entryData) {
|
||||||
|
_entryData->_macro.UpdateRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionCounterEdit::ResetClicked()
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData || !_entryData->_macro.get()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_entryData->_macro->ResetCount();
|
||||||
|
ResetTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionCounterEdit::UpdateCount()
|
||||||
|
{
|
||||||
|
if (_entryData && _entryData->_macro.get()) {
|
||||||
|
_currentCount->setText(
|
||||||
|
QString::number(_entryData->_macro->GetCount()));
|
||||||
|
} else {
|
||||||
|
_currentCount->setText("-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionCounterEdit::ResetTimer()
|
||||||
|
{
|
||||||
|
_timer.reset(new QTimer(this));
|
||||||
|
connect(_timer.get(), SIGNAL(timeout()), this, SLOT(UpdateCount()));
|
||||||
|
_timer->start(1000);
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
#include "headers/macro-condition-edit.hpp"
|
#include "headers/macro-condition-edit.hpp"
|
||||||
|
#include "headers/macro-condition-scene.hpp"
|
||||||
|
|
||||||
std::map<int, MacroConditionInfo> MacroConditionFactory::_methods;
|
std::map<std::string, MacroConditionInfo> MacroConditionFactory::_methods;
|
||||||
|
|
||||||
bool MacroConditionFactory::Register(int id, MacroConditionInfo info)
|
bool MacroConditionFactory::Register(const std::string &id,
|
||||||
|
MacroConditionInfo info)
|
||||||
{
|
{
|
||||||
if (auto it = _methods.find(id); it == _methods.end()) {
|
if (auto it = _methods.find(id); it == _methods.end()) {
|
||||||
_methods[id] = info;
|
_methods[id] = info;
|
||||||
|
|
@ -11,24 +13,51 @@ bool MacroConditionFactory::Register(int id, MacroConditionInfo info)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<MacroCondition> MacroConditionFactory::Create(const int id)
|
std::shared_ptr<MacroCondition>
|
||||||
|
MacroConditionFactory::Create(const std::string &id)
|
||||||
{
|
{
|
||||||
if (auto it = _methods.find(id); it != _methods.end())
|
if (auto it = _methods.find(id); it != _methods.end()) {
|
||||||
return it->second._createFunc();
|
return it->second._createFunc();
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QWidget *
|
QWidget *
|
||||||
MacroConditionFactory::CreateWidget(const int id, QWidget *parent,
|
MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
|
||||||
std::shared_ptr<MacroCondition> cond)
|
std::shared_ptr<MacroCondition> cond)
|
||||||
{
|
{
|
||||||
if (auto it = _methods.find(id); it != _methods.end())
|
if (auto it = _methods.find(id); it != _methods.end()) {
|
||||||
return it->second._createWidgetFunc(parent, cond);
|
return it->second._createWidgetFunc(parent, cond);
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string MacroConditionFactory::GetConditionName(const std::string &id)
|
||||||
|
{
|
||||||
|
if (auto it = _methods.find(id); it != _methods.end()) {
|
||||||
|
return it->second._name;
|
||||||
|
}
|
||||||
|
return "unknown condition";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string MacroConditionFactory::GetIdByName(const QString &name)
|
||||||
|
{
|
||||||
|
for (auto it : _methods) {
|
||||||
|
if (name == obs_module_text(it.second._name.c_str())) {
|
||||||
|
return it.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionFactory::UsesDurationConstraint(const std::string &id)
|
||||||
|
{
|
||||||
|
if (auto it = _methods.find(id); it != _methods.end()) {
|
||||||
|
return it->second._useDurationConstraint;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static inline void populateLogicSelection(QComboBox *list, bool root = false)
|
static inline void populateLogicSelection(QComboBox *list, bool root = false)
|
||||||
{
|
{
|
||||||
if (root) {
|
if (root) {
|
||||||
|
|
@ -57,24 +86,34 @@ static inline void populateConditionSelection(QComboBox *list)
|
||||||
}
|
}
|
||||||
|
|
||||||
MacroConditionEdit::MacroConditionEdit(
|
MacroConditionEdit::MacroConditionEdit(
|
||||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData, int type,
|
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
||||||
bool root, bool startCollapsed)
|
const std::string &id, bool root, bool startCollapsed)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
_logicSelection = new QComboBox();
|
_logicSelection = new QComboBox();
|
||||||
_conditionSelection = new QComboBox();
|
_conditionSelection = new QComboBox();
|
||||||
_section = new Section(300);
|
_section = new Section(300);
|
||||||
|
_dur = new DurationConstraintEdit();
|
||||||
|
|
||||||
QWidget::connect(_logicSelection, SIGNAL(currentIndexChanged(int)),
|
QWidget::connect(_logicSelection, SIGNAL(currentIndexChanged(int)),
|
||||||
this, SLOT(LogicSelectionChanged(int)));
|
this, SLOT(LogicSelectionChanged(int)));
|
||||||
QWidget::connect(_conditionSelection, SIGNAL(currentIndexChanged(int)),
|
QWidget::connect(_conditionSelection,
|
||||||
this, SLOT(ConditionSelectionChanged(int)));
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
|
SLOT(ConditionSelectionChanged(const QString &)));
|
||||||
|
QWidget::connect(_dur, SIGNAL(DurationChanged(double)), this,
|
||||||
|
SLOT(DurationChanged(double)));
|
||||||
|
QWidget::connect(_dur, SIGNAL(UnitChanged(DurationUnit)), this,
|
||||||
|
SLOT(DurationUnitChanged(DurationUnit)));
|
||||||
|
QWidget::connect(_dur, SIGNAL(ConditionChanged(DurationCondition)),
|
||||||
|
this,
|
||||||
|
SLOT(DurationConditionChanged(DurationCondition)));
|
||||||
|
|
||||||
populateLogicSelection(_logicSelection, root);
|
populateLogicSelection(_logicSelection, root);
|
||||||
populateConditionSelection(_conditionSelection);
|
populateConditionSelection(_conditionSelection);
|
||||||
|
|
||||||
_section->AddHeaderWidget(_logicSelection);
|
_section->AddHeaderWidget(_logicSelection);
|
||||||
_section->AddHeaderWidget(_conditionSelection);
|
_section->AddHeaderWidget(_conditionSelection);
|
||||||
|
_section->AddHeaderWidget(_dur);
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addWidget(_section);
|
mainLayout->addWidget(_section);
|
||||||
|
|
@ -82,9 +121,8 @@ MacroConditionEdit::MacroConditionEdit(
|
||||||
|
|
||||||
_entryData = entryData;
|
_entryData = entryData;
|
||||||
_isRoot = root;
|
_isRoot = root;
|
||||||
UpdateEntryData(type);
|
UpdateEntryData(id, startCollapsed);
|
||||||
_loading = false;
|
_loading = false;
|
||||||
_section->Collapse(startCollapsed);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionEdit::LogicSelectionChanged(int idx)
|
void MacroConditionEdit::LogicSelectionChanged(int idx)
|
||||||
|
|
@ -109,11 +147,12 @@ bool MacroConditionEdit::IsRootNode()
|
||||||
return _isRoot;
|
return _isRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionEdit::UpdateEntryData(int type)
|
void MacroConditionEdit::UpdateEntryData(const std::string &id, bool collapse)
|
||||||
{
|
{
|
||||||
_conditionSelection->setCurrentIndex(type);
|
_conditionSelection->setCurrentText(obs_module_text(
|
||||||
auto widget = MacroConditionFactory::CreateWidget(type, window(),
|
MacroConditionFactory::GetConditionName(id).c_str()));
|
||||||
*_entryData);
|
auto widget =
|
||||||
|
MacroConditionFactory::CreateWidget(id, window(), *_entryData);
|
||||||
auto logic = (*_entryData)->GetLogicType();
|
auto logic = (*_entryData)->GetLogicType();
|
||||||
if (IsRootNode()) {
|
if (IsRootNode()) {
|
||||||
_logicSelection->setCurrentIndex(static_cast<int>(logic));
|
_logicSelection->setCurrentIndex(static_cast<int>(logic));
|
||||||
|
|
@ -121,29 +160,63 @@ void MacroConditionEdit::UpdateEntryData(int type)
|
||||||
_logicSelection->setCurrentIndex(static_cast<int>(logic) -
|
_logicSelection->setCurrentIndex(static_cast<int>(logic) -
|
||||||
logic_root_offset);
|
logic_root_offset);
|
||||||
}
|
}
|
||||||
_section->SetContent(widget);
|
_section->SetContent(widget, collapse);
|
||||||
|
|
||||||
|
_dur->setVisible(MacroConditionFactory::UsesDurationConstraint(id));
|
||||||
|
auto constraint = (*_entryData)->GetDurationConstraint();
|
||||||
|
_dur->SetValue(constraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionEdit::Collapse(bool collapsed)
|
void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
||||||
{
|
{
|
||||||
_section->Collapse(collapsed);
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string id = MacroConditionFactory::GetIdByName(text);
|
||||||
|
|
||||||
|
auto temp = DurationConstraint();
|
||||||
|
_dur->SetValue(temp);
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
auto logic = (*_entryData)->GetLogicType();
|
||||||
|
_entryData->reset();
|
||||||
|
*_entryData = MacroConditionFactory::Create(id);
|
||||||
|
(*_entryData)->SetLogicType(logic);
|
||||||
|
auto widget =
|
||||||
|
MacroConditionFactory::CreateWidget(id, window(), *_entryData);
|
||||||
|
_section->SetContent(widget, false);
|
||||||
|
_dur->setVisible(MacroConditionFactory::UsesDurationConstraint(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionEdit::ConditionSelectionChanged(int idx)
|
void MacroConditionEdit::DurationChanged(double seconds)
|
||||||
{
|
{
|
||||||
if (_loading || !_entryData) {
|
if (_loading || !_entryData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
auto logic = (*_entryData)->GetLogicType();
|
(*_entryData)->SetDuration(seconds);
|
||||||
_entryData->reset();
|
}
|
||||||
*_entryData = MacroConditionFactory::Create(idx);
|
|
||||||
(*_entryData)->SetLogicType(logic);
|
void MacroConditionEdit::DurationConditionChanged(DurationCondition cond)
|
||||||
auto widget =
|
{
|
||||||
MacroConditionFactory::CreateWidget(idx, window(), *_entryData);
|
if (_loading || !_entryData) {
|
||||||
_section->SetContent(widget);
|
return;
|
||||||
_section->Collapse(false);
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
(*_entryData)->SetDurationCondition(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionEdit::DurationUnitChanged(DurationUnit unit)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
(*_entryData)->SetDurationUnit(unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_conditionAdd_clicked()
|
void AdvSceneSwitcher::on_conditionAdd_clicked()
|
||||||
|
|
@ -152,17 +225,18 @@ void AdvSceneSwitcher::on_conditionAdd_clicked()
|
||||||
if (!macro) {
|
if (!macro) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
MacroConditionScene temp;
|
||||||
|
std::string id = temp.GetId();
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
bool root = macro->Conditions().size() == 0;
|
bool root = macro->Conditions().size() == 0;
|
||||||
macro->Conditions().emplace_back(MacroConditionFactory::Create(0));
|
macro->Conditions().emplace_back(MacroConditionFactory::Create(id));
|
||||||
auto logic = root ? LogicType::ROOT_NONE : LogicType::NONE;
|
auto logic = root ? LogicType::ROOT_NONE : LogicType::NONE;
|
||||||
macro->Conditions().back()->SetLogicType(logic);
|
macro->Conditions().back()->SetLogicType(logic);
|
||||||
auto newEntry = new MacroConditionEdit(
|
auto newEntry = new MacroConditionEdit(
|
||||||
this, ¯o->Conditions().back(), 0, root);
|
this, ¯o->Conditions().back(), id, root, false);
|
||||||
ui->macroEditConditionLayout->addWidget(newEntry);
|
ui->macroEditConditionLayout->addWidget(newEntry);
|
||||||
ui->macroEditConditionHelp->setVisible(false);
|
ui->macroEditConditionHelp->setVisible(false);
|
||||||
newEntry->Collapse(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_conditionRemove_clicked()
|
void AdvSceneSwitcher::on_conditionRemove_clicked()
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
|
||||||
const int MacroConditionFile::id = 4;
|
const std::string MacroConditionFile::id = "file";
|
||||||
|
|
||||||
bool MacroConditionFile::_registered = MacroConditionFactory::Register(
|
bool MacroConditionFile::_registered = MacroConditionFactory::Register(
|
||||||
MacroConditionFile::id,
|
MacroConditionFile::id,
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
const int MacroConditionIdle::id = 10;
|
const std::string MacroConditionIdle::id = "idle";
|
||||||
|
|
||||||
bool MacroConditionIdle::_registered = MacroConditionFactory::Register(
|
bool MacroConditionIdle::_registered = MacroConditionFactory::Register(
|
||||||
MacroConditionIdle::id,
|
MacroConditionIdle::id,
|
||||||
{MacroConditionIdle::Create, MacroConditionIdleEdit::Create,
|
{MacroConditionIdle::Create, MacroConditionIdleEdit::Create,
|
||||||
"AdvSceneSwitcher.condition.idle"});
|
"AdvSceneSwitcher.condition.idle", false});
|
||||||
|
|
||||||
bool MacroConditionIdle::CheckCondition()
|
bool MacroConditionIdle::CheckCondition()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
88
src/macro-condition-interval.cpp
Normal file
88
src/macro-condition-interval.cpp
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
#include "headers/macro-condition-edit.hpp"
|
||||||
|
#include "headers/macro-condition-interval.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
|
const std::string MacroConditionInterval::id = "interval";
|
||||||
|
|
||||||
|
bool MacroConditionInterval::_registered = MacroConditionFactory::Register(
|
||||||
|
MacroConditionInterval::id,
|
||||||
|
{MacroConditionInterval::Create, MacroConditionIntervalEdit::Create,
|
||||||
|
"AdvSceneSwitcher.condition.interval", false});
|
||||||
|
|
||||||
|
bool MacroConditionInterval::CheckCondition()
|
||||||
|
{
|
||||||
|
if (_duration.DurationReached()) {
|
||||||
|
_duration.Reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionInterval::Save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroCondition::Save(obj);
|
||||||
|
_duration.Save(obj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionInterval::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroCondition::Load(obj);
|
||||||
|
_duration.Load(obj);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroConditionIntervalEdit::MacroConditionIntervalEdit(
|
||||||
|
QWidget *parent, std::shared_ptr<MacroConditionInterval> entryData)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
_duration = new DurationSelection();
|
||||||
|
|
||||||
|
QWidget::connect(_duration, SIGNAL(DurationChanged(double)), this,
|
||||||
|
SLOT(DurationChanged(double)));
|
||||||
|
QWidget::connect(_duration, SIGNAL(UnitChanged(DurationUnit)), this,
|
||||||
|
SLOT(DurationUnitChanged(DurationUnit)));
|
||||||
|
|
||||||
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{duration}}", _duration},
|
||||||
|
};
|
||||||
|
placeWidgets(
|
||||||
|
obs_module_text("AdvSceneSwitcher.condition.interval.entry"),
|
||||||
|
mainLayout, widgetPlaceholders);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
_entryData = entryData;
|
||||||
|
UpdateEntryData();
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionIntervalEdit::DurationChanged(double seconds)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_duration.seconds = seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionIntervalEdit::DurationUnitChanged(DurationUnit unit)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_duration.displayUnit = unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionIntervalEdit::UpdateEntryData()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_duration->SetDuration(_entryData->_duration);
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
const int MacroConditionMedia::id = 5;
|
const std::string MacroConditionMedia::id = "media";
|
||||||
|
|
||||||
bool MacroConditionMedia::_registered = MacroConditionFactory::Register(
|
bool MacroConditionMedia::_registered = MacroConditionFactory::Register(
|
||||||
MacroConditionMedia::id,
|
MacroConditionMedia::id,
|
||||||
|
|
@ -256,7 +256,7 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
|
||||||
QWidget::connect(_time, SIGNAL(UnitChanged(DurationUnit)), this,
|
QWidget::connect(_time, SIGNAL(UnitChanged(DurationUnit)), this,
|
||||||
SLOT(TimeUnitChanged(DurationUnit)));
|
SLOT(TimeUnitChanged(DurationUnit)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateMediaSelection(_mediaSources);
|
populateMediaSelection(_mediaSources);
|
||||||
populateMediaStates(_states);
|
populateMediaStates(_states);
|
||||||
populateMediaTimeRestrictions(_timeRestrictions);
|
populateMediaTimeRestrictions(_timeRestrictions);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,13 @@
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
const int MacroConditionPluginState::id = 11;
|
const std::string MacroConditionPluginState::id = "plugin_state";
|
||||||
|
|
||||||
bool MacroConditionPluginState::_registered = MacroConditionFactory::Register(
|
bool MacroConditionPluginState::_registered = MacroConditionFactory::Register(
|
||||||
MacroConditionPluginState::id,
|
MacroConditionPluginState::id,
|
||||||
{MacroConditionPluginState::Create,
|
{MacroConditionPluginState::Create,
|
||||||
MacroConditionPluginStateEdit::Create,
|
MacroConditionPluginStateEdit::Create,
|
||||||
"AdvSceneSwitcher.condition.pluginState"});
|
"AdvSceneSwitcher.condition.pluginState", false});
|
||||||
|
|
||||||
static std::map<PluginStateCondition, std::string> pluginStateConditionTypes = {
|
static std::map<PluginStateCondition, std::string> pluginStateConditionTypes = {
|
||||||
{PluginStateCondition::SCENESWITCHED,
|
{PluginStateCondition::SCENESWITCHED,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
const int MacroConditionProcess::id = 9;
|
const std::string MacroConditionProcess::id = "process";
|
||||||
|
|
||||||
bool MacroConditionProcess::_registered = MacroConditionFactory::Register(
|
bool MacroConditionProcess::_registered = MacroConditionFactory::Register(
|
||||||
MacroConditionProcess::id,
|
MacroConditionProcess::id,
|
||||||
|
|
@ -61,7 +61,7 @@ MacroConditionProcessEdit::MacroConditionProcessEdit(
|
||||||
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
||||||
SLOT(FocusChanged(int)));
|
SLOT(FocusChanged(int)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateProcessSelection(_processSelection);
|
populateProcessSelection(_processSelection);
|
||||||
|
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{processes}}", _processSelection},
|
{"{{processes}}", _processSelection},
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
const int MacroConditionRecord::id = 8;
|
const std::string MacroConditionRecord::id = "recording";
|
||||||
|
|
||||||
bool MacroConditionRecord::_registered = MacroConditionFactory::Register(
|
bool MacroConditionRecord::_registered = MacroConditionFactory::Register(
|
||||||
MacroConditionRecord::id,
|
MacroConditionRecord::id,
|
||||||
|
|
@ -32,20 +32,13 @@ bool MacroConditionRecord::CheckCondition()
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return stateMatch;
|
||||||
if (!stateMatch) {
|
|
||||||
_duration.Reset();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _duration.DurationReached();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionRecord::Save(obs_data_t *obj)
|
bool MacroConditionRecord::Save(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
MacroCondition::Save(obj);
|
MacroCondition::Save(obj);
|
||||||
obs_data_set_int(obj, "state", static_cast<int>(_recordState));
|
obs_data_set_int(obj, "state", static_cast<int>(_recordState));
|
||||||
_duration.Save(obj);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,7 +46,6 @@ bool MacroConditionRecord::Load(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
MacroCondition::Load(obj);
|
MacroCondition::Load(obj);
|
||||||
_recordState = static_cast<RecordState>(obs_data_get_int(obj, "state"));
|
_recordState = static_cast<RecordState>(obs_data_get_int(obj, "state"));
|
||||||
_duration.Load(obj);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,14 +61,9 @@ MacroConditionRecordEdit::MacroConditionRecordEdit(
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
_recordState = new QComboBox();
|
_recordState = new QComboBox();
|
||||||
_duration = new DurationSelection();
|
|
||||||
|
|
||||||
QWidget::connect(_recordState, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_recordState, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(StateChanged(int)));
|
SLOT(StateChanged(int)));
|
||||||
QWidget::connect(_duration, SIGNAL(DurationChanged(double)), this,
|
|
||||||
SLOT(DurationChanged(double)));
|
|
||||||
QWidget::connect(_duration, SIGNAL(UnitChanged(DurationUnit)), this,
|
|
||||||
SLOT(DurationUnitChanged(DurationUnit)));
|
|
||||||
|
|
||||||
populateStateSelection(_recordState);
|
populateStateSelection(_recordState);
|
||||||
|
|
||||||
|
|
@ -84,7 +71,6 @@ MacroConditionRecordEdit::MacroConditionRecordEdit(
|
||||||
|
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{recordState}}", _recordState},
|
{"{{recordState}}", _recordState},
|
||||||
{"{{duration}}", _duration},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.record.entry"),
|
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.record.entry"),
|
||||||
|
|
@ -106,26 +92,6 @@ void MacroConditionRecordEdit::StateChanged(int value)
|
||||||
_entryData->_recordState = static_cast<RecordState>(value);
|
_entryData->_recordState = static_cast<RecordState>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionRecordEdit::DurationChanged(double seconds)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
_entryData->_duration.seconds = seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionRecordEdit::DurationUnitChanged(DurationUnit unit)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
_entryData->_duration.displayUnit = unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionRecordEdit::UpdateEntryData()
|
void MacroConditionRecordEdit::UpdateEntryData()
|
||||||
{
|
{
|
||||||
if (!_entryData) {
|
if (!_entryData) {
|
||||||
|
|
@ -134,5 +100,4 @@ void MacroConditionRecordEdit::UpdateEntryData()
|
||||||
|
|
||||||
_recordState->setCurrentIndex(
|
_recordState->setCurrentIndex(
|
||||||
static_cast<int>(_entryData->_recordState));
|
static_cast<int>(_entryData->_recordState));
|
||||||
_duration->SetDuration(_entryData->_duration);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
const int MacroConditionRegion::id = 2;
|
const std::string MacroConditionRegion::id = "region";
|
||||||
|
|
||||||
bool MacroConditionRegion::_registered = MacroConditionFactory::Register(
|
bool MacroConditionRegion::_registered = MacroConditionFactory::Register(
|
||||||
MacroConditionRegion::id,
|
MacroConditionRegion::id,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
const int MacroConditionScene::id = 0;
|
const std::string MacroConditionScene::id = "scene";
|
||||||
|
|
||||||
bool MacroConditionScene::_registered = MacroConditionFactory::Register(
|
bool MacroConditionScene::_registered = MacroConditionFactory::Register(
|
||||||
MacroConditionScene::id,
|
MacroConditionScene::id,
|
||||||
|
|
@ -29,11 +29,7 @@ bool MacroConditionScene::CheckCondition()
|
||||||
sceneMatch = switcher->previousScene == _scene;
|
sceneMatch = switcher->previousScene == _scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sceneMatch) {
|
return sceneMatch;
|
||||||
_duration.Reset();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return _duration.DurationReached();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionScene::Save(obs_data_t *obj)
|
bool MacroConditionScene::Save(obs_data_t *obj)
|
||||||
|
|
@ -41,7 +37,6 @@ bool MacroConditionScene::Save(obs_data_t *obj)
|
||||||
MacroCondition::Save(obj);
|
MacroCondition::Save(obj);
|
||||||
obs_data_set_string(obj, "scene", GetWeakSourceName(_scene).c_str());
|
obs_data_set_string(obj, "scene", GetWeakSourceName(_scene).c_str());
|
||||||
obs_data_set_int(obj, "type", static_cast<int>(_type));
|
obs_data_set_int(obj, "type", static_cast<int>(_type));
|
||||||
_duration.Save(obj);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,7 +45,6 @@ bool MacroConditionScene::Load(obs_data_t *obj)
|
||||||
MacroCondition::Load(obj);
|
MacroCondition::Load(obj);
|
||||||
_scene = GetWeakSourceByName(obs_data_get_string(obj, "scene"));
|
_scene = GetWeakSourceByName(obs_data_get_string(obj, "scene"));
|
||||||
_type = static_cast<SceneType>(obs_data_get_int(obj, "type"));
|
_type = static_cast<SceneType>(obs_data_get_int(obj, "type"));
|
||||||
_duration.Load(obj);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -67,26 +61,20 @@ MacroConditionSceneEdit::MacroConditionSceneEdit(
|
||||||
{
|
{
|
||||||
_sceneSelection = new QComboBox();
|
_sceneSelection = new QComboBox();
|
||||||
_sceneType = new QComboBox();
|
_sceneType = new QComboBox();
|
||||||
_duration = new DurationSelection();
|
|
||||||
|
|
||||||
QWidget::connect(_sceneSelection,
|
QWidget::connect(_sceneSelection,
|
||||||
SIGNAL(currentTextChanged(const QString &)), this,
|
SIGNAL(currentTextChanged(const QString &)), this,
|
||||||
SLOT(SceneChanged(const QString &)));
|
SLOT(SceneChanged(const QString &)));
|
||||||
QWidget::connect(_sceneType, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_sceneType, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(TypeChanged(int)));
|
SLOT(TypeChanged(int)));
|
||||||
QWidget::connect(_duration, SIGNAL(DurationChanged(double)), this,
|
|
||||||
SLOT(DurationChanged(double)));
|
|
||||||
QWidget::connect(_duration, SIGNAL(UnitChanged(DurationUnit)), this,
|
|
||||||
SLOT(DurationUnitChanged(DurationUnit)));
|
|
||||||
|
|
||||||
AdvSceneSwitcher::populateSceneSelection(_sceneSelection);
|
populateSceneSelection(_sceneSelection);
|
||||||
populateTypeSelection(_sceneType);
|
populateTypeSelection(_sceneType);
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{scenes}}", _sceneSelection},
|
{"{{scenes}}", _sceneSelection},
|
||||||
{"{{sceneType}}", _sceneType},
|
{"{{sceneType}}", _sceneType},
|
||||||
{"{{duration}}", _duration},
|
|
||||||
};
|
};
|
||||||
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.scene.entry"),
|
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.scene.entry"),
|
||||||
mainLayout, widgetPlaceholders);
|
mainLayout, widgetPlaceholders);
|
||||||
|
|
@ -117,26 +105,6 @@ void MacroConditionSceneEdit::TypeChanged(int value)
|
||||||
_entryData->_type = static_cast<SceneType>(value);
|
_entryData->_type = static_cast<SceneType>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionSceneEdit::DurationChanged(double seconds)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
_entryData->_duration.seconds = seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionSceneEdit::DurationUnitChanged(DurationUnit unit)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
_entryData->_duration.displayUnit = unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionSceneEdit::UpdateEntryData()
|
void MacroConditionSceneEdit::UpdateEntryData()
|
||||||
{
|
{
|
||||||
if (!_entryData) {
|
if (!_entryData) {
|
||||||
|
|
@ -146,5 +114,4 @@ void MacroConditionSceneEdit::UpdateEntryData()
|
||||||
_sceneSelection->setCurrentText(
|
_sceneSelection->setCurrentText(
|
||||||
GetWeakSourceName(_entryData->_scene).c_str());
|
GetWeakSourceName(_entryData->_scene).c_str());
|
||||||
_sceneType->setCurrentIndex(static_cast<int>(_entryData->_type));
|
_sceneType->setCurrentIndex(static_cast<int>(_entryData->_type));
|
||||||
_duration->SetDuration(_entryData->_duration);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
223
src/macro-condition-source.cpp
Normal file
223
src/macro-condition-source.cpp
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
#include "headers/macro-condition-edit.hpp"
|
||||||
|
#include "headers/macro-condition-source.hpp"
|
||||||
|
#include "headers/utility.hpp"
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
const std::string MacroConditionSource::id = "source";
|
||||||
|
|
||||||
|
bool MacroConditionSource::_registered = MacroConditionFactory::Register(
|
||||||
|
MacroConditionSource::id,
|
||||||
|
{MacroConditionSource::Create, MacroConditionSourceEdit::Create,
|
||||||
|
"AdvSceneSwitcher.condition.source"});
|
||||||
|
|
||||||
|
static std::map<SourceCondition, std::string> sourceConditionTypes = {
|
||||||
|
{SourceCondition::ACTIVE,
|
||||||
|
"AdvSceneSwitcher.condition.source.type.active"},
|
||||||
|
{SourceCondition::SHOWING,
|
||||||
|
"AdvSceneSwitcher.condition.source.type.showing"},
|
||||||
|
{SourceCondition::SETTINGS,
|
||||||
|
"AdvSceneSwitcher.condition.source.type.settings"},
|
||||||
|
};
|
||||||
|
|
||||||
|
bool checkSettings(const OBSWeakSource &source, const std::string &settings,
|
||||||
|
bool useRegex)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
std::string currentSettings = getSourceSettings(source);
|
||||||
|
if (useRegex) {
|
||||||
|
try {
|
||||||
|
std::regex expr(settings);
|
||||||
|
ret = std::regex_match(currentSettings, expr);
|
||||||
|
} catch (const std::regex_error &) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ret = currentSettings == settings;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionSource::CheckCondition()
|
||||||
|
{
|
||||||
|
if (!_source) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
auto s = obs_weak_source_get_source(_source);
|
||||||
|
|
||||||
|
switch (_condition) {
|
||||||
|
case SourceCondition::ACTIVE:
|
||||||
|
ret = obs_source_active(s);
|
||||||
|
break;
|
||||||
|
case SourceCondition::SHOWING:
|
||||||
|
ret = obs_source_showing(s);
|
||||||
|
break;
|
||||||
|
case SourceCondition::SETTINGS:
|
||||||
|
ret = checkSettings(_source, _settings, _regex);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
obs_source_release(s);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionSource::Save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroCondition::Save(obj);
|
||||||
|
obs_data_set_string(obj, "source", GetWeakSourceName(_source).c_str());
|
||||||
|
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
||||||
|
obs_data_set_string(obj, "settings", _settings.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MacroConditionSource::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
MacroCondition::Load(obj);
|
||||||
|
const char *sourceName = obs_data_get_string(obj, "source");
|
||||||
|
_source = GetWeakSourceByName(sourceName);
|
||||||
|
_condition = static_cast<SourceCondition>(
|
||||||
|
obs_data_get_int(obj, "condition"));
|
||||||
|
_settings = obs_data_get_string(obj, "settings");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void populateConditionSelection(QComboBox *list)
|
||||||
|
{
|
||||||
|
for (auto entry : sourceConditionTypes) {
|
||||||
|
list->addItem(obs_module_text(entry.second.c_str()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroConditionSourceEdit::MacroConditionSourceEdit(
|
||||||
|
QWidget *parent, std::shared_ptr<MacroConditionSource> entryData)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
_sources = new QComboBox();
|
||||||
|
_conditions = new QComboBox();
|
||||||
|
_getSettings = new QPushButton(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.source.getSettings"));
|
||||||
|
_settings = new QPlainTextEdit();
|
||||||
|
_regex = new QCheckBox(
|
||||||
|
obs_module_text("AdvSceneSwitcher.condition.source.regex"));
|
||||||
|
|
||||||
|
populateConditionSelection(_conditions);
|
||||||
|
populateSourceSelection(_sources);
|
||||||
|
|
||||||
|
QWidget::connect(_sources, SIGNAL(currentTextChanged(const QString &)),
|
||||||
|
this, SLOT(SourceChanged(const QString &)));
|
||||||
|
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
|
||||||
|
SLOT(ConditionChanged(int)));
|
||||||
|
QWidget::connect(_getSettings, SIGNAL(clicked()), this,
|
||||||
|
SLOT(GetSettingsClicked()));
|
||||||
|
QWidget::connect(_settings, SIGNAL(textChanged()), this,
|
||||||
|
SLOT(SettingsChanged()));
|
||||||
|
QWidget::connect(_regex, SIGNAL(stateChanged(int)), this,
|
||||||
|
SLOT(RegexChanged(int)));
|
||||||
|
|
||||||
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
|
QHBoxLayout *line1Layout = new QHBoxLayout;
|
||||||
|
QHBoxLayout *line2Layout = new QHBoxLayout;
|
||||||
|
QHBoxLayout *line3Layout = new QHBoxLayout;
|
||||||
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
|
{"{{sources}}", _sources}, {"{{conditions}}", _conditions},
|
||||||
|
{"{{settings}}", _settings}, {"{{getSettings}}", _getSettings},
|
||||||
|
{"{{regex}}", _regex},
|
||||||
|
};
|
||||||
|
placeWidgets(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.source.entry.line1"),
|
||||||
|
line1Layout, widgetPlaceholders);
|
||||||
|
placeWidgets(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.source.entry.line2"),
|
||||||
|
line2Layout, widgetPlaceholders, false);
|
||||||
|
placeWidgets(obs_module_text(
|
||||||
|
"AdvSceneSwitcher.condition.source.entry.line3"),
|
||||||
|
line3Layout, widgetPlaceholders);
|
||||||
|
mainLayout->addLayout(line1Layout);
|
||||||
|
mainLayout->addLayout(line2Layout);
|
||||||
|
mainLayout->addLayout(line3Layout);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
|
||||||
|
_entryData = entryData;
|
||||||
|
UpdateEntryData();
|
||||||
|
_loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionSourceEdit::SourceChanged(const QString &text)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_source = GetWeakSourceByQString(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionSourceEdit::ConditionChanged(int index)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_condition = static_cast<SourceCondition>(index);
|
||||||
|
SetSettingsSelectionVisible(_entryData->_condition ==
|
||||||
|
SourceCondition::SETTINGS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionSourceEdit::GetSettingsClicked()
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData || !_entryData->_source) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_settings->setPlainText(
|
||||||
|
QString::fromStdString(getSourceSettings(_entryData->_source)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionSourceEdit::SettingsChanged()
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_settings = _settings->toPlainText().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionSourceEdit::RegexChanged(int state)
|
||||||
|
{
|
||||||
|
if (_loading || !_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
_entryData->_regex = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionSourceEdit::SetSettingsSelectionVisible(bool visible)
|
||||||
|
{
|
||||||
|
_settings->setVisible(visible);
|
||||||
|
_getSettings->setVisible(visible);
|
||||||
|
_regex->setVisible(visible);
|
||||||
|
adjustSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroConditionSourceEdit::UpdateEntryData()
|
||||||
|
{
|
||||||
|
if (!_entryData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_sources->setCurrentText(
|
||||||
|
GetWeakSourceName(_entryData->_source).c_str());
|
||||||
|
_conditions->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||||
|
_settings->setPlainText(QString::fromStdString(_entryData->_settings));
|
||||||
|
_regex->setChecked(_entryData->_regex);
|
||||||
|
SetSettingsSelectionVisible(_entryData->_condition ==
|
||||||
|
SourceCondition::SETTINGS);
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
#include "headers/advanced-scene-switcher.hpp"
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
const int MacroConditionStream::id = 7;
|
const std::string MacroConditionStream::id = "streaming";
|
||||||
|
|
||||||
bool MacroConditionStream::_registered = MacroConditionFactory::Register(
|
bool MacroConditionStream::_registered = MacroConditionFactory::Register(
|
||||||
MacroConditionStream::id,
|
MacroConditionStream::id,
|
||||||
|
|
@ -28,20 +28,13 @@ bool MacroConditionStream::CheckCondition()
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return stateMatch;
|
||||||
if (!stateMatch) {
|
|
||||||
_duration.Reset();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _duration.DurationReached();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroConditionStream::Save(obs_data_t *obj)
|
bool MacroConditionStream::Save(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
MacroCondition::Save(obj);
|
MacroCondition::Save(obj);
|
||||||
obs_data_set_int(obj, "state", static_cast<int>(_streamState));
|
obs_data_set_int(obj, "state", static_cast<int>(_streamState));
|
||||||
_duration.Save(obj);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,7 +42,6 @@ bool MacroConditionStream::Load(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
MacroCondition::Load(obj);
|
MacroCondition::Load(obj);
|
||||||
_streamState = static_cast<StreamState>(obs_data_get_int(obj, "state"));
|
_streamState = static_cast<StreamState>(obs_data_get_int(obj, "state"));
|
||||||
_duration.Load(obj);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,14 +57,9 @@ MacroConditionStreamEdit::MacroConditionStreamEdit(
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
{
|
{
|
||||||
_streamState = new QComboBox();
|
_streamState = new QComboBox();
|
||||||
_duration = new DurationSelection();
|
|
||||||
|
|
||||||
QWidget::connect(_streamState, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_streamState, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(StateChanged(int)));
|
SLOT(StateChanged(int)));
|
||||||
QWidget::connect(_duration, SIGNAL(DurationChanged(double)), this,
|
|
||||||
SLOT(DurationChanged(double)));
|
|
||||||
QWidget::connect(_duration, SIGNAL(UnitChanged(DurationUnit)), this,
|
|
||||||
SLOT(DurationUnitChanged(DurationUnit)));
|
|
||||||
|
|
||||||
populateStateSelection(_streamState);
|
populateStateSelection(_streamState);
|
||||||
|
|
||||||
|
|
@ -80,7 +67,6 @@ MacroConditionStreamEdit::MacroConditionStreamEdit(
|
||||||
|
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{streamState}}", _streamState},
|
{"{{streamState}}", _streamState},
|
||||||
{"{{duration}}", _duration},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.stream.entry"),
|
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.stream.entry"),
|
||||||
|
|
@ -102,26 +88,6 @@ void MacroConditionStreamEdit::StateChanged(int value)
|
||||||
_entryData->_streamState = static_cast<StreamState>(value);
|
_entryData->_streamState = static_cast<StreamState>(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionStreamEdit::DurationChanged(double seconds)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
_entryData->_duration.seconds = seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionStreamEdit::DurationUnitChanged(DurationUnit unit)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
_entryData->_duration.displayUnit = unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionStreamEdit::UpdateEntryData()
|
void MacroConditionStreamEdit::UpdateEntryData()
|
||||||
{
|
{
|
||||||
if (!_entryData) {
|
if (!_entryData) {
|
||||||
|
|
@ -130,5 +96,4 @@ void MacroConditionStreamEdit::UpdateEntryData()
|
||||||
|
|
||||||
_streamState->setCurrentIndex(
|
_streamState->setCurrentIndex(
|
||||||
static_cast<int>(_entryData->_streamState));
|
static_cast<int>(_entryData->_streamState));
|
||||||
_duration->SetDuration(_entryData->_duration);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
#include <QToolTip>
|
#include <QToolTip>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
const int MacroConditionVideo::id = 6;
|
const std::string MacroConditionVideo::id = "video";
|
||||||
|
|
||||||
bool MacroConditionVideo::_registered = MacroConditionFactory::Register(
|
bool MacroConditionVideo::_registered = MacroConditionFactory::Register(
|
||||||
MacroConditionVideo::id,
|
MacroConditionVideo::id,
|
||||||
|
|
@ -39,15 +39,7 @@ bool MacroConditionVideo::CheckCondition()
|
||||||
|
|
||||||
if (_screenshotData) {
|
if (_screenshotData) {
|
||||||
if (_screenshotData->done) {
|
if (_screenshotData->done) {
|
||||||
bool imageMatch = Compare();
|
match = Compare();
|
||||||
|
|
||||||
if (!imageMatch) {
|
|
||||||
_duration.Reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (imageMatch && _duration.DurationReached()) {
|
|
||||||
match = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!requiresFileInput(_condition)) {
|
if (!requiresFileInput(_condition)) {
|
||||||
_matchImage = std::move(_screenshotData->image);
|
_matchImage = std::move(_screenshotData->image);
|
||||||
|
|
@ -66,7 +58,6 @@ bool MacroConditionVideo::Save(obs_data_t *obj)
|
||||||
obs_data_set_string(obj, "videoSource",
|
obs_data_set_string(obj, "videoSource",
|
||||||
GetWeakSourceName(_videoSource).c_str());
|
GetWeakSourceName(_videoSource).c_str());
|
||||||
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
||||||
_duration.Save(obj);
|
|
||||||
obs_data_set_string(obj, "filePath", _file.c_str());
|
obs_data_set_string(obj, "filePath", _file.c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -77,7 +68,6 @@ bool MacroConditionVideo::Load(obs_data_t *obj)
|
||||||
_videoSource = GetWeakSourceByName(videoSourceName);
|
_videoSource = GetWeakSourceByName(videoSourceName);
|
||||||
_condition =
|
_condition =
|
||||||
static_cast<VideoCondition>(obs_data_get_int(obj, "condition"));
|
static_cast<VideoCondition>(obs_data_get_int(obj, "condition"));
|
||||||
_duration.Load(obj);
|
|
||||||
_file = obs_data_get_string(obj, "filePath");
|
_file = obs_data_get_string(obj, "filePath");
|
||||||
|
|
||||||
if (requiresFileInput(_condition)) {
|
if (requiresFileInput(_condition)) {
|
||||||
|
|
@ -137,7 +127,6 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
||||||
{
|
{
|
||||||
_videoSelection = new QComboBox();
|
_videoSelection = new QComboBox();
|
||||||
_condition = new QComboBox();
|
_condition = new QComboBox();
|
||||||
_duration = new DurationSelection();
|
|
||||||
_filePath = new QLineEdit();
|
_filePath = new QLineEdit();
|
||||||
_browseButton =
|
_browseButton =
|
||||||
new QPushButton(obs_module_text("AdvSceneSwitcher.browse"));
|
new QPushButton(obs_module_text("AdvSceneSwitcher.browse"));
|
||||||
|
|
@ -151,23 +140,18 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
||||||
SLOT(SourceChanged(const QString &)));
|
SLOT(SourceChanged(const QString &)));
|
||||||
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
|
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
|
||||||
SLOT(ConditionChanged(int)));
|
SLOT(ConditionChanged(int)));
|
||||||
QWidget::connect(_duration, SIGNAL(DurationChanged(double)), this,
|
|
||||||
SLOT(DurationChanged(double)));
|
|
||||||
QWidget::connect(_duration, SIGNAL(UnitChanged(DurationUnit)), this,
|
|
||||||
SLOT(DurationUnitChanged(DurationUnit)));
|
|
||||||
QWidget::connect(_filePath, SIGNAL(editingFinished()), this,
|
QWidget::connect(_filePath, SIGNAL(editingFinished()), this,
|
||||||
SLOT(FilePathChanged()));
|
SLOT(FilePathChanged()));
|
||||||
QWidget::connect(_browseButton, SIGNAL(clicked()), this,
|
QWidget::connect(_browseButton, SIGNAL(clicked()), this,
|
||||||
SLOT(BrowseButtonClicked()));
|
SLOT(BrowseButtonClicked()));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateVideoSelection(_videoSelection, false);
|
populateVideoSelection(_videoSelection);
|
||||||
populateConditionSelection(_condition);
|
populateConditionSelection(_condition);
|
||||||
|
|
||||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{videoSources}}", _videoSelection},
|
{"{{videoSources}}", _videoSelection},
|
||||||
{"{{condition}}", _condition},
|
{"{{condition}}", _condition},
|
||||||
{"{{duration}}", _duration},
|
|
||||||
{"{{filePath}}", _filePath},
|
{"{{filePath}}", _filePath},
|
||||||
{"{{browseButton}}", _browseButton},
|
{"{{browseButton}}", _browseButton},
|
||||||
};
|
};
|
||||||
|
|
@ -324,26 +308,6 @@ void MacroConditionVideoEdit::BrowseButtonClicked()
|
||||||
SetFilePath(path);
|
SetFilePath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MacroConditionVideoEdit::DurationChanged(double seconds)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
_entryData->_duration.seconds = seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionVideoEdit::DurationUnitChanged(DurationUnit unit)
|
|
||||||
{
|
|
||||||
if (_loading || !_entryData) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
|
||||||
_entryData->_duration.displayUnit = unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MacroConditionVideoEdit::UpdateEntryData()
|
void MacroConditionVideoEdit::UpdateEntryData()
|
||||||
{
|
{
|
||||||
if (!_entryData) {
|
if (!_entryData) {
|
||||||
|
|
@ -353,7 +317,6 @@ void MacroConditionVideoEdit::UpdateEntryData()
|
||||||
_videoSelection->setCurrentText(
|
_videoSelection->setCurrentText(
|
||||||
GetWeakSourceName(_entryData->_videoSource).c_str());
|
GetWeakSourceName(_entryData->_videoSource).c_str());
|
||||||
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||||
_duration->SetDuration(_entryData->_duration);
|
|
||||||
_filePath->setText(QString::fromStdString(_entryData->_file));
|
_filePath->setText(QString::fromStdString(_entryData->_file));
|
||||||
|
|
||||||
if (!requiresFileInput(_entryData->_condition)) {
|
if (!requiresFileInput(_entryData->_condition)) {
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
const int MacroConditionWindow::id = 1;
|
const std::string MacroConditionWindow::id = "window";
|
||||||
|
|
||||||
bool MacroConditionWindow::_registered = MacroConditionFactory::Register(
|
bool MacroConditionWindow::_registered = MacroConditionFactory::Register(
|
||||||
MacroConditionWindow::id,
|
MacroConditionWindow::id,
|
||||||
|
|
@ -83,12 +83,7 @@ bool MacroConditionWindow::Load(obs_data_t *obj)
|
||||||
MacroCondition::Load(obj);
|
MacroCondition::Load(obj);
|
||||||
_window = obs_data_get_string(obj, "window");
|
_window = obs_data_get_string(obj, "window");
|
||||||
_fullscreen = obs_data_get_bool(obj, "fullscreen");
|
_fullscreen = obs_data_get_bool(obj, "fullscreen");
|
||||||
#if __APPLE__
|
|
||||||
// TODO: Implement maximized check on MacOS
|
|
||||||
_maximized = false;
|
|
||||||
#else
|
|
||||||
_maximized = obs_data_get_bool(obj, "maximized");
|
_maximized = obs_data_get_bool(obj, "maximized");
|
||||||
#endif
|
|
||||||
_focus = obs_data_get_bool(obj, "focus");
|
_focus = obs_data_get_bool(obj, "focus");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -115,7 +110,7 @@ MacroConditionWindowEdit::MacroConditionWindowEdit(
|
||||||
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
||||||
SLOT(FocusChanged(int)));
|
SLOT(FocusChanged(int)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateWindowSelection(_windowSelection);
|
populateWindowSelection(_windowSelection);
|
||||||
|
|
||||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||||
{"{{windows}}", _windowSelection},
|
{"{{windows}}", _windowSelection},
|
||||||
|
|
|
||||||
68
src/macro-selection.cpp
Normal file
68
src/macro-selection.cpp
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
#include "headers/macro-selection.hpp"
|
||||||
|
#include "headers/advanced-scene-switcher.hpp"
|
||||||
|
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
|
MacroSelection::MacroSelection(QWidget *parent) : QComboBox(parent)
|
||||||
|
{
|
||||||
|
addItem(obs_module_text("AdvSceneSwitcher.selectMacro"));
|
||||||
|
|
||||||
|
QStandardItemModel *model =
|
||||||
|
qobject_cast<QStandardItemModel *>(this->model());
|
||||||
|
QModelIndex firstIndex =
|
||||||
|
model->index(0, modelColumn(), rootModelIndex());
|
||||||
|
QStandardItem *firstItem = model->itemFromIndex(firstIndex);
|
||||||
|
firstItem->setSelectable(false);
|
||||||
|
firstItem->setEnabled(false);
|
||||||
|
|
||||||
|
for (auto &m : switcher->macros) {
|
||||||
|
addItem(QString::fromStdString(m.Name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
QWidget::connect(parent, SIGNAL(MacroAdded(const QString &)), this,
|
||||||
|
SLOT(MacroAdd(const QString &)));
|
||||||
|
QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this,
|
||||||
|
SLOT(MacroRemove(const QString &)));
|
||||||
|
QWidget::connect(parent,
|
||||||
|
SIGNAL(MacroRenamed(const QString &, const QString &)),
|
||||||
|
this,
|
||||||
|
SLOT(MacroRename(const QString &, const QString &)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroSelection::MacroAdd(const QString &name)
|
||||||
|
{
|
||||||
|
addItem(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroSelection::SetCurrentMacro(Macro *m)
|
||||||
|
{
|
||||||
|
if (!m) {
|
||||||
|
this->setCurrentIndex(0);
|
||||||
|
} else {
|
||||||
|
this->setCurrentText(QString::fromStdString(m->Name()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroSelection::MacroRemove(const QString &name)
|
||||||
|
{
|
||||||
|
int idx = findText(name);
|
||||||
|
if (idx == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
removeItem(idx);
|
||||||
|
setCurrentIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroSelection::MacroRename(const QString &oldName, const QString &newName)
|
||||||
|
{
|
||||||
|
bool renameSelected = currentText() == oldName;
|
||||||
|
int idx = findText(oldName);
|
||||||
|
if (idx == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
removeItem(idx);
|
||||||
|
insertItem(idx, newName);
|
||||||
|
if (renameSelected) {
|
||||||
|
setCurrentIndex(findText(newName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,17 +9,11 @@
|
||||||
static QMetaObject::Connection addPulse;
|
static QMetaObject::Connection addPulse;
|
||||||
|
|
||||||
const auto conditionsCollapseThreshold = 4;
|
const auto conditionsCollapseThreshold = 4;
|
||||||
const auto actionsCollapseThreshold = 2;
|
const auto actionsCollapseThreshold = 4;
|
||||||
|
|
||||||
bool macroNameExists(std::string name)
|
bool macroNameExists(std::string name)
|
||||||
{
|
{
|
||||||
for (auto &m : switcher->macros) {
|
return !!GetMacroByName(name.c_str());
|
||||||
if (m.Name() == name) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AdvSceneSwitcher::addNewMacro(std::string &name)
|
bool AdvSceneSwitcher::addNewMacro(std::string &name)
|
||||||
|
|
@ -69,10 +63,14 @@ void AdvSceneSwitcher::on_macroAdd_clicked()
|
||||||
|
|
||||||
QListWidgetItem *item = new QListWidgetItem(text, ui->macros);
|
QListWidgetItem *item = new QListWidgetItem(text, ui->macros);
|
||||||
item->setData(Qt::UserRole, text);
|
item->setData(Qt::UserRole, text);
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Checked);
|
||||||
ui->macros->setCurrentItem(item);
|
ui->macros->setCurrentItem(item);
|
||||||
|
|
||||||
ui->macroAdd->disconnect(addPulse);
|
ui->macroAdd->disconnect(addPulse);
|
||||||
ui->macroHelp->setVisible(false);
|
ui->macroHelp->setVisible(false);
|
||||||
|
|
||||||
|
emit MacroAdded(QString::fromStdString(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_macroRemove_clicked()
|
void AdvSceneSwitcher::on_macroRemove_clicked()
|
||||||
|
|
@ -81,9 +79,11 @@ void AdvSceneSwitcher::on_macroRemove_clicked()
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
QString name;
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
int idx = ui->macros->currentRow();
|
int idx = ui->macros->currentRow();
|
||||||
|
QString::fromStdString(switcher->macros[idx].Name());
|
||||||
switcher->macros.erase(switcher->macros.begin() + idx);
|
switcher->macros.erase(switcher->macros.begin() + idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,6 +92,7 @@ void AdvSceneSwitcher::on_macroRemove_clicked()
|
||||||
if (ui->macros->count() == 0) {
|
if (ui->macros->count() == 0) {
|
||||||
ui->macroHelp->setVisible(true);
|
ui->macroHelp->setVisible(true);
|
||||||
}
|
}
|
||||||
|
emit MacroRemoved(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_macroUp_clicked()
|
void AdvSceneSwitcher::on_macroUp_clicked()
|
||||||
|
|
@ -147,12 +148,17 @@ void AdvSceneSwitcher::on_macroName_editingFinished()
|
||||||
if (nameValid) {
|
if (nameValid) {
|
||||||
macro->SetName(newName.toUtf8().constData());
|
macro->SetName(newName.toUtf8().constData());
|
||||||
QListWidgetItem *item = ui->macros->currentItem();
|
QListWidgetItem *item = ui->macros->currentItem();
|
||||||
item->setData(Qt::UserRole, newName);
|
// Don't trigger itemChanged()
|
||||||
|
// pause state remains as is
|
||||||
|
ui->macros->blockSignals(true);
|
||||||
item->setText(newName);
|
item->setText(newName);
|
||||||
|
ui->macros->blockSignals(false);
|
||||||
} else {
|
} else {
|
||||||
ui->macroName->setText(oldName);
|
ui->macroName->setText(oldName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit MacroRenamed(oldName, newName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::SetEditMacro(Macro &m)
|
void AdvSceneSwitcher::SetEditMacro(Macro &m)
|
||||||
|
|
@ -196,22 +202,14 @@ void AdvSceneSwitcher::SetEditMacro(Macro &m)
|
||||||
|
|
||||||
Macro *AdvSceneSwitcher::getSelectedMacro()
|
Macro *AdvSceneSwitcher::getSelectedMacro()
|
||||||
{
|
{
|
||||||
Macro *macro = nullptr;
|
|
||||||
QListWidgetItem *item = ui->macros->currentItem();
|
QListWidgetItem *item = ui->macros->currentItem();
|
||||||
|
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return macro;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString name = item->data(Qt::UserRole).toString();
|
QString name = item->text();
|
||||||
for (auto &m : switcher->macros) {
|
return GetMacroByQString(name);
|
||||||
if (name.compare(m.Name().c_str()) == 0) {
|
|
||||||
macro = &m;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return macro;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_macros_currentRowChanged(int idx)
|
void AdvSceneSwitcher::on_macros_currentRowChanged(int idx)
|
||||||
|
|
@ -226,13 +224,26 @@ void AdvSceneSwitcher::on_macros_currentRowChanged(int idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
QListWidgetItem *item = ui->macros->item(idx);
|
QListWidgetItem *item = ui->macros->item(idx);
|
||||||
QString macroName = item->data(Qt::UserRole).toString();
|
QString macroName = item->text();
|
||||||
|
|
||||||
for (auto &m : switcher->macros) {
|
auto macro = GetMacroByQString(macroName);
|
||||||
if (macroName.compare(m.Name().c_str()) == 0) {
|
if (macro) {
|
||||||
SetEditMacro(m);
|
SetEditMacro(*macro);
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_macros_itemChanged(QListWidgetItem *item)
|
||||||
|
{
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
QString name = item->text();
|
||||||
|
|
||||||
|
auto m = GetMacroByQString(name);
|
||||||
|
if (m) {
|
||||||
|
m->SetPaused(item->checkState() != Qt::Checked);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -243,10 +254,18 @@ void AdvSceneSwitcher::setupMacroTab()
|
||||||
|
|
||||||
QListWidgetItem *item = new QListWidgetItem(text, ui->macros);
|
QListWidgetItem *item = new QListWidgetItem(text, ui->macros);
|
||||||
item->setData(Qt::UserRole, text);
|
item->setData(Qt::UserRole, text);
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
if (m.Paused()) {
|
||||||
|
item->setCheckState(Qt::Unchecked);
|
||||||
|
} else {
|
||||||
|
item->setCheckState(Qt::Checked);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->macros.size() == 0) {
|
if (switcher->macros.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->macroAdd, QColor(Qt::green));
|
if (!switcher->disableHints) {
|
||||||
|
addPulse = PulseWidget(ui->macroAdd, QColor(Qt::green));
|
||||||
|
}
|
||||||
ui->macroHelp->setVisible(true);
|
ui->macroHelp->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->macroHelp->setVisible(false);
|
ui->macroHelp->setVisible(false);
|
||||||
|
|
@ -286,5 +305,7 @@ void AdvSceneSwitcher::copyMacro()
|
||||||
QString text = QString::fromStdString(name);
|
QString text = QString::fromStdString(name);
|
||||||
QListWidgetItem *item = new QListWidgetItem(text, ui->macros);
|
QListWidgetItem *item = new QListWidgetItem(text, ui->macros);
|
||||||
item->setData(Qt::UserRole, text);
|
item->setData(Qt::UserRole, text);
|
||||||
|
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||||
|
item->setCheckState(Qt::Checked);
|
||||||
ui->macros->setCurrentItem(item);
|
ui->macros->setCurrentItem(item);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
334
src/macro.cpp
334
src/macro.cpp
|
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
#include "headers/macro-action-edit.hpp"
|
#include "headers/macro-action-edit.hpp"
|
||||||
#include "headers/macro-condition-edit.hpp"
|
#include "headers/macro-condition-edit.hpp"
|
||||||
#include "headers/macro-action-switch-scene.hpp"
|
#include "headers/macro-action-scene-switch.hpp"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#undef max
|
||||||
|
|
||||||
const std::map<LogicType, LogicTypeInfo> MacroCondition::logicTypes = {
|
const std::map<LogicType, LogicTypeInfo> MacroCondition::logicTypes = {
|
||||||
{LogicType::NONE, {"AdvSceneSwitcher.logic.none"}},
|
{LogicType::NONE, {"AdvSceneSwitcher.logic.none"}},
|
||||||
|
|
@ -14,15 +17,26 @@ const std::map<LogicType, LogicTypeInfo> MacroCondition::logicTypes = {
|
||||||
{LogicType::ROOT_NOT, {"AdvSceneSwitcher.logic.not"}},
|
{LogicType::ROOT_NOT, {"AdvSceneSwitcher.logic.not"}},
|
||||||
};
|
};
|
||||||
|
|
||||||
Macro::Macro(std::string name) : _name(name) {}
|
Macro::Macro(const std::string &name)
|
||||||
|
{
|
||||||
|
SetupHotkeys();
|
||||||
|
SetName(name);
|
||||||
|
}
|
||||||
|
|
||||||
Macro::~Macro() {}
|
Macro::~Macro()
|
||||||
|
{
|
||||||
|
ClearHotkeys();
|
||||||
|
}
|
||||||
|
|
||||||
bool Macro::CeckMatch()
|
bool Macro::CeckMatch()
|
||||||
{
|
{
|
||||||
_matched = false;
|
_matched = false;
|
||||||
for (auto &c : _conditions) {
|
for (auto &c : _conditions) {
|
||||||
bool cond = c->CheckCondition();
|
bool cond = c->CheckCondition();
|
||||||
|
if (!cond) {
|
||||||
|
c->ResetDuration();
|
||||||
|
}
|
||||||
|
cond = cond && c->DurationReached();
|
||||||
|
|
||||||
switch (c->GetLogicType()) {
|
switch (c->GetLogicType()) {
|
||||||
case LogicType::NONE:
|
case LogicType::NONE:
|
||||||
|
|
@ -55,6 +69,21 @@ bool Macro::CeckMatch()
|
||||||
_name.c_str());
|
_name.c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
vblog(LOG_INFO, "condition %s returned %d", c->GetId().c_str(),
|
||||||
|
cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched);
|
||||||
|
|
||||||
|
// Condition checks shall still be run even if macro is paused.
|
||||||
|
// Otherwise conditions might behave in unexpected ways when resuming.
|
||||||
|
//
|
||||||
|
// For example, audio could immediately match after unpause, when it
|
||||||
|
// matched before it was paused due to timers not being updated.
|
||||||
|
if (_paused) {
|
||||||
|
vblog(LOG_INFO, "Macro %s is paused", _name.c_str());
|
||||||
|
_matched = false;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _matched;
|
return _matched;
|
||||||
|
|
@ -70,13 +99,29 @@ bool Macro::PerformAction()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (ret && _count != std::numeric_limits<int>::max()) {
|
||||||
|
_count++;
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Macro::SetName(const std::string &name)
|
||||||
|
{
|
||||||
|
_name = name;
|
||||||
|
SetHotkeysDesc();
|
||||||
|
}
|
||||||
|
|
||||||
bool Macro::Save(obs_data_t *obj)
|
bool Macro::Save(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
obs_data_set_string(obj, "name", _name.c_str());
|
obs_data_set_string(obj, "name", _name.c_str());
|
||||||
|
obs_data_set_bool(obj, "pause", _paused);
|
||||||
|
|
||||||
|
obs_data_array_t *pauseHotkey = obs_hotkey_save(_pauseHotkey);
|
||||||
|
obs_data_set_array(obj, "pauseHotkey", pauseHotkey);
|
||||||
|
obs_data_array_release(pauseHotkey);
|
||||||
|
obs_data_array_t *unpauseHotkey = obs_hotkey_save(_unpauseHotkey);
|
||||||
|
obs_data_set_array(obj, "unpauseHotkey", unpauseHotkey);
|
||||||
|
obs_data_array_release(unpauseHotkey);
|
||||||
|
|
||||||
obs_data_array_t *conditions = obs_data_array_create();
|
obs_data_array_t *conditions = obs_data_array_create();
|
||||||
for (auto &c : _conditions) {
|
for (auto &c : _conditions) {
|
||||||
|
|
@ -142,15 +187,27 @@ void setValidLogic(MacroCondition *c, bool root, std::string name)
|
||||||
bool Macro::Load(obs_data_t *obj)
|
bool Macro::Load(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
_name = obs_data_get_string(obj, "name");
|
_name = obs_data_get_string(obj, "name");
|
||||||
bool root = true;
|
_paused = obs_data_get_bool(obj, "pause");
|
||||||
|
|
||||||
|
obs_data_array_t *pauseHotkey = obs_data_get_array(obj, "pauseHotkey");
|
||||||
|
obs_hotkey_load(_pauseHotkey, pauseHotkey);
|
||||||
|
obs_data_array_release(pauseHotkey);
|
||||||
|
|
||||||
|
obs_data_array_t *unpauseHotkey =
|
||||||
|
obs_data_get_array(obj, "unpauseHotkey");
|
||||||
|
obs_hotkey_load(_unpauseHotkey, unpauseHotkey);
|
||||||
|
obs_data_array_release(unpauseHotkey);
|
||||||
|
|
||||||
|
SetHotkeysDesc();
|
||||||
|
|
||||||
|
bool root = true;
|
||||||
obs_data_array_t *conditions = obs_data_get_array(obj, "conditions");
|
obs_data_array_t *conditions = obs_data_get_array(obj, "conditions");
|
||||||
size_t count = obs_data_array_count(conditions);
|
size_t count = obs_data_array_count(conditions);
|
||||||
|
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
obs_data_t *array_obj = obs_data_array_item(conditions, i);
|
obs_data_t *array_obj = obs_data_array_item(conditions, i);
|
||||||
|
|
||||||
int id = obs_data_get_int(array_obj, "id");
|
std::string id = obs_data_get_string(array_obj, "id");
|
||||||
|
|
||||||
auto newEntry = MacroConditionFactory::Create(id);
|
auto newEntry = MacroConditionFactory::Create(id);
|
||||||
if (newEntry) {
|
if (newEntry) {
|
||||||
|
|
@ -160,8 +217,8 @@ bool Macro::Load(obs_data_t *obj)
|
||||||
setValidLogic(c, root, _name);
|
setValidLogic(c, root, _name);
|
||||||
} else {
|
} else {
|
||||||
blog(LOG_WARNING,
|
blog(LOG_WARNING,
|
||||||
"discarding condition entry with unkown id (%d) for macro %s",
|
"discarding condition entry with unkown id (%s) for macro %s",
|
||||||
id, _name.c_str());
|
id.c_str(), _name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
|
|
@ -175,7 +232,7 @@ bool Macro::Load(obs_data_t *obj)
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
obs_data_t *array_obj = obs_data_array_item(actions, i);
|
obs_data_t *array_obj = obs_data_array_item(actions, i);
|
||||||
|
|
||||||
int id = obs_data_get_int(array_obj, "id");
|
std::string id = obs_data_get_string(array_obj, "id");
|
||||||
|
|
||||||
auto newEntry = MacroActionFactory::Create(id);
|
auto newEntry = MacroActionFactory::Create(id);
|
||||||
if (newEntry) {
|
if (newEntry) {
|
||||||
|
|
@ -183,44 +240,154 @@ bool Macro::Load(obs_data_t *obj)
|
||||||
_actions.back()->Load(array_obj);
|
_actions.back()->Load(array_obj);
|
||||||
} else {
|
} else {
|
||||||
blog(LOG_WARNING,
|
blog(LOG_WARNING,
|
||||||
"discarding action entry with unkown id (%d) for macro %s",
|
"discarding action entry with unkown id (%s) for macro %s",
|
||||||
id, _name.c_str());
|
id.c_str(), _name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_array_release(actions);
|
obs_data_array_release(actions);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Macro::ResolveMacroRef()
|
||||||
|
{
|
||||||
|
for (auto &c : _conditions) {
|
||||||
|
MacroRefCondition *ref =
|
||||||
|
dynamic_cast<MacroRefCondition *>(c.get());
|
||||||
|
if (ref) {
|
||||||
|
ref->_macro.UpdateRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto &a : _actions) {
|
||||||
|
MacroRefAction *ref = dynamic_cast<MacroRefAction *>(a.get());
|
||||||
|
if (ref) {
|
||||||
|
ref->_macro.UpdateRef();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Macro::SwitchesScene()
|
bool Macro::SwitchesScene()
|
||||||
{
|
{
|
||||||
MacroActionSwitchScene temp;
|
MacroActionSwitchScene temp;
|
||||||
|
auto sceneSwitchId = temp.GetId();
|
||||||
for (auto &a : _actions) {
|
for (auto &a : _actions) {
|
||||||
if (a->GetId() == temp.GetId()) {
|
if (a->GetId() == sceneSwitchId) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void pauseCB(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
|
||||||
|
bool pressed)
|
||||||
|
{
|
||||||
|
UNUSED_PARAMETER(id);
|
||||||
|
UNUSED_PARAMETER(data);
|
||||||
|
UNUSED_PARAMETER(hotkey);
|
||||||
|
if (pressed) {
|
||||||
|
auto m = static_cast<Macro *>(data);
|
||||||
|
m->SetPaused(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unpauseCB(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
|
||||||
|
bool pressed)
|
||||||
|
{
|
||||||
|
UNUSED_PARAMETER(id);
|
||||||
|
UNUSED_PARAMETER(data);
|
||||||
|
UNUSED_PARAMETER(hotkey);
|
||||||
|
if (pressed) {
|
||||||
|
auto m = static_cast<Macro *>(data);
|
||||||
|
m->SetPaused(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int macroHotkeyID = 0;
|
||||||
|
|
||||||
|
void Macro::SetupHotkeys()
|
||||||
|
{
|
||||||
|
if (_pauseHotkey != OBS_INVALID_HOTKEY_ID ||
|
||||||
|
_unpauseHotkey != OBS_INVALID_HOTKEY_ID) {
|
||||||
|
ClearHotkeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
macroHotkeyID++;
|
||||||
|
|
||||||
|
std::string hotkeyName =
|
||||||
|
"macro_pause_hotkey_" + std::to_string(macroHotkeyID);
|
||||||
|
QString format{obs_module_text("AdvSceneSwitcher.hotkey.macro.pause")};
|
||||||
|
QString hotkeyDesc = format.arg(QString::fromStdString(_name));
|
||||||
|
_pauseHotkey = obs_hotkey_register_frontend(
|
||||||
|
hotkeyName.c_str(), hotkeyDesc.toStdString().c_str(), pauseCB,
|
||||||
|
this);
|
||||||
|
|
||||||
|
macroHotkeyID++;
|
||||||
|
|
||||||
|
hotkeyName = "macro_pause_hotkey_" + _name;
|
||||||
|
format = {obs_module_text("AdvSceneSwitcher.hotkey.macro.unpause")};
|
||||||
|
hotkeyDesc = format.arg(QString::fromStdString(_name));
|
||||||
|
_unpauseHotkey = obs_hotkey_register_frontend(
|
||||||
|
hotkeyName.c_str(), hotkeyDesc.toStdString().c_str(), unpauseCB,
|
||||||
|
this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Macro::ClearHotkeys()
|
||||||
|
{
|
||||||
|
obs_hotkey_unregister(_pauseHotkey);
|
||||||
|
obs_hotkey_unregister(_unpauseHotkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Macro::SetHotkeysDesc()
|
||||||
|
{
|
||||||
|
QString format{obs_module_text("AdvSceneSwitcher.hotkey.macro.pause")};
|
||||||
|
QString hotkeyDesc = format.arg(QString::fromStdString(_name));
|
||||||
|
obs_hotkey_set_description(_pauseHotkey,
|
||||||
|
hotkeyDesc.toStdString().c_str());
|
||||||
|
format = {obs_module_text("AdvSceneSwitcher.hotkey.macro.unpause")};
|
||||||
|
hotkeyDesc = format.arg(QString::fromStdString(_name));
|
||||||
|
obs_hotkey_set_description(_unpauseHotkey,
|
||||||
|
hotkeyDesc.toStdString().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroCondition::Save(obs_data_t *obj)
|
bool MacroCondition::Save(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
obs_data_set_int(obj, "id", GetId());
|
obs_data_set_string(obj, "id", GetId().c_str());
|
||||||
obs_data_set_int(obj, "logic", static_cast<int>(_logic));
|
obs_data_set_int(obj, "logic", static_cast<int>(_logic));
|
||||||
|
_duration.Save(obj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MacroCondition::Load(obs_data_t *obj)
|
bool MacroCondition::Load(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
_logic = static_cast<LogicType>(obs_data_get_int(obj, "logic"));
|
_logic = static_cast<LogicType>(obs_data_get_int(obj, "logic"));
|
||||||
|
_duration.Load(obj);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MacroCondition::SetDurationConstraint(const DurationConstraint &dur)
|
||||||
|
{
|
||||||
|
_duration = dur;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroCondition::SetDurationCondition(DurationCondition cond)
|
||||||
|
{
|
||||||
|
_duration.SetCondition(cond);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroCondition::SetDurationUnit(DurationUnit u)
|
||||||
|
{
|
||||||
|
_duration.SetUnit(u);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroCondition::SetDuration(double seconds)
|
||||||
|
{
|
||||||
|
_duration.SetValue(seconds);
|
||||||
|
}
|
||||||
|
|
||||||
bool MacroAction::Save(obs_data_t *obj)
|
bool MacroAction::Save(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
obs_data_set_int(obj, "id", GetId());
|
obs_data_set_string(obj, "id", GetId().c_str());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -232,7 +399,7 @@ bool MacroAction::Load(obs_data_t *obj)
|
||||||
|
|
||||||
void MacroAction::LogAction()
|
void MacroAction::LogAction()
|
||||||
{
|
{
|
||||||
blog(LOG_INFO, "performed action %d", GetId());
|
vblog(LOG_INFO, "performed action %s", GetId().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::saveMacros(obs_data_t *obj)
|
void SwitcherData::saveMacros(obs_data_t *obj)
|
||||||
|
|
@ -250,8 +417,71 @@ void SwitcherData::saveMacros(obs_data_t *obj)
|
||||||
obs_data_array_release(macroArray);
|
obs_data_array_release(macroArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Temporary helper functions to convert old settings format to new one
|
||||||
|
static std::unordered_map<int, std::string> actionIntToActionString = {
|
||||||
|
{2, "audio"}, {4, "recording"}, {5, "replay_buffer"}, {6, "run"},
|
||||||
|
{3, "streaming"}, {0, "scene_switch"}, {1, "wait"},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void replaceActionIds(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
obs_data_array_t *actions = obs_data_get_array(obj, "actions");
|
||||||
|
size_t count = obs_data_array_count(actions);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
obs_data_t *array_obj = obs_data_array_item(actions, i);
|
||||||
|
auto oldId = obs_data_get_int(array_obj, "id");
|
||||||
|
obs_data_set_string(array_obj, "id",
|
||||||
|
actionIntToActionString[oldId].c_str());
|
||||||
|
obs_data_release(array_obj);
|
||||||
|
}
|
||||||
|
obs_data_array_release(actions);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::unordered_map<int, std::string> conditionIntToConditionString = {
|
||||||
|
{3, "audio"}, {4, "file"}, {10, "idle"}, {5, "media"},
|
||||||
|
{11, "plugin_state"}, {9, "process"}, {8, "recording"}, {2, "region"},
|
||||||
|
{0, "scene"}, {7, "streaming"}, {6, "video"}, {1, "window"},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void replaceConditionIds(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
obs_data_array_t *conditions = obs_data_get_array(obj, "conditions");
|
||||||
|
size_t count = obs_data_array_count(conditions);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
obs_data_t *array_obj = obs_data_array_item(conditions, i);
|
||||||
|
auto oldId = obs_data_get_int(array_obj, "id");
|
||||||
|
obs_data_set_string(
|
||||||
|
array_obj, "id",
|
||||||
|
conditionIntToConditionString[oldId].c_str());
|
||||||
|
obs_data_release(array_obj);
|
||||||
|
}
|
||||||
|
obs_data_array_release(conditions);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convertOldMacroIdsToString(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
obs_data_array_t *macroArray = obs_data_get_array(obj, "macros");
|
||||||
|
size_t count = obs_data_array_count(macroArray);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < count; i++) {
|
||||||
|
obs_data_t *array_obj = obs_data_array_item(macroArray, i);
|
||||||
|
replaceActionIds(array_obj);
|
||||||
|
replaceConditionIds(array_obj);
|
||||||
|
obs_data_release(array_obj);
|
||||||
|
}
|
||||||
|
obs_data_array_release(macroArray);
|
||||||
|
}
|
||||||
|
|
||||||
void SwitcherData::loadMacros(obs_data_t *obj)
|
void SwitcherData::loadMacros(obs_data_t *obj)
|
||||||
{
|
{
|
||||||
|
// TODO: Remove conversion helper in future version
|
||||||
|
std::string previousVersion = obs_data_get_string(obj, "version");
|
||||||
|
if (previousVersion == "2ce0b35921be892c987c7dbb5fc90db38f15f0a6") {
|
||||||
|
convertOldMacroIdsToString(obj);
|
||||||
|
}
|
||||||
|
|
||||||
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");
|
||||||
|
|
@ -264,6 +494,10 @@ void SwitcherData::loadMacros(obs_data_t *obj)
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_array_release(macroArray);
|
obs_data_array_release(macroArray);
|
||||||
|
|
||||||
|
for (auto &m : macros) {
|
||||||
|
m.ResolveMacroRef();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SwitcherData::checkMacros()
|
bool SwitcherData::checkMacros()
|
||||||
|
|
@ -286,7 +520,7 @@ bool SwitcherData::runMacros()
|
||||||
{
|
{
|
||||||
for (auto &m : macros) {
|
for (auto &m : macros) {
|
||||||
if (m.Matched()) {
|
if (m.Matched()) {
|
||||||
blog(LOG_INFO, "running macro: %s", m.Name().c_str());
|
vblog(LOG_INFO, "running macro: %s", m.Name().c_str());
|
||||||
if (!m.PerformAction()) {
|
if (!m.PerformAction()) {
|
||||||
blog(LOG_WARNING, "abort macro: %s",
|
blog(LOG_WARNING, "abort macro: %s",
|
||||||
m.Name().c_str());
|
m.Name().c_str());
|
||||||
|
|
@ -296,3 +530,69 @@ bool SwitcherData::runMacros()
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Macro *GetMacroByName(const char *name)
|
||||||
|
{
|
||||||
|
for (auto &m : switcher->macros) {
|
||||||
|
if (m.Name() == name) {
|
||||||
|
return &m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Macro *GetMacroByQString(const QString &name)
|
||||||
|
{
|
||||||
|
return GetMacroByName(name.toUtf8().constData());
|
||||||
|
}
|
||||||
|
|
||||||
|
MacroRef::MacroRef(std::string name) : _name(name)
|
||||||
|
{
|
||||||
|
UpdateRef();
|
||||||
|
}
|
||||||
|
void MacroRef::UpdateRef()
|
||||||
|
{
|
||||||
|
_ref = GetMacroByName(_name.c_str());
|
||||||
|
}
|
||||||
|
void MacroRef::UpdateRef(std::string newName)
|
||||||
|
{
|
||||||
|
_name = newName;
|
||||||
|
UpdateRef();
|
||||||
|
}
|
||||||
|
void MacroRef::UpdateRef(QString newName)
|
||||||
|
{
|
||||||
|
_name = newName.toStdString();
|
||||||
|
UpdateRef();
|
||||||
|
}
|
||||||
|
void MacroRef::Save(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
if (_ref) {
|
||||||
|
obs_data_set_string(obj, "macro", _ref->Name().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MacroRef::Load(obs_data_t *obj)
|
||||||
|
{
|
||||||
|
_name = obs_data_get_string(obj, "macro");
|
||||||
|
UpdateRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
Macro *MacroRef::get()
|
||||||
|
{
|
||||||
|
return _ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
Macro *MacroRef::operator->()
|
||||||
|
{
|
||||||
|
return _ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroRefCondition::ResolveMacroRef()
|
||||||
|
{
|
||||||
|
_macro.UpdateRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MacroRefAction::ResolveMacroRef()
|
||||||
|
{
|
||||||
|
_macro.UpdateRef();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ void GetWindowList(std::vector<std::string> &windows)
|
||||||
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
|
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
|
||||||
kCGWindowListOptionAll, kCGNullWindowID);
|
kCGWindowListOptionAll, kCGNullWindowID);
|
||||||
for (NSDictionary *app in apps) {
|
for (NSDictionary *app in apps) {
|
||||||
// Construct string from NSString accounting for nil
|
|
||||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||||
UTF8String],
|
UTF8String],
|
||||||
[[app objectForKey:@"kCGWindowName"]
|
[[app objectForKey:@"kCGWindowName"]
|
||||||
|
|
@ -30,53 +29,26 @@ void GetWindowList(std::vector<std::string> &windows)
|
||||||
lengthOfBytesUsingEncoding:
|
lengthOfBytesUsingEncoding:
|
||||||
NSUTF8StringEncoding]);
|
NSUTF8StringEncoding]);
|
||||||
|
|
||||||
// Check if name exists
|
|
||||||
if (!name.empty() &&
|
if (!name.empty() &&
|
||||||
find(windows.begin(), windows.end(), name) ==
|
find(windows.begin(), windows.end(), name) ==
|
||||||
windows.end())
|
windows.end())
|
||||||
windows.emplace_back(name);
|
windows.emplace_back(name);
|
||||||
// Check if owner exists
|
|
||||||
else if (!owner.empty() &&
|
if (!owner.empty() &&
|
||||||
find(windows.begin(), windows.end(), owner) ==
|
find(windows.begin(), windows.end(), owner) ==
|
||||||
windows.end())
|
windows.end())
|
||||||
windows.emplace_back(owner);
|
windows.emplace_back(owner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overloaded
|
|
||||||
void GetWindowList(QStringList &windows)
|
void GetWindowList(QStringList &windows)
|
||||||
{
|
{
|
||||||
windows.clear();
|
windows.clear();
|
||||||
|
std::vector<std::string> temp;
|
||||||
@autoreleasepool {
|
GetWindowList(temp);
|
||||||
NSMutableArray *apps =
|
for (auto &w : temp) {
|
||||||
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
|
windows << QString::fromStdString(w);
|
||||||
kCGWindowListOptionAll, kCGNullWindowID);
|
|
||||||
for (NSDictionary *app in apps) {
|
|
||||||
// Construct string from NSString accounting for nil
|
|
||||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
|
||||||
UTF8String],
|
|
||||||
[[app objectForKey:@"kCGWindowName"]
|
|
||||||
lengthOfBytesUsingEncoding:
|
|
||||||
NSUTF8StringEncoding]);
|
|
||||||
std::string owner(
|
|
||||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
|
||||||
UTF8String],
|
|
||||||
[[app objectForKey:@"kCGWindowOwnerName"]
|
|
||||||
lengthOfBytesUsingEncoding:
|
|
||||||
NSUTF8StringEncoding]);
|
|
||||||
|
|
||||||
// Check if name exists
|
|
||||||
if (!name.empty() &&
|
|
||||||
!windows.contains(QString::fromStdString(name)))
|
|
||||||
windows << QString::fromStdString(name);
|
|
||||||
// Check if owner exists
|
|
||||||
else if (!owner.empty() &&
|
|
||||||
!windows.contains(
|
|
||||||
QString::fromStdString(name)))
|
|
||||||
windows << QString::fromStdString(owner);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,7 +66,6 @@ void GetCurrentWindowTitle(std::string &title)
|
||||||
[[app objectForKey:@"kCGWindowLayer"] intValue];
|
[[app objectForKey:@"kCGWindowLayer"] intValue];
|
||||||
// True if window is frontmost
|
// True if window is frontmost
|
||||||
if (layer == 0) {
|
if (layer == 0) {
|
||||||
// Construct string from NSString accounting for nil
|
|
||||||
std::string name(
|
std::string name(
|
||||||
[[app objectForKey:@"kCGWindowName"]
|
[[app objectForKey:@"kCGWindowName"]
|
||||||
UTF8String],
|
UTF8String],
|
||||||
|
|
@ -130,23 +101,68 @@ std::pair<int, int> getCursorPos()
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
bool isWindowOriginOnScreen(NSDictionary *app, NSScreen *screen,
|
||||||
// not implemented on MacOS as I cannot test it
|
bool fullscreen = false)
|
||||||
bool isMaximized(std::string &title)
|
|
||||||
{
|
{
|
||||||
return false;
|
NSArray *screens = [NSScreen screens];
|
||||||
|
NSRect mainScreenFrame = [screens[0] frame];
|
||||||
|
NSRect screenFrame;
|
||||||
|
if (fullscreen) {
|
||||||
|
screenFrame = [screen frame];
|
||||||
|
} else {
|
||||||
|
screenFrame = [screen visibleFrame];
|
||||||
|
}
|
||||||
|
NSRect windowBounds;
|
||||||
|
CGRectMakeWithDictionaryRepresentation(
|
||||||
|
(CFDictionaryRef)[app objectForKey:@"kCGWindowBounds"],
|
||||||
|
&windowBounds);
|
||||||
|
|
||||||
|
return (windowBounds.origin.x == screenFrame.origin.x &&
|
||||||
|
(mainScreenFrame.size.height - screenFrame.size.height -
|
||||||
|
windowBounds.origin.y ==
|
||||||
|
screenFrame.origin.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isFullscreen(std::string &title)
|
bool isWindowMaximizedOnScreen(NSDictionary *app, NSScreen *screen)
|
||||||
|
{
|
||||||
|
double maximizedTolerance = 0.99;
|
||||||
|
NSRect screenFrame = [screen frame];
|
||||||
|
NSRect windowBounds;
|
||||||
|
CGRectMakeWithDictionaryRepresentation(
|
||||||
|
(CFDictionaryRef)[app objectForKey:@"kCGWindowBounds"],
|
||||||
|
&windowBounds);
|
||||||
|
|
||||||
|
int sumX = windowBounds.origin.x + windowBounds.size.width;
|
||||||
|
int sumY = windowBounds.origin.y + windowBounds.size.height;
|
||||||
|
|
||||||
|
// Return false if window spans over multiple screens
|
||||||
|
if (sumX > screenFrame.size.width) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (sumY > screenFrame.size.height) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((double)sumX / (double)screenFrame.size.width) >
|
||||||
|
maximizedTolerance &&
|
||||||
|
((double)sumY / (double)screenFrame.size.height) >
|
||||||
|
maximizedTolerance;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nameMachesPattern(std::string windowName, std::string pattern)
|
||||||
|
{
|
||||||
|
return QString::fromStdString(windowName)
|
||||||
|
.contains(QRegularExpression(QString::fromStdString(pattern)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isMaximized(const std::string &title)
|
||||||
{
|
{
|
||||||
// Check for match
|
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
NSArray *screens = [NSScreen screens];
|
NSArray *screens = [NSScreen screens];
|
||||||
NSMutableArray *apps =
|
NSMutableArray *apps =
|
||||||
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
|
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
|
||||||
kCGWindowListOptionAll, kCGNullWindowID);
|
kCGWindowListOptionAll, kCGNullWindowID);
|
||||||
for (NSDictionary *app in apps) {
|
for (NSDictionary *app in apps) {
|
||||||
// Construct string from NSString accounting for nil
|
|
||||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||||
UTF8String],
|
UTF8String],
|
||||||
[[app objectForKey:@"kCGWindowName"]
|
[[app objectForKey:@"kCGWindowName"]
|
||||||
|
|
@ -159,51 +175,69 @@ bool isFullscreen(std::string &title)
|
||||||
lengthOfBytesUsingEncoding:
|
lengthOfBytesUsingEncoding:
|
||||||
NSUTF8StringEncoding]);
|
NSUTF8StringEncoding]);
|
||||||
|
|
||||||
// True if switch equals app
|
|
||||||
bool equals = (title == name || title == owner);
|
bool equals = (title == name || title == owner);
|
||||||
// True if switch matches app
|
bool matches = nameMachesPattern(name, title) ||
|
||||||
bool matches = (QString::fromStdString(name).contains(
|
nameMachesPattern(owner, title);
|
||||||
QRegularExpression(
|
|
||||||
QString::fromStdString(
|
|
||||||
title))) ||
|
|
||||||
QString::fromStdString(owner).contains(
|
|
||||||
QRegularExpression(
|
|
||||||
QString::fromStdString(
|
|
||||||
title))));
|
|
||||||
|
|
||||||
// If found, check if fullscreen
|
|
||||||
if (equals || matches) {
|
if (equals || matches) {
|
||||||
// Get window bounds
|
|
||||||
NSRect bounds;
|
|
||||||
CGRectMakeWithDictionaryRepresentation(
|
|
||||||
(CFDictionaryRef)[app
|
|
||||||
objectForKey:@"kCGWindowBounds"],
|
|
||||||
&bounds);
|
|
||||||
|
|
||||||
// Compare to screen bounds
|
|
||||||
for (NSScreen *screen in screens) {
|
for (NSScreen *screen in screens) {
|
||||||
NSRect frame = [screen visibleFrame];
|
if (isWindowOriginOnScreen(app,
|
||||||
|
screen) &&
|
||||||
|
isWindowMaximizedOnScreen(app,
|
||||||
|
screen)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// True if flipped window origin equals screen origin
|
bool isWindowFullscreenOnScreen(NSDictionary *app, NSScreen *screen)
|
||||||
bool origin =
|
{
|
||||||
(bounds.origin.x ==
|
NSRect screenFrame = [screen frame];
|
||||||
frame.origin.x &&
|
NSRect windowBounds;
|
||||||
([screens[0] visibleFrame]
|
CGRectMakeWithDictionaryRepresentation(
|
||||||
.size.height -
|
(CFDictionaryRef)[app objectForKey:@"kCGWindowBounds"],
|
||||||
frame.size.height -
|
&windowBounds);
|
||||||
bounds.origin.y ==
|
|
||||||
frame.origin.y));
|
|
||||||
// True if window size equals screen size
|
|
||||||
bool size = NSEqualSizes(bounds.size,
|
|
||||||
frame.size);
|
|
||||||
|
|
||||||
if (origin && size)
|
return NSEqualSizes(windowBounds.size, screenFrame.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFullscreen(const std::string &title)
|
||||||
|
{
|
||||||
|
@autoreleasepool {
|
||||||
|
NSArray *screens = [NSScreen screens];
|
||||||
|
NSMutableArray *apps =
|
||||||
|
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
|
||||||
|
kCGWindowListOptionAll, kCGNullWindowID);
|
||||||
|
for (NSDictionary *app in apps) {
|
||||||
|
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||||
|
UTF8String],
|
||||||
|
[[app objectForKey:@"kCGWindowName"]
|
||||||
|
lengthOfBytesUsingEncoding:
|
||||||
|
NSUTF8StringEncoding]);
|
||||||
|
std::string owner(
|
||||||
|
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||||
|
UTF8String],
|
||||||
|
[[app objectForKey:@"kCGWindowOwnerName"]
|
||||||
|
lengthOfBytesUsingEncoding:
|
||||||
|
NSUTF8StringEncoding]);
|
||||||
|
|
||||||
|
bool equals = (title == name || title == owner);
|
||||||
|
bool matches = nameMachesPattern(name, title) ||
|
||||||
|
nameMachesPattern(owner, title);
|
||||||
|
if (equals || matches) {
|
||||||
|
for (NSScreen *screen in screens) {
|
||||||
|
if (isWindowOriginOnScreen(app, screen,
|
||||||
|
true) &&
|
||||||
|
isWindowFullscreenOnScreen(app,
|
||||||
|
screen))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -499,7 +499,10 @@ void AdvSceneSwitcher::setupSceneGroupTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->sceneGroups.size() == 0) {
|
if (switcher->sceneGroups.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->sceneGroupAdd, QColor(Qt::green));
|
if (!switcher->disableHints) {
|
||||||
|
addPulse = PulseWidget(ui->sceneGroupAdd,
|
||||||
|
QColor(Qt::green));
|
||||||
|
}
|
||||||
ui->sceneGroupHelp->setVisible(true);
|
ui->sceneGroupHelp->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->sceneGroupHelp->setVisible(false);
|
ui->sceneGroupHelp->setVisible(false);
|
||||||
|
|
|
||||||
|
|
@ -347,7 +347,10 @@ void AdvSceneSwitcher::setupTriggerTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->sceneTriggers.size() == 0) {
|
if (switcher->sceneTriggers.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->triggerAdd, QColor(Qt::green));
|
if (!switcher->disableHints) {
|
||||||
|
addPulse =
|
||||||
|
PulseWidget(ui->triggerAdd, QColor(Qt::green));
|
||||||
|
}
|
||||||
ui->triggerHelp->setVisible(true);
|
ui->triggerHelp->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->triggerHelp->setVisible(false);
|
ui->triggerHelp->setVisible(false);
|
||||||
|
|
@ -381,7 +384,7 @@ void SceneTrigger::load(obs_data_t *obj)
|
||||||
|
|
||||||
static inline void populateTriggers(QComboBox *list)
|
static inline void populateTriggers(QComboBox *list)
|
||||||
{
|
{
|
||||||
AdvSceneSwitcher::addSelectionEntry(
|
addSelectionEntry(
|
||||||
list,
|
list,
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.none"));
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.none"));
|
||||||
|
|
@ -396,7 +399,7 @@ static inline void populateTriggers(QComboBox *list)
|
||||||
|
|
||||||
inline void populateActions(QComboBox *list)
|
inline void populateActions(QComboBox *list)
|
||||||
{
|
{
|
||||||
AdvSceneSwitcher::addSelectionEntry(
|
addSelectionEntry(
|
||||||
list,
|
list,
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.none"));
|
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.none"));
|
||||||
|
|
@ -451,7 +454,7 @@ SceneTriggerWidget::SceneTriggerWidget(QWidget *parent, SceneTrigger *s)
|
||||||
|
|
||||||
populateTriggers(triggers);
|
populateTriggers(triggers);
|
||||||
populateActions(actions);
|
populateActions(actions);
|
||||||
AdvSceneSwitcher::populateAudioSelection(audioSources);
|
populateAudioSelection(audioSources);
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
triggers->setCurrentIndex(static_cast<int>(s->triggerType));
|
triggers->setCurrentIndex(static_cast<int>(s->triggerType));
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
#include <QPropertyAnimation>
|
|
||||||
#include "headers/section.hpp"
|
#include "headers/section.hpp"
|
||||||
#include "headers/utility.hpp"
|
#include "headers/utility.hpp"
|
||||||
|
|
||||||
|
#include <QPropertyAnimation>
|
||||||
|
#include <QEvent>
|
||||||
|
|
||||||
Section::Section(const int animationDuration, QWidget *parent)
|
Section::Section(const int animationDuration, QWidget *parent)
|
||||||
: QWidget(parent), _animationDuration(animationDuration)
|
: QWidget(parent), _animationDuration(animationDuration)
|
||||||
{
|
{
|
||||||
|
|
@ -38,45 +40,74 @@ Section::Section(const int animationDuration, QWidget *parent)
|
||||||
connect(_toggleButton, &QToolButton::toggled, this, &Section::Collapse);
|
connect(_toggleButton, &QToolButton::toggled, this, &Section::Collapse);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Section::Collapse(bool collapsed)
|
void Section::Collapse(bool collapse)
|
||||||
{
|
{
|
||||||
_toggleButton->setChecked(collapsed);
|
_toggleButton->setChecked(collapse);
|
||||||
_toggleButton->setArrowType(!collapsed ? Qt::ArrowType::DownArrow
|
_toggleButton->setArrowType(!collapse ? Qt::ArrowType::DownArrow
|
||||||
: Qt::ArrowType::RightArrow);
|
: Qt::ArrowType::RightArrow);
|
||||||
_toggleAnimation->setDirection(!collapsed
|
_toggleAnimation->setDirection(!collapse
|
||||||
? QAbstractAnimation::Forward
|
? QAbstractAnimation::Forward
|
||||||
: QAbstractAnimation::Backward);
|
: QAbstractAnimation::Backward);
|
||||||
|
_transitioning = true;
|
||||||
|
_collapsed = collapse;
|
||||||
_toggleAnimation->start();
|
_toggleAnimation->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Section::SetContent(QWidget *w)
|
void Section::SetContent(QWidget *w, bool collapsed)
|
||||||
{
|
{
|
||||||
// Clean up previous content
|
CleanUpPreviousContent();
|
||||||
if (_contentArea) {
|
|
||||||
auto oldLayout = _contentArea->layout();
|
|
||||||
if (oldLayout) {
|
|
||||||
clearLayout(oldLayout);
|
|
||||||
delete oldLayout;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete _contentArea;
|
delete _contentArea;
|
||||||
delete _toggleAnimation;
|
|
||||||
|
|
||||||
// Setup contentArea
|
// Setup contentArea
|
||||||
_contentArea = new QScrollArea(this);
|
_contentArea = new QScrollArea(this);
|
||||||
_contentArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
_contentArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
_contentArea->setStyleSheet("QScrollArea { border: none; }");
|
||||||
// Start out collapsed
|
|
||||||
_contentArea->setMaximumHeight(0);
|
_contentArea->setMaximumHeight(0);
|
||||||
_contentArea->setMinimumHeight(0);
|
_contentArea->setMinimumHeight(0);
|
||||||
|
|
||||||
|
w->installEventFilter(this);
|
||||||
|
_content = w;
|
||||||
auto newLayout = new QVBoxLayout();
|
auto newLayout = new QVBoxLayout();
|
||||||
|
newLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
newLayout->addWidget(w);
|
newLayout->addWidget(w);
|
||||||
_contentArea->setLayout(newLayout);
|
_contentArea->setLayout(newLayout);
|
||||||
_mainLayout->addWidget(_contentArea, 1, 0, 1, 3);
|
_mainLayout->addWidget(_contentArea, 1, 0, 1, 3);
|
||||||
|
|
||||||
// Animation Setup
|
_headerHeight = sizeHint().height() - _contentArea->maximumHeight();
|
||||||
|
_contentHeight = newLayout->sizeHint().height();
|
||||||
|
|
||||||
|
if (collapsed) {
|
||||||
|
this->setMinimumHeight(_headerHeight);
|
||||||
|
_contentArea->setMaximumHeight(0);
|
||||||
|
} else {
|
||||||
|
this->setMinimumHeight(_headerHeight + _contentHeight);
|
||||||
|
_contentArea->setMaximumHeight(_contentHeight);
|
||||||
|
}
|
||||||
|
SetupAnimations();
|
||||||
|
Collapse(collapsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Section::AddHeaderWidget(QWidget *w)
|
||||||
|
{
|
||||||
|
_headerWidgetLayout->addWidget(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Section::eventFilter(QObject *obj, QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::Resize && !_transitioning && !_collapsed) {
|
||||||
|
_contentHeight = _content->sizeHint().height();
|
||||||
|
setMaximumHeight(_headerHeight + _contentHeight);
|
||||||
|
setMinimumHeight(_headerHeight + _contentHeight);
|
||||||
|
_contentArea->setMaximumHeight(_contentHeight);
|
||||||
|
SetupAnimations();
|
||||||
|
}
|
||||||
|
return QObject::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Section::SetupAnimations()
|
||||||
|
{
|
||||||
|
delete _toggleAnimation;
|
||||||
|
|
||||||
_toggleAnimation = new QParallelAnimationGroup(this);
|
_toggleAnimation = new QParallelAnimationGroup(this);
|
||||||
_toggleAnimation->addAnimation(
|
_toggleAnimation->addAnimation(
|
||||||
new QPropertyAnimation(this, "minimumHeight"));
|
new QPropertyAnimation(this, "minimumHeight"));
|
||||||
|
|
@ -85,17 +116,13 @@ void Section::SetContent(QWidget *w)
|
||||||
_toggleAnimation->addAnimation(
|
_toggleAnimation->addAnimation(
|
||||||
new QPropertyAnimation(_contentArea, "maximumHeight"));
|
new QPropertyAnimation(_contentArea, "maximumHeight"));
|
||||||
|
|
||||||
const auto collapsedHeight =
|
|
||||||
sizeHint().height() - _contentArea->maximumHeight();
|
|
||||||
auto contentHeight = newLayout->sizeHint().height();
|
|
||||||
|
|
||||||
for (int i = 0; i < _toggleAnimation->animationCount() - 1; ++i) {
|
for (int i = 0; i < _toggleAnimation->animationCount() - 1; ++i) {
|
||||||
QPropertyAnimation *SectionAnimation =
|
QPropertyAnimation *SectionAnimation =
|
||||||
static_cast<QPropertyAnimation *>(
|
static_cast<QPropertyAnimation *>(
|
||||||
_toggleAnimation->animationAt(i));
|
_toggleAnimation->animationAt(i));
|
||||||
SectionAnimation->setDuration(_animationDuration);
|
SectionAnimation->setDuration(_animationDuration);
|
||||||
SectionAnimation->setStartValue(collapsedHeight);
|
SectionAnimation->setStartValue(_headerHeight);
|
||||||
SectionAnimation->setEndValue(collapsedHeight + contentHeight);
|
SectionAnimation->setEndValue(_headerHeight + _contentHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPropertyAnimation *contentAnimation =
|
QPropertyAnimation *contentAnimation =
|
||||||
|
|
@ -103,10 +130,24 @@ void Section::SetContent(QWidget *w)
|
||||||
_toggleAnimation->animationCount() - 1));
|
_toggleAnimation->animationCount() - 1));
|
||||||
contentAnimation->setDuration(_animationDuration);
|
contentAnimation->setDuration(_animationDuration);
|
||||||
contentAnimation->setStartValue(0);
|
contentAnimation->setStartValue(0);
|
||||||
contentAnimation->setEndValue(contentHeight);
|
contentAnimation->setEndValue(_contentHeight);
|
||||||
|
|
||||||
|
QWidget::connect(_toggleAnimation, SIGNAL(finished()), this,
|
||||||
|
SLOT(AnimationFinished()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Section::AddHeaderWidget(QWidget *w)
|
void Section::CleanUpPreviousContent()
|
||||||
{
|
{
|
||||||
_headerWidgetLayout->addWidget(w);
|
if (_contentArea) {
|
||||||
|
auto oldLayout = _contentArea->layout();
|
||||||
|
if (oldLayout) {
|
||||||
|
clearLayout(oldLayout);
|
||||||
|
delete oldLayout;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Section::AnimationFinished()
|
||||||
|
{
|
||||||
|
_transitioning = false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,9 @@ void AdvSceneSwitcher::setupAudioTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->audioSwitches.size() == 0) {
|
if (switcher->audioSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->audioAdd, QColor(Qt::green));
|
if (!switcher->disableHints) {
|
||||||
|
addPulse = PulseWidget(ui->audioAdd, QColor(Qt::green));
|
||||||
|
}
|
||||||
ui->audioHelp->setVisible(true);
|
ui->audioHelp->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->audioHelp->setVisible(false);
|
ui->audioHelp->setVisible(false);
|
||||||
|
|
@ -447,7 +449,7 @@ AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
|
||||||
QWidget::connect(ignoreInactiveSource, SIGNAL(stateChanged(int)), this,
|
QWidget::connect(ignoreInactiveSource, SIGNAL(stateChanged(int)), this,
|
||||||
SLOT(IgnoreInactiveChanged(int)));
|
SLOT(IgnoreInactiveChanged(int)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateAudioSelection(audioSources);
|
populateAudioSelection(audioSources);
|
||||||
populateConditionSelection(condition);
|
populateConditionSelection(condition);
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
|
|
|
||||||
|
|
@ -187,7 +187,10 @@ void AdvSceneSwitcher::setupExecutableTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->executableSwitches.size() == 0) {
|
if (switcher->executableSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->executableAdd, QColor(Qt::green));
|
if (!switcher->disableHints) {
|
||||||
|
addPulse = PulseWidget(ui->executableAdd,
|
||||||
|
QColor(Qt::green));
|
||||||
|
}
|
||||||
ui->exeHelp->setVisible(true);
|
ui->exeHelp->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->exeHelp->setVisible(false);
|
ui->exeHelp->setVisible(false);
|
||||||
|
|
@ -223,7 +226,7 @@ ExecutableSwitchWidget::ExecutableSwitchWidget(QWidget *parent,
|
||||||
QWidget::connect(requiresFocus, SIGNAL(stateChanged(int)), this,
|
QWidget::connect(requiresFocus, SIGNAL(stateChanged(int)), this,
|
||||||
SLOT(FocusChanged(int)));
|
SLOT(FocusChanged(int)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateProcessSelection(processes);
|
populateProcessSelection(processes);
|
||||||
|
|
||||||
processes->setEditable(true);
|
processes->setEditable(true);
|
||||||
processes->setMaxVisibleItems(20);
|
processes->setMaxVisibleItems(20);
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ void SwitcherData::writeSceneInfoToFile()
|
||||||
obs_source_release(currentSource);
|
obs_source_release(currentSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SwitcherData::writeToStatusFile(QString msg)
|
void SwitcherData::writeToStatusFile(const QString &msg)
|
||||||
{
|
{
|
||||||
if (!fileIO.writeEnabled || fileIO.writePath.empty()) {
|
if (!fileIO.writeEnabled || fileIO.writePath.empty()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -415,7 +415,9 @@ void AdvSceneSwitcher::setupFileTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->fileSwitches.size() == 0) {
|
if (switcher->fileSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->fileAdd, QColor(Qt::green));
|
if (!switcher->disableHints) {
|
||||||
|
addPulse = PulseWidget(ui->fileAdd, QColor(Qt::green));
|
||||||
|
}
|
||||||
ui->fileHelp->setVisible(true);
|
ui->fileHelp->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->fileHelp->setVisible(false);
|
ui->fileHelp->setVisible(false);
|
||||||
|
|
|
||||||
|
|
@ -228,10 +228,9 @@ SwitchWidget::SwitchWidget(QWidget *parent, SceneSwitcherEntry *s,
|
||||||
SIGNAL(SceneGroupRenamed(const QString &, const QString &)),
|
SIGNAL(SceneGroupRenamed(const QString &, const QString &)),
|
||||||
this, SLOT(SceneGroupRename(const QString &, const QString &)));
|
this, SLOT(SceneGroupRename(const QString &, const QString &)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateSceneSelection(scenes, usePreviousScene,
|
populateSceneSelection(scenes, usePreviousScene, addSceneGroup,
|
||||||
addSceneGroup);
|
&switcher->sceneGroups);
|
||||||
AdvSceneSwitcher::populateTransitionSelection(transitions,
|
populateTransitionSelection(transitions, addCurrentTransition);
|
||||||
addCurrentTransition);
|
|
||||||
|
|
||||||
switchData = s;
|
switchData = s;
|
||||||
showSwitchData();
|
showSwitchData();
|
||||||
|
|
|
||||||
|
|
@ -244,7 +244,9 @@ void AdvSceneSwitcher::setupMediaTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->mediaSwitches.size() == 0) {
|
if (switcher->mediaSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->mediaAdd, QColor(Qt::green));
|
if (!switcher->disableHints) {
|
||||||
|
addPulse = PulseWidget(ui->mediaAdd, QColor(Qt::green));
|
||||||
|
}
|
||||||
ui->mediaHelp->setVisible(true);
|
ui->mediaHelp->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->mediaHelp->setVisible(false);
|
ui->mediaHelp->setVisible(false);
|
||||||
|
|
@ -458,7 +460,7 @@ MediaSwitchWidget::MediaSwitchWidget(QWidget *parent, MediaSwitch *s)
|
||||||
QWidget::connect(time, SIGNAL(valueChanged(int)), this,
|
QWidget::connect(time, SIGNAL(valueChanged(int)), this,
|
||||||
SLOT(TimeChanged(int)));
|
SLOT(TimeChanged(int)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateMediaSelection(mediaSources);
|
populateMediaSelection(mediaSources);
|
||||||
populateMediaStates(states);
|
populateMediaStates(states);
|
||||||
populateTimeRestrictions(timeRestrictions);
|
populateTimeRestrictions(timeRestrictions);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,13 +17,16 @@ Most of this code is based on https://github.com/Palakis/obs-websocket
|
||||||
#define PARAM_CLIENT_ENABLE "ClientEnabled"
|
#define PARAM_CLIENT_ENABLE "ClientEnabled"
|
||||||
#define PARAM_CLIENT_PORT "ClientPort"
|
#define PARAM_CLIENT_PORT "ClientPort"
|
||||||
#define PARAM_ADDRESS "Address"
|
#define PARAM_ADDRESS "Address"
|
||||||
#define PARAM_CLIENT_SENDALL "SendAll"
|
#define PARAM_CLIENT_SEND_SCENE_CHANGE "SendSceneChange"
|
||||||
|
#define PARAM_CLIENT_SEND_SCENE_CHANGE_ALL "SendSceneChangeAll"
|
||||||
|
#define PARAM_CLIENT_SENDPREVIEW "SendPreview"
|
||||||
|
|
||||||
#define RECONNECT_DELAY 10
|
#define RECONNECT_DELAY 10
|
||||||
|
|
||||||
#define SCENE_ENTRY "scene"
|
#define SCENE_ENTRY "scene"
|
||||||
#define TRANSITION_ENTRY "transition"
|
#define TRANSITION_ENTRY "transition"
|
||||||
#define TRANSITION_DURATION "duration"
|
#define TRANSITION_DURATION "duration"
|
||||||
|
#define SET_PREVIEW "preview"
|
||||||
|
|
||||||
using websocketpp::lib::placeholders::_1;
|
using websocketpp::lib::placeholders::_1;
|
||||||
using websocketpp::lib::placeholders::_2;
|
using websocketpp::lib::placeholders::_2;
|
||||||
|
|
@ -36,7 +39,9 @@ NetworkConfig::NetworkConfig()
|
||||||
ClientEnabled(false),
|
ClientEnabled(false),
|
||||||
Address(""),
|
Address(""),
|
||||||
ClientPort(55555),
|
ClientPort(55555),
|
||||||
SendAll(true)
|
SendSceneChange(true),
|
||||||
|
SendSceneChangeAll(true),
|
||||||
|
SendPreview(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,7 +56,11 @@ void NetworkConfig::Load(obs_data_t *obj)
|
||||||
ClientEnabled = obs_data_get_bool(obj, PARAM_CLIENT_ENABLE);
|
ClientEnabled = obs_data_get_bool(obj, PARAM_CLIENT_ENABLE);
|
||||||
Address = obs_data_get_string(obj, PARAM_ADDRESS);
|
Address = obs_data_get_string(obj, PARAM_ADDRESS);
|
||||||
ClientPort = obs_data_get_int(obj, PARAM_CLIENT_PORT);
|
ClientPort = obs_data_get_int(obj, PARAM_CLIENT_PORT);
|
||||||
SendAll = obs_data_get_bool(obj, PARAM_CLIENT_SENDALL);
|
SendSceneChange =
|
||||||
|
obs_data_get_bool(obj, PARAM_CLIENT_SEND_SCENE_CHANGE);
|
||||||
|
SendSceneChangeAll =
|
||||||
|
obs_data_get_bool(obj, PARAM_CLIENT_SEND_SCENE_CHANGE_ALL);
|
||||||
|
SendPreview = obs_data_get_bool(obj, PARAM_CLIENT_SENDPREVIEW);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkConfig::Save(obs_data_t *obj)
|
void NetworkConfig::Save(obs_data_t *obj)
|
||||||
|
|
@ -63,7 +72,10 @@ void NetworkConfig::Save(obs_data_t *obj)
|
||||||
obs_data_set_bool(obj, PARAM_CLIENT_ENABLE, ClientEnabled);
|
obs_data_set_bool(obj, PARAM_CLIENT_ENABLE, ClientEnabled);
|
||||||
obs_data_set_string(obj, PARAM_ADDRESS, Address.c_str());
|
obs_data_set_string(obj, PARAM_ADDRESS, Address.c_str());
|
||||||
obs_data_set_int(obj, PARAM_CLIENT_PORT, ClientPort);
|
obs_data_set_int(obj, PARAM_CLIENT_PORT, ClientPort);
|
||||||
obs_data_set_bool(obj, PARAM_CLIENT_SENDALL, SendAll);
|
obs_data_set_bool(obj, PARAM_CLIENT_SEND_SCENE_CHANGE, SendSceneChange);
|
||||||
|
obs_data_set_bool(obj, PARAM_CLIENT_SEND_SCENE_CHANGE_ALL,
|
||||||
|
SendSceneChangeAll);
|
||||||
|
obs_data_set_bool(obj, PARAM_CLIENT_SENDPREVIEW, SendPreview);
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkConfig::SetDefaults(obs_data_t *obj)
|
void NetworkConfig::SetDefaults(obs_data_t *obj)
|
||||||
|
|
@ -75,7 +87,11 @@ void NetworkConfig::SetDefaults(obs_data_t *obj)
|
||||||
obs_data_set_default_bool(obj, PARAM_CLIENT_ENABLE, ClientEnabled);
|
obs_data_set_default_bool(obj, PARAM_CLIENT_ENABLE, ClientEnabled);
|
||||||
obs_data_set_default_string(obj, PARAM_ADDRESS, Address.c_str());
|
obs_data_set_default_string(obj, PARAM_ADDRESS, Address.c_str());
|
||||||
obs_data_set_default_int(obj, PARAM_CLIENT_PORT, ClientPort);
|
obs_data_set_default_int(obj, PARAM_CLIENT_PORT, ClientPort);
|
||||||
obs_data_set_default_bool(obj, PARAM_CLIENT_SENDALL, SendAll);
|
obs_data_set_default_bool(obj, PARAM_CLIENT_SEND_SCENE_CHANGE,
|
||||||
|
SendSceneChange);
|
||||||
|
obs_data_set_default_bool(obj, PARAM_CLIENT_SEND_SCENE_CHANGE_ALL,
|
||||||
|
SendSceneChangeAll);
|
||||||
|
obs_data_set_default_bool(obj, PARAM_CLIENT_SENDPREVIEW, SendPreview);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string NetworkConfig::GetClientUri()
|
std::string NetworkConfig::GetClientUri()
|
||||||
|
|
@ -83,6 +99,21 @@ std::string NetworkConfig::GetClientUri()
|
||||||
return "ws://" + Address + ":" + std::to_string(ClientPort);
|
return "ws://" + Address + ":" + std::to_string(ClientPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NetworkConfig::ShouldSendSceneChange()
|
||||||
|
{
|
||||||
|
return ServerEnabled && SendSceneChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NetworkConfig::ShouldSendFrontendSceneChange()
|
||||||
|
{
|
||||||
|
return ShouldSendSceneChange() && SendSceneChangeAll;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NetworkConfig::ShouldSendPrviewSceneChange()
|
||||||
|
{
|
||||||
|
return ServerEnabled && SendPreview;
|
||||||
|
}
|
||||||
|
|
||||||
WSServer::WSServer()
|
WSServer::WSServer()
|
||||||
: QObject(nullptr), _connections(), _clMutex(QMutex::Recursive)
|
: QObject(nullptr), _connections(), _clMutex(QMutex::Recursive)
|
||||||
{
|
{
|
||||||
|
|
@ -192,7 +223,7 @@ void WSServer::stop()
|
||||||
blog(LOG_INFO, "server stopped successfully");
|
blog(LOG_INFO, "server stopped successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
void WSServer::sendMessage(sceneSwitchInfo sceneSwitch)
|
void WSServer::sendMessage(sceneSwitchInfo sceneSwitch, bool preview)
|
||||||
{
|
{
|
||||||
if (!sceneSwitch.scene) {
|
if (!sceneSwitch.scene) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -204,6 +235,7 @@ void WSServer::sendMessage(sceneSwitchInfo sceneSwitch)
|
||||||
obs_data_set_string(data, TRANSITION_ENTRY,
|
obs_data_set_string(data, TRANSITION_ENTRY,
|
||||||
GetWeakSourceName(sceneSwitch.transition).c_str());
|
GetWeakSourceName(sceneSwitch.transition).c_str());
|
||||||
obs_data_set_int(data, TRANSITION_DURATION, sceneSwitch.duration);
|
obs_data_set_int(data, TRANSITION_DURATION, sceneSwitch.duration);
|
||||||
|
obs_data_set_bool(data, SET_PREVIEW, preview);
|
||||||
std::string message = obs_data_get_json(data);
|
std::string message = obs_data_get_json(data);
|
||||||
obs_data_release(data);
|
obs_data_release(data);
|
||||||
|
|
||||||
|
|
@ -248,7 +280,8 @@ std::string processMessage(std::string payload)
|
||||||
|
|
||||||
if (!obs_data_has_user_value(data, SCENE_ENTRY) ||
|
if (!obs_data_has_user_value(data, SCENE_ENTRY) ||
|
||||||
!obs_data_has_user_value(data, TRANSITION_ENTRY) ||
|
!obs_data_has_user_value(data, TRANSITION_ENTRY) ||
|
||||||
!obs_data_has_user_value(data, TRANSITION_DURATION)) {
|
!obs_data_has_user_value(data, TRANSITION_DURATION) ||
|
||||||
|
!obs_data_has_user_value(data, SET_PREVIEW)) {
|
||||||
return "missing request parameters";
|
return "missing request parameters";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,6 +289,7 @@ std::string processMessage(std::string payload)
|
||||||
std::string transitionName =
|
std::string transitionName =
|
||||||
obs_data_get_string(data, TRANSITION_ENTRY);
|
obs_data_get_string(data, TRANSITION_ENTRY);
|
||||||
int duration = obs_data_get_int(data, TRANSITION_DURATION);
|
int duration = obs_data_get_int(data, TRANSITION_DURATION);
|
||||||
|
bool preview = obs_data_get_bool(data, SET_PREVIEW);
|
||||||
|
|
||||||
obs_data_release(data);
|
obs_data_release(data);
|
||||||
|
|
||||||
|
|
@ -271,8 +305,11 @@ std::string processMessage(std::string payload)
|
||||||
ret += " - ignoring invalid transition: '" + transitionName +
|
ret += " - ignoring invalid transition: '" + transitionName +
|
||||||
"'";
|
"'";
|
||||||
}
|
}
|
||||||
|
if (preview) {
|
||||||
switchScene({scene, transition, duration});
|
switchPreviewScene(scene);
|
||||||
|
} else {
|
||||||
|
switchScene({scene, transition, duration});
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -478,7 +515,12 @@ void AdvSceneSwitcher::setupNetworkTab()
|
||||||
ui->clientSettings->setChecked(switcher->networkConfig.ClientEnabled);
|
ui->clientSettings->setChecked(switcher->networkConfig.ClientEnabled);
|
||||||
ui->clientHostname->setText(switcher->networkConfig.Address.c_str());
|
ui->clientHostname->setText(switcher->networkConfig.Address.c_str());
|
||||||
ui->clientPort->setValue(switcher->networkConfig.ClientPort);
|
ui->clientPort->setValue(switcher->networkConfig.ClientPort);
|
||||||
ui->restrictSend->setChecked(!switcher->networkConfig.SendAll);
|
ui->sendSceneChange->setChecked(
|
||||||
|
switcher->networkConfig.SendSceneChange);
|
||||||
|
ui->restrictSend->setChecked(
|
||||||
|
!switcher->networkConfig.SendSceneChangeAll);
|
||||||
|
ui->sendPreview->setChecked(switcher->networkConfig.SendPreview);
|
||||||
|
ui->restrictSend->setDisabled(!switcher->networkConfig.SendSceneChange);
|
||||||
|
|
||||||
QTimer *statusTimer = new QTimer(this);
|
QTimer *statusTimer = new QTimer(this);
|
||||||
connect(statusTimer, SIGNAL(timeout()), this,
|
connect(statusTimer, SIGNAL(timeout()), this,
|
||||||
|
|
@ -592,6 +634,17 @@ void AdvSceneSwitcher::on_clientPort_valueChanged(int value)
|
||||||
switcher->networkConfig.ClientPort = value;
|
switcher->networkConfig.ClientPort = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sendSceneChange_stateChanged(int state)
|
||||||
|
{
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->networkConfig.SendSceneChange = state;
|
||||||
|
ui->restrictSend->setDisabled(!state);
|
||||||
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_restrictSend_stateChanged(int state)
|
void AdvSceneSwitcher::on_restrictSend_stateChanged(int state)
|
||||||
{
|
{
|
||||||
if (loading) {
|
if (loading) {
|
||||||
|
|
@ -599,7 +652,17 @@ void AdvSceneSwitcher::on_restrictSend_stateChanged(int state)
|
||||||
}
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(switcher->m);
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
switcher->networkConfig.SendAll = !state;
|
switcher->networkConfig.SendSceneChangeAll = !state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AdvSceneSwitcher::on_sendPreview_stateChanged(int state)
|
||||||
|
{
|
||||||
|
if (loading) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(switcher->m);
|
||||||
|
switcher->networkConfig.SendPreview = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvSceneSwitcher::on_clientReconnect_clicked()
|
void AdvSceneSwitcher::on_clientReconnect_clicked()
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,6 @@ void SwitcherData::savePauseSwitches(obs_data_t *obj)
|
||||||
obs_data_release(array_obj);
|
obs_data_release(array_obj);
|
||||||
}
|
}
|
||||||
obs_data_set_array(obj, "pauseEntries", pauseScenesArray);
|
obs_data_set_array(obj, "pauseEntries", pauseScenesArray);
|
||||||
obs_data_set_int(obj, "oldPauseValuesImported", 1);
|
|
||||||
obs_data_array_release(pauseScenesArray);
|
obs_data_array_release(pauseScenesArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,7 +264,9 @@ void AdvSceneSwitcher::setupPauseTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->pauseEntries.size() == 0) {
|
if (switcher->pauseEntries.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->pauseAdd, QColor(Qt::green));
|
if (!switcher->disableHints) {
|
||||||
|
addPulse = PulseWidget(ui->pauseAdd, QColor(Qt::green));
|
||||||
|
}
|
||||||
ui->pauseHelp->setVisible(true);
|
ui->pauseHelp->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->pauseHelp->setVisible(false);
|
ui->pauseHelp->setVisible(false);
|
||||||
|
|
@ -316,7 +317,7 @@ PauseEntryWidget::PauseEntryWidget(QWidget *parent, PauseEntry *s)
|
||||||
|
|
||||||
populatePauseTypes(pauseTypes);
|
populatePauseTypes(pauseTypes);
|
||||||
populatePauseTargets(pauseTargets);
|
populatePauseTargets(pauseTargets);
|
||||||
AdvSceneSwitcher::populateWindowSelection(windows);
|
populateWindowSelection(windows);
|
||||||
|
|
||||||
windows->setEditable(true);
|
windows->setEditable(true);
|
||||||
windows->setMaxVisibleItems(20);
|
windows->setMaxVisibleItems(20);
|
||||||
|
|
|
||||||
|
|
@ -125,15 +125,20 @@ void AdvSceneSwitcher::setupRandomTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->randomSwitches.size() == 0) {
|
if (switcher->randomSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->randomAdd, QColor(Qt::green));
|
if (!switcher->disableHints) {
|
||||||
|
addPulse =
|
||||||
|
PulseWidget(ui->randomAdd, QColor(Qt::green));
|
||||||
|
}
|
||||||
ui->randomHelp->setVisible(true);
|
ui->randomHelp->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->randomHelp->setVisible(false);
|
ui->randomHelp->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->switchIfNotMatching != RANDOM_SWITCH) {
|
if (switcher->switchIfNotMatching != RANDOM_SWITCH) {
|
||||||
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
if (!switcher->disableHints) {
|
||||||
QColor(0, 0, 0, 0), "QLabel ");
|
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
||||||
|
QColor(0, 0, 0, 0), "QLabel ");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ui->randomDisabledWarning->setVisible(false);
|
ui->randomDisabledWarning->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -245,7 +245,10 @@ void AdvSceneSwitcher::setupRegionTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->screenRegionSwitches.size() == 0) {
|
if (switcher->screenRegionSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->screenRegionAdd, QColor(Qt::green));
|
if (!switcher->disableHints) {
|
||||||
|
addPulse = PulseWidget(ui->screenRegionAdd,
|
||||||
|
QColor(Qt::green));
|
||||||
|
}
|
||||||
ui->regionHelp->setVisible(true);
|
ui->regionHelp->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->regionHelp->setVisible(false);
|
ui->regionHelp->setVisible(false);
|
||||||
|
|
@ -320,8 +323,8 @@ ScreenRegionWidget::ScreenRegionWidget(QWidget *parent, ScreenRegionSwitch *s)
|
||||||
QWidget::connect(maxY, SIGNAL(valueChanged(int)), this,
|
QWidget::connect(maxY, SIGNAL(valueChanged(int)), this,
|
||||||
SLOT(MaxYChanged(int)));
|
SLOT(MaxYChanged(int)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateSceneSelection(
|
populateSceneSelection(
|
||||||
excludeScenes, false, false, true,
|
excludeScenes, false, false, nullptr, true,
|
||||||
obs_module_text(
|
obs_module_text(
|
||||||
"AdvSceneSwitcher.screenRegionTab.excludeScenes.None"),
|
"AdvSceneSwitcher.screenRegionTab.excludeScenes.None"),
|
||||||
true);
|
true);
|
||||||
|
|
|
||||||
|
|
@ -289,7 +289,10 @@ void AdvSceneSwitcher::setupSequenceTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->sceneSequenceSwitches.size() == 0) {
|
if (switcher->sceneSequenceSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->sceneSequenceAdd, QColor(Qt::green));
|
if (!switcher->disableHints) {
|
||||||
|
addPulse = PulseWidget(ui->sceneSequenceAdd,
|
||||||
|
QColor(Qt::green));
|
||||||
|
}
|
||||||
ui->sequenceHelp->setVisible(true);
|
ui->sequenceHelp->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->sequenceHelp->setVisible(false);
|
ui->sequenceHelp->setVisible(false);
|
||||||
|
|
@ -440,8 +443,6 @@ void SceneSequenceSwitch::prepareUninterruptibleMatch(
|
||||||
{
|
{
|
||||||
int dur = delay.seconds * 1000;
|
int dur = delay.seconds * 1000;
|
||||||
if (dur > 0) {
|
if (dur > 0) {
|
||||||
switcher->waitScene = obs_weak_source_get_source(currentScene);
|
|
||||||
obs_source_release(switcher->waitScene);
|
|
||||||
linger = dur;
|
linger = dur;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -588,7 +589,7 @@ SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s,
|
||||||
QWidget::connect(reduce, SIGNAL(clicked()), this,
|
QWidget::connect(reduce, SIGNAL(clicked()), this,
|
||||||
SLOT(ReduceClicked()));
|
SLOT(ReduceClicked()));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateSceneSelection(startScenes, false);
|
populateSceneSelection(startScenes);
|
||||||
interruptible->setToolTip(obs_module_text(
|
interruptible->setToolTip(obs_module_text(
|
||||||
"AdvSceneSwitcher.sceneSequenceTab.interruptibleHint"));
|
"AdvSceneSwitcher.sceneSequenceTab.interruptibleHint"));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,9 @@ void AdvSceneSwitcher::setupTimeTab()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (switcher->timeSwitches.size() == 0) {
|
if (switcher->timeSwitches.size() == 0) {
|
||||||
addPulse = PulseWidget(ui->timeAdd, QColor(Qt::green));
|
if (!switcher->disableHints) {
|
||||||
|
addPulse = PulseWidget(ui->timeAdd, QColor(Qt::green));
|
||||||
|
}
|
||||||
ui->timeHelp->setVisible(true);
|
ui->timeHelp->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->timeHelp->setVisible(false);
|
ui->timeHelp->setVisible(false);
|
||||||
|
|
|
||||||
|
|
@ -240,7 +240,7 @@ std::pair<obs_weak_source_t *, int> getNextTransition(obs_weak_source_t *scene1,
|
||||||
return std::make_pair(ws, duration);
|
return std::make_pair(ws, duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
void overwriteTransitionOverride(sceneSwitchInfo ssi, transitionData &td)
|
void overwriteTransitionOverride(const sceneSwitchInfo &ssi, transitionData &td)
|
||||||
{
|
{
|
||||||
obs_source_t *scene = obs_weak_source_get_source(ssi.scene);
|
obs_source_t *scene = obs_weak_source_get_source(ssi.scene);
|
||||||
obs_data_t *data = obs_source_get_private_settings(scene);
|
obs_data_t *data = obs_source_get_private_settings(scene);
|
||||||
|
|
@ -257,7 +257,7 @@ void overwriteTransitionOverride(sceneSwitchInfo ssi, transitionData &td)
|
||||||
obs_source_release(scene);
|
obs_source_release(scene);
|
||||||
}
|
}
|
||||||
|
|
||||||
void restoreTransitionOverride(obs_source_t *scene, transitionData td)
|
void restoreTransitionOverride(obs_source_t *scene, const transitionData &td)
|
||||||
{
|
{
|
||||||
obs_data_t *data = obs_source_get_private_settings(scene);
|
obs_data_t *data = obs_source_get_private_settings(scene);
|
||||||
|
|
||||||
|
|
@ -267,7 +267,7 @@ void restoreTransitionOverride(obs_source_t *scene, transitionData td)
|
||||||
obs_data_release(data);
|
obs_data_release(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setNextTransition(sceneSwitchInfo &sceneSwitch,
|
void setNextTransition(const sceneSwitchInfo &sceneSwitch,
|
||||||
obs_source_t *currentSource, transitionData &td)
|
obs_source_t *currentSource, transitionData &td)
|
||||||
{
|
{
|
||||||
// Priority:
|
// Priority:
|
||||||
|
|
@ -495,7 +495,7 @@ TransitionSwitchWidget::TransitionSwitchWidget(QWidget *parent,
|
||||||
QWidget::connect(duration, SIGNAL(valueChanged(double)), this,
|
QWidget::connect(duration, SIGNAL(valueChanged(double)), this,
|
||||||
SLOT(DurationChanged(double)));
|
SLOT(DurationChanged(double)));
|
||||||
|
|
||||||
AdvSceneSwitcher::populateSceneSelection(scenes2, false);
|
populateSceneSelection(scenes2);
|
||||||
|
|
||||||
if (s) {
|
if (s) {
|
||||||
scenes2->setCurrentText(GetWeakSourceName(s->scene2).c_str());
|
scenes2->setCurrentText(GetWeakSourceName(s->scene2).c_str());
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user