mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-03-21 17:34:57 -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
|
||||
CMAKE_GENERATOR: "Visual Studio 16 2019"
|
||||
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
|
||||
WINDOWS_DEPS_VERSION: '2017'
|
||||
WINDOWS_DEPS_VERSION: '2019'
|
||||
steps:
|
||||
- name: Add msbuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
|
|
|
|||
|
|
@ -62,7 +62,6 @@ set(advanced-scene-switcher_HEADERS
|
|||
${advanced-scene-switcher_HEADERS}
|
||||
src/headers/advanced-scene-switcher.hpp
|
||||
src/headers/switcher-data-structs.hpp
|
||||
src/headers/utility.hpp
|
||||
src/headers/scene-group.hpp
|
||||
src/headers/scene-trigger.hpp
|
||||
src/headers/switch-audio.hpp
|
||||
|
|
@ -82,32 +81,44 @@ set(advanced-scene-switcher_HEADERS
|
|||
src/headers/switch-generic.hpp
|
||||
src/headers/macro-action-edit.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-replay-buffer.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-switch-scene.hpp
|
||||
src/headers/macro-action-wait.hpp
|
||||
src/headers/macro-condition-edit.hpp
|
||||
src/headers/macro-condition-audio.hpp
|
||||
src/headers/macro-condition-counter.hpp
|
||||
src/headers/macro-condition-file.hpp
|
||||
src/headers/macro-condition-idle.hpp
|
||||
src/headers/macro-condition-interval.hpp
|
||||
src/headers/macro-condition-media.hpp
|
||||
src/headers/macro-condition-plugin-state.hpp
|
||||
src/headers/macro-condition-process.hpp
|
||||
src/headers/macro-condition-recording.hpp
|
||||
src/headers/macro-condition-region.hpp
|
||||
src/headers/macro-condition-scene.hpp
|
||||
src/headers/macro-condition-source.hpp
|
||||
src/headers/macro-condition-streaming.hpp
|
||||
src/headers/macro-condition-video.hpp
|
||||
src/headers/macro-condition-virt-desktop.hpp
|
||||
src/headers/macro-condition-window.hpp
|
||||
src/headers/macro.hpp
|
||||
src/headers/macro-selection.hpp
|
||||
src/headers/curl-helper.hpp
|
||||
src/headers/screenshot-helper.hpp
|
||||
src/headers/name-dialog.hpp
|
||||
src/headers/duration-control.hpp
|
||||
src/headers/section.hpp
|
||||
src/headers/platform-funcs.hpp
|
||||
src/headers/utility.hpp
|
||||
src/headers/volume-control.hpp
|
||||
src/headers/version.h
|
||||
)
|
||||
|
|
@ -139,33 +150,44 @@ set(advanced-scene-switcher_SOURCES
|
|||
src/switch-generic.cpp
|
||||
src/macro-action-edit.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-replay-buffer.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-switch-scene.cpp
|
||||
src/macro-action-wait.cpp
|
||||
src/macro-condition-edit.cpp
|
||||
src/macro-condition-audio.cpp
|
||||
src/macro-condition-counter.cpp
|
||||
src/macro-condition-file.cpp
|
||||
src/macro-condition-idle.cpp
|
||||
src/macro-condition-interval.cpp
|
||||
src/macro-condition-media.cpp
|
||||
src/macro-condition-plugin-state.cpp
|
||||
src/macro-condition-process.cpp
|
||||
src/macro-condition-recording.cpp
|
||||
src/macro-condition-region.cpp
|
||||
src/macro-condition-scene.cpp
|
||||
src/macro-condition-source.cpp
|
||||
src/macro-condition-streaming.cpp
|
||||
src/macro-condition-video.cpp
|
||||
src/macro-condition-virt-desktop.cpp
|
||||
src/macro-condition-window.cpp
|
||||
src/macro.cpp
|
||||
src/macro-selection.cpp
|
||||
src/macro-tab.cpp
|
||||
src/curl-helper.cpp
|
||||
src/screenshot-helper.cpp
|
||||
src/name-dialog.cpp
|
||||
src/duration-control.cpp
|
||||
src/section.cpp
|
||||
src/utility.cpp
|
||||
src/volume-control.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.port="Port"
|
||||
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.server.status.currentStatus="Aktueller Status"
|
||||
AdvSceneSwitcher.networkTab.server.status.notRunning="Nicht gestartet"
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ AdvSceneSwitcher.generalTab.priority.macro="Macro"
|
|||
AdvSceneSwitcher.macroTab.title="Macro"
|
||||
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.editConditionHelp="This section allows you to define Macro conditions.\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."
|
||||
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.\nThen click the plus button below to add a new action."
|
||||
AdvSceneSwitcher.macroTab.edit="Edit macro"
|
||||
AdvSceneSwitcher.macroTab.edit.logic="Logic type:"
|
||||
AdvSceneSwitcher.macroTab.edit.condition="Condition type:"
|
||||
|
|
@ -68,6 +68,7 @@ AdvSceneSwitcher.macroTab.name="Name:"
|
|||
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
|
||||
AdvSceneSwitcher.macroTab.exists="Macro name exists already"
|
||||
AdvSceneSwitcher.macroTab.copy="Create copy"
|
||||
|
||||
; Macro Logic
|
||||
AdvSceneSwitcher.logic.none="Ignore entry"
|
||||
AdvSceneSwitcher.logic.and="And"
|
||||
|
|
@ -76,17 +77,18 @@ AdvSceneSwitcher.logic.andNot="And not"
|
|||
AdvSceneSwitcher.logic.orNot="Or not"
|
||||
AdvSceneSwitcher.logic.rootNone="If"
|
||||
AdvSceneSwitcher.logic.not="If not"
|
||||
|
||||
; Macro Conditions
|
||||
AdvSceneSwitcher.condition.audio="Audio"
|
||||
AdvSceneSwitcher.ondition.audio.state.below="Below"
|
||||
AdvSceneSwitcher.ondition.audio.state.above="Above"
|
||||
AdvSceneSwitcher.condition.audio.entry="Volume of {{audioSources}} is {{condition}} {{volume}} for {{duration}} seconds"
|
||||
AdvSceneSwitcher.condition.audio.state.below="Below"
|
||||
AdvSceneSwitcher.condition.audio.state.above="Above"
|
||||
AdvSceneSwitcher.condition.audio.entry="Volume of {{audioSources}} is {{condition}} {{volume}}"
|
||||
AdvSceneSwitcher.condition.region="Screen region"
|
||||
AdvSceneSwitcher.condition.region.entry="Cursor is in {{minX}} {{minY}} x {{maxX}} {{maxY}}"
|
||||
AdvSceneSwitcher.condition.scene="Scene"
|
||||
AdvSceneSwitcher.condition.scene.type.current="Current"
|
||||
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.entry.line1="{{windows}} exist and ..."
|
||||
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.file="Use existing file"
|
||||
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.state.start="Stream running"
|
||||
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.state.start="Recording running"
|
||||
AdvSceneSwitcher.condition.record.state.pause="Recording paused"
|
||||
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.entry="{{processes}} is running {{focused}} and is focused"
|
||||
AdvSceneSwitcher.condition.idle="Idle"
|
||||
|
|
@ -126,6 +128,24 @@ AdvSceneSwitcher.condition.virtDesktop="Virtual desktop"
|
|||
AdvSceneSwitcher.condition.virtDesktop.notAvailable="Not availbale"
|
||||
AdvSceneSwitcher.condition.virtDesktop.entry.line1="Active virtual desktop is {{virtDesktops}}"
|
||||
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
|
||||
AdvSceneSwitcher.action.switchScene="Switch scene"
|
||||
|
|
@ -159,7 +179,37 @@ AdvSceneSwitcher.action.streaming.type.start="Start streaming"
|
|||
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
|
||||
AdvSceneSwitcher.action.run="Run"
|
||||
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
|
||||
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.port="Port"
|
||||
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.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.server.status.currentStatus="Current status"
|
||||
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.stopSwitcherHotkey="Stop 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?"
|
||||
|
||||
|
|
@ -409,10 +463,14 @@ AdvSceneSwitcher.selectPreviousScene="Previous Scene"
|
|||
AdvSceneSwitcher.currentTransition="Current Transition"
|
||||
AdvSceneSwitcher.selectTransition="--select transition--"
|
||||
AdvSceneSwitcher.selectWindow="--select window--"
|
||||
AdvSceneSwitcher.selectSource="--select source--"
|
||||
AdvSceneSwitcher.selectAudioSource="--select audio source--"
|
||||
AdvSceneSwitcher.selectVideoSource="--select video source--"
|
||||
AdvSceneSwitcher.selectMediaSource="--select media source--"
|
||||
AdvSceneSwitcher.selectProcess="--select process--"
|
||||
AdvSceneSwitcher.selectFilter="--select filter--"
|
||||
AdvSceneSwitcher.selectMacro="--select macro--"
|
||||
AdvSceneSwitcher.selectItem="--select item--"
|
||||
AdvSceneSwitcher.enterPath="--enter path--"
|
||||
AdvSceneSwitcher.enterText="--enter text--"
|
||||
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved"
|
||||
|
|
@ -425,3 +483,7 @@ AdvSceneSwitcher.unit.milliseconds="milliseconds"
|
|||
AdvSceneSwitcher.unit.secends="seconds"
|
||||
AdvSceneSwitcher.unit.minutes="minutes"
|
||||
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">
|
||||
<string>AdvSceneSwitcher.macroTab.edit</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_34" stretch="1,20,10">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_34">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0">
|
||||
<item>
|
||||
|
|
@ -752,184 +752,204 @@
|
|||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="macroConditions">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>767</width>
|
||||
<height>293</height>
|
||||
</rect>
|
||||
<widget class="QScrollArea" name="macroConditions">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_35" stretch="10,1">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_27">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="macroEditConditionHelp">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.macroTab.editConditionHelp</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="macroEditConditionLayout"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<item>
|
||||
<widget class="QPushButton" name="conditionAdd">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">addIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="conditionRemove">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">removeIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_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 class="QWidget" name="scrollAreaWidgetContents_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>767</width>
|
||||
<height>220</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_35" stretch="10,1">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinAndMaxSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_27">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinAndMaxSize</enum>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="macroEditConditionHelp">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.macroTab.editConditionHelp</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="macroEditConditionLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_12">
|
||||
<item>
|
||||
<widget class="QPushButton" name="conditionAdd">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">addIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="conditionRemove">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">removeIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_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>
|
||||
</item>
|
||||
<item>
|
||||
<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>
|
||||
<widget class="QScrollArea" name="macroActions">
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_33" stretch="10,1">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_25">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="macroEditActionHelp">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.macroTab.editActionHelp</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="macroEditActionLayout"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_21">
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionAdd">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">addIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionRemove">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">removeIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_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 class="QWidget" name="scrollAreaWidgetContents_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>767</width>
|
||||
<height>219</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_33" stretch="10,1">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinAndMaxSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_25">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="macroEditActionHelp">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.macroTab.editActionHelp</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="macroEditActionLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetMinAndMaxSize</enum>
|
||||
</property>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_21">
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionAdd">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">addIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="actionRemove">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>22</width>
|
||||
<height>22</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="themeID" stdset="0">
|
||||
<string notr="true">removeIconSmall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_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>
|
||||
</item>
|
||||
|
|
@ -3724,6 +3744,27 @@
|
|||
<layout class="QVBoxLayout" name="verticalLayout_31">
|
||||
<item>
|
||||
<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">
|
||||
<widget class="QSpinBox" name="serverPort">
|
||||
<property name="minimum">
|
||||
|
|
@ -3751,24 +3792,17 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_19">
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="sendPreview">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.networkTab.server.status.currentStatus</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="serverStatus">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.networkTab.server.status.notRunning</string>
|
||||
<string>AdvSceneSwitcher.networkTab.server.sendPreview</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="restrictSend">
|
||||
<widget class="QCheckBox" name="sendSceneChange">
|
||||
<property name="text">
|
||||
<string>AdvSceneSwitcher.networkTab.server.restrictSendToAutomatedSwitches</string>
|
||||
<string>AdvSceneSwitcher.networkTab.server.sendSceneChange</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
#include <QMainWindow>
|
||||
#include <QAction>
|
||||
#include <QtGui/qstandarditemmodel.h>
|
||||
#include <QPropertyAnimation>
|
||||
#include <QGraphicsColorizeEffect>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include <obs-module.h>
|
||||
#include <obs-frontend-api.h>
|
||||
#include <util/util.hpp>
|
||||
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/curl-helper.hpp"
|
||||
|
|
@ -73,331 +69,36 @@ void AdvSceneSwitcher::loadUI()
|
|||
}
|
||||
|
||||
/******************************************************************************
|
||||
* UI helpers
|
||||
* Saving and loading
|
||||
******************************************************************************/
|
||||
void AdvSceneSwitcher::addSelectionEntry(QComboBox *sel,
|
||||
const char *description,
|
||||
bool selectable, const char *tooltip)
|
||||
void AskBackup(obs_data_t *obj)
|
||||
{
|
||||
sel->addItem(description);
|
||||
bool backupSettings = DisplayMessage(
|
||||
obs_module_text("AdvSceneSwitcher.askBackup"), true);
|
||||
|
||||
if (strcmp(tooltip, "") != 0) {
|
||||
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");
|
||||
if (!backupSettings) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (addButton && addHighlight) {
|
||||
addButton->disconnect(*addHighlight);
|
||||
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;
|
||||
}
|
||||
|
||||
QListWidgetItem *item;
|
||||
item = new QListWidgetItem(list);
|
||||
list->addItem(item);
|
||||
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;
|
||||
QFile file(directory);
|
||||
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget *row = list->itemWidget(list->currentItem());
|
||||
QListWidgetItem *itemN = list->currentItem()->clone();
|
||||
|
||||
list->insertItem(index - 1, itemN);
|
||||
list->setItemWidget(itemN, row);
|
||||
|
||||
list->takeItem(index + 1);
|
||||
list->setCurrentRow(index - 1);
|
||||
return true;
|
||||
obs_data_save_json(obj, file.fileName().toUtf8().constData());
|
||||
}
|
||||
|
||||
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 *)
|
||||
{
|
||||
if (saving) {
|
||||
|
|
@ -422,7 +123,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
|
|||
obj = obs_data_create();
|
||||
}
|
||||
if (switcher->versionChanged(obj, g_GIT_SHA1)) {
|
||||
AdvSceneSwitcher::AskBackup(obj);
|
||||
AskBackup(obj);
|
||||
}
|
||||
|
||||
switcher->loadSettings(obj);
|
||||
|
|
@ -484,6 +185,7 @@ void SwitcherData::Thread()
|
|||
}
|
||||
|
||||
vblog(LOG_INFO, "try to sleep for %ld", duration.count());
|
||||
setWaitScene();
|
||||
cv.wait_for(lock, duration);
|
||||
|
||||
startTime = std::chrono::high_resolution_clock::now();
|
||||
|
|
@ -510,6 +212,7 @@ void SwitcherData::Thread()
|
|||
vblog(LOG_INFO, "sleep for %ld before switching scene",
|
||||
duration.count());
|
||||
|
||||
setWaitScene();
|
||||
cv.wait_for(lock, duration);
|
||||
|
||||
if (stop) {
|
||||
|
|
@ -616,7 +319,7 @@ bool SwitcherData::checkForMatch(OBSWeakSource &scene,
|
|||
return match;
|
||||
}
|
||||
|
||||
void switchScene(sceneSwitchInfo sceneSwitch)
|
||||
void switchScene(const sceneSwitchInfo &sceneSwitch)
|
||||
{
|
||||
if (!sceneSwitch.scene && switcher->verbose) {
|
||||
blog(LOG_INFO, "nothing to switch to");
|
||||
|
|
@ -640,7 +343,7 @@ void switchScene(sceneSwitchInfo sceneSwitch)
|
|||
blog(LOG_INFO, "switched scene");
|
||||
}
|
||||
|
||||
if (switcher->networkConfig.ServerEnabled) {
|
||||
if (switcher->networkConfig.ShouldSendSceneChange()) {
|
||||
switcher->server.sendMessage(sceneSwitch);
|
||||
}
|
||||
}
|
||||
|
|
@ -648,6 +351,13 @@ void switchScene(sceneSwitchInfo sceneSwitch)
|
|||
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()
|
||||
{
|
||||
if (!(th && th->isRunning())) {
|
||||
|
|
@ -669,6 +379,13 @@ void SwitcherData::Start()
|
|||
}
|
||||
}
|
||||
|
||||
void ResetMacroCounters()
|
||||
{
|
||||
for (auto &m : switcher->macros) {
|
||||
m.ResetCount();
|
||||
}
|
||||
}
|
||||
|
||||
void SwitcherData::Stop()
|
||||
{
|
||||
if (th && th->isRunning()) {
|
||||
|
|
@ -680,12 +397,19 @@ void SwitcherData::Stop()
|
|||
th = nullptr;
|
||||
|
||||
writeToStatusFile("Advanced Scene Switcher stopped");
|
||||
ResetMacroCounters();
|
||||
}
|
||||
|
||||
server.stop();
|
||||
client.disconnect();
|
||||
}
|
||||
|
||||
void SwitcherData::setWaitScene()
|
||||
{
|
||||
waitScene = obs_frontend_get_current_scene();
|
||||
obs_source_release(waitScene);
|
||||
}
|
||||
|
||||
bool SwitcherData::sceneChangedDuringWait()
|
||||
{
|
||||
obs_source_t *currentSource = obs_frontend_get_current_scene();
|
||||
|
|
@ -713,11 +437,11 @@ extern "C" void FreeSceneSwitcher()
|
|||
switcher = nullptr;
|
||||
}
|
||||
|
||||
void handleSceneChange(SwitcherData *s)
|
||||
void handleSceneChange()
|
||||
{
|
||||
// Stop waiting if scene was changed
|
||||
if (s->sceneChangedDuringWait()) {
|
||||
s->cv.notify_one();
|
||||
if (switcher->sceneChangedDuringWait()) {
|
||||
switcher->cv.notify_one();
|
||||
}
|
||||
|
||||
// Set previous scene
|
||||
|
|
@ -725,42 +449,52 @@ void handleSceneChange(SwitcherData *s)
|
|||
obs_weak_source_t *ws = obs_source_get_weak_source(source);
|
||||
obs_source_release(source);
|
||||
obs_weak_source_release(ws);
|
||||
if (source && s->previousSceneHelper != ws) {
|
||||
s->previousScene = s->previousSceneHelper;
|
||||
s->previousSceneHelper = ws;
|
||||
if (source && switcher->previousSceneHelper != ws) {
|
||||
switcher->previousScene = switcher->previousSceneHelper;
|
||||
switcher->previousSceneHelper = ws;
|
||||
}
|
||||
|
||||
s->checkTriggers();
|
||||
s->checkDefaultSceneTransitions();
|
||||
switcher->checkTriggers();
|
||||
switcher->checkDefaultSceneTransitions();
|
||||
|
||||
if (switcher->networkConfig.ServerEnabled &&
|
||||
switcher->networkConfig.SendAll) {
|
||||
if (switcher->networkConfig.ShouldSendFrontendSceneChange()) {
|
||||
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 ||
|
||||
s->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
|
||||
s->Start();
|
||||
if (switcher->autoStartEvent == AutoStartEvent::RECORDING ||
|
||||
switcher->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
|
||||
switcher->Start();
|
||||
}
|
||||
|
||||
void checkAutoStartStreaming(SwitcherData *s)
|
||||
void checkAutoStartStreaming()
|
||||
{
|
||||
if (s->autoStartEvent == AutoStartEvent::STREAMING ||
|
||||
s->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
|
||||
s->Start();
|
||||
if (switcher->autoStartEvent == AutoStartEvent::STREAMING ||
|
||||
switcher->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
|
||||
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:
|
||||
|
|
@ -768,24 +502,31 @@ void checkAutoStartStreaming(SwitcherData *s)
|
|||
// frontend functions such as obs_frontend_set_current_scene()
|
||||
static void OBSEvent(enum obs_frontend_event event, void *switcher)
|
||||
{
|
||||
if (!switcher) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event) {
|
||||
case OBS_FRONTEND_EVENT_EXIT:
|
||||
FreeSceneSwitcher();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
|
||||
handleSceneChange((SwitcherData *)switcher);
|
||||
handleSceneChange();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_PREVIEW_SCENE_CHANGED:
|
||||
handlePeviewSceneChange();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_RECORDING_STARTED:
|
||||
setLiveTime((SwitcherData *)switcher);
|
||||
checkAutoStartRecording((SwitcherData *)switcher);
|
||||
setLiveTime();
|
||||
checkAutoStartRecording();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_STREAMING_STARTED:
|
||||
setLiveTime((SwitcherData *)switcher);
|
||||
checkAutoStartStreaming((SwitcherData *)switcher);
|
||||
setLiveTime();
|
||||
checkAutoStartStreaming();
|
||||
break;
|
||||
case OBS_FRONTEND_EVENT_RECORDING_STOPPED:
|
||||
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
|
||||
resetLiveTime((SwitcherData *)switcher);
|
||||
resetLiveTime();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "headers/duration-control.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
#include "obs-module.h"
|
||||
|
||||
#include <sstream>
|
||||
|
|
@ -99,6 +100,8 @@ DurationSelection::DurationSelection(QWidget *parent, bool showUnitSelection)
|
|||
SLOT(_UnitChanged(int)));
|
||||
|
||||
QHBoxLayout *layout = new QHBoxLayout;
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(11);
|
||||
layout->addWidget(_duration);
|
||||
if (showUnitSelection) {
|
||||
layout->addWidget(_unitSelection);
|
||||
|
|
@ -137,3 +140,131 @@ void DurationSelection::_UnitChanged(int idx)
|
|||
|
||||
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/utility.hpp"
|
||||
#include "headers/version.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
|
||||
QMetaObject::Connection inactivePluse;
|
||||
|
||||
void AdvSceneSwitcher::on_close_clicked()
|
||||
|
|
@ -156,8 +156,11 @@ void AdvSceneSwitcher::SetStopped()
|
|||
obs_module_text("AdvSceneSwitcher.generalTab.status.start"));
|
||||
ui->pluginRunningText->setText(
|
||||
obs_module_text("AdvSceneSwitcher.status.inactive"));
|
||||
inactivePluse = PulseWidget(ui->pluginRunningText, QColor(Qt::red),
|
||||
QColor(0, 0, 0, 0), "QLabel ");
|
||||
if (!switcher->disableHints) {
|
||||
inactivePluse = PulseWidget(ui->pluginRunningText,
|
||||
QColor(Qt::red), QColor(0, 0, 0, 0),
|
||||
"QLabel ");
|
||||
}
|
||||
currentStatusActive = false;
|
||||
}
|
||||
|
||||
|
|
@ -207,34 +210,6 @@ void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int 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()
|
||||
{
|
||||
QString directory = QFileDialog::getSaveFileName(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "ui_advanced-scene-switcher.h"
|
||||
#endif
|
||||
#include "switcher-data-structs.hpp"
|
||||
#include "platform-funcs.hpp"
|
||||
|
||||
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
|
||||
#define vblog(level, msg, ...) \
|
||||
|
|
@ -69,44 +70,10 @@ public:
|
|||
void setTabOrder();
|
||||
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:
|
||||
void MacroAdded(const QString &name);
|
||||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString newName);
|
||||
void SceneGroupAdded(const QString &name);
|
||||
void SceneGroupRemoved(const QString &name);
|
||||
void SceneGroupRenamed(const QString &oldName, const QString newName);
|
||||
|
|
@ -137,6 +104,7 @@ public slots:
|
|||
void on_macroDown_clicked();
|
||||
void on_macroName_editingFinished();
|
||||
void on_macros_currentRowChanged(int idx);
|
||||
void on_macros_itemChanged(QListWidgetItem *);
|
||||
void on_conditionAdd_clicked();
|
||||
void on_conditionRemove_clicked();
|
||||
void on_actionAdd_clicked();
|
||||
|
|
@ -243,7 +211,9 @@ public slots:
|
|||
void on_clientSettings_toggled(bool on);
|
||||
void on_clientHostname_textChanged(const QString &text);
|
||||
void on_clientPort_valueChanged(int value);
|
||||
void on_sendSceneChange_stateChanged(int state);
|
||||
void on_restrictSend_stateChanged(int state);
|
||||
void on_sendPreview_stateChanged(int state);
|
||||
void on_clientReconnect_clicked();
|
||||
void updateClientStatus();
|
||||
|
||||
|
|
@ -276,42 +246,17 @@ public slots:
|
|||
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
|
||||
******************************************************************************/
|
||||
|
||||
void setNextTransition(sceneSwitchInfo &ssi, obs_source_t *currentSource,
|
||||
void setNextTransition(const sceneSwitchInfo &ssi, obs_source_t *currentSource,
|
||||
transitionData &td);
|
||||
void overwriteTransitionOverride(sceneSwitchInfo ssi, transitionData &td);
|
||||
void restoreTransitionOverride(obs_source_t *scene, transitionData td);
|
||||
void switchScene(sceneSwitchInfo ssi);
|
||||
void overwriteTransitionOverride(const sceneSwitchInfo &ssi,
|
||||
transitionData &td);
|
||||
void restoreTransitionOverride(obs_source_t *scene, const transitionData &td);
|
||||
void switchScene(const sceneSwitchInfo &ssi);
|
||||
void switchPreviewScene(const OBSWeakSource &ws);
|
||||
|
||||
/******************************************************************************
|
||||
* Main SwitcherData
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <QWidget>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QComboBox>
|
||||
#include <QPushButton>
|
||||
#include <chrono>
|
||||
|
||||
#include "obs-data.h"
|
||||
|
|
@ -53,3 +54,57 @@ private:
|
|||
|
||||
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();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroActionAudio>();
|
||||
|
|
@ -27,7 +27,7 @@ public:
|
|||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionAudioEdit : public QWidget {
|
||||
|
|
@ -37,6 +37,7 @@ public:
|
|||
MacroActionAudioEdit(
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroActionAudio> entryData = nullptr);
|
||||
void SetWidgetVisibility();
|
||||
void UpdateEntryData();
|
||||
static QWidget *Create(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
|
|
|
|||
|
|
@ -20,14 +20,16 @@ struct MacroActionInfo {
|
|||
class MacroActionFactory {
|
||||
public:
|
||||
MacroActionFactory() = delete;
|
||||
static bool Register(int id, MacroActionInfo);
|
||||
static std::shared_ptr<MacroAction> Create(const int id);
|
||||
static QWidget *CreateWidget(const int id, QWidget *parent,
|
||||
static bool Register(const std::string &id, MacroActionInfo);
|
||||
static std::shared_ptr<MacroAction> Create(const std::string &id);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action);
|
||||
static auto GetActionTypes() { return _methods; }
|
||||
static std::string GetActionName(const std::string &id);
|
||||
static std::string GetIdByName(const QString &name);
|
||||
|
||||
private:
|
||||
static std::map<int, MacroActionInfo> _methods;
|
||||
static std::map<std::string, MacroActionInfo> _methods;
|
||||
};
|
||||
|
||||
class MacroActionEdit : public QWidget {
|
||||
|
|
@ -35,13 +37,13 @@ class MacroActionEdit : public QWidget {
|
|||
|
||||
public:
|
||||
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);
|
||||
void UpdateEntryData(int type);
|
||||
void Collapse(bool collapsed);
|
||||
void UpdateEntryData(const std::string &id, bool collapse);
|
||||
|
||||
private slots:
|
||||
void ActionSelectionChanged(int idx);
|
||||
void ActionSelectionChanged(const QString &text);
|
||||
|
||||
protected:
|
||||
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();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroActionRecord>();
|
||||
|
|
@ -26,7 +26,7 @@ public:
|
|||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionRecordEdit : public QWidget {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public:
|
|||
void LogAction();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroActionReplayBuffer>();
|
||||
|
|
@ -33,7 +33,7 @@ private:
|
|||
Duration _duration;
|
||||
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionReplayBufferEdit : public QWidget {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ public:
|
|||
void LogAction();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroActionRun>();
|
||||
|
|
@ -20,7 +20,7 @@ public:
|
|||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionRunEdit : public QWidget {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ public:
|
|||
void LogAction();
|
||||
bool Save(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()
|
||||
{
|
||||
|
|
@ -21,7 +21,7 @@ private:
|
|||
const char *getType() { return "MacroActionSwitchScene"; }
|
||||
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
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();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroActionStream>();
|
||||
|
|
@ -28,7 +28,7 @@ private:
|
|||
Duration _retryCooldown;
|
||||
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionStreamEdit : public QWidget {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ public:
|
|||
bool PerformAction();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroActionWait>();
|
||||
|
|
@ -24,7 +24,7 @@ public:
|
|||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroActionWaitEdit : public QWidget {
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@
|
|||
#include <QComboBox>
|
||||
#include <chrono>
|
||||
|
||||
#include "duration-control.hpp"
|
||||
|
||||
enum class AudioCondition {
|
||||
ABOVE,
|
||||
BELOW,
|
||||
|
|
@ -19,7 +17,7 @@ public:
|
|||
bool CheckCondition();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroConditionAudio>();
|
||||
|
|
@ -33,13 +31,12 @@ public:
|
|||
OBSWeakSource _audioSource;
|
||||
int _volume = 0;
|
||||
AudioCondition _condition = AudioCondition::ABOVE;
|
||||
Duration _duration;
|
||||
obs_volmeter_t *_volmeter = nullptr;
|
||||
|
||||
private:
|
||||
float _peak = -std::numeric_limits<float>::infinity();
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroConditionAudioEdit : public QWidget {
|
||||
|
|
@ -63,13 +60,11 @@ private slots:
|
|||
void SourceChanged(const QString &text);
|
||||
void VolumeThresholdChanged(int vol);
|
||||
void ConditionChanged(int cond);
|
||||
void DurationChanged(double seconds);
|
||||
|
||||
protected:
|
||||
QComboBox *_audioSources;
|
||||
QComboBox *_condition;
|
||||
QSpinBox *_volume;
|
||||
DurationSelection *_duration;
|
||||
VolControl *_volMeter = nullptr;
|
||||
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;
|
||||
TCreateWidgetMethod _createWidgetFunc;
|
||||
std::string _name;
|
||||
bool _useDurationConstraint = true;
|
||||
};
|
||||
|
||||
class MacroConditionFactory {
|
||||
public:
|
||||
MacroConditionFactory() = delete;
|
||||
static bool Register(int id, MacroConditionInfo);
|
||||
static std::shared_ptr<MacroCondition> Create(const int id);
|
||||
static QWidget *CreateWidget(const int id, QWidget *parent,
|
||||
static bool Register(const std::string &, MacroConditionInfo);
|
||||
static std::shared_ptr<MacroCondition> Create(const std::string &);
|
||||
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
|
||||
std::shared_ptr<MacroCondition>);
|
||||
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:
|
||||
static std::map<int, MacroConditionInfo> _methods;
|
||||
static std::map<std::string, MacroConditionInfo> _methods;
|
||||
};
|
||||
|
||||
class MacroConditionEdit : public QWidget {
|
||||
|
|
@ -36,20 +40,23 @@ class MacroConditionEdit : public QWidget {
|
|||
public:
|
||||
MacroConditionEdit(QWidget *parent = nullptr,
|
||||
std::shared_ptr<MacroCondition> * = nullptr,
|
||||
int type = 0, bool root = true,
|
||||
const std::string &id = "scene", bool root = true,
|
||||
bool startCollapsed = false);
|
||||
bool IsRootNode();
|
||||
void UpdateEntryData(int type);
|
||||
void Collapse(bool collapsed);
|
||||
void UpdateEntryData(const std::string &id, bool collapse);
|
||||
|
||||
private slots:
|
||||
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:
|
||||
QComboBox *_logicSelection;
|
||||
QComboBox *_conditionSelection;
|
||||
Section *_section;
|
||||
DurationConstraintEdit *_dur;
|
||||
|
||||
std::shared_ptr<MacroCondition> *_entryData;
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public:
|
|||
bool CheckCondition();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroConditionFile>();
|
||||
|
|
@ -39,7 +39,7 @@ private:
|
|||
QDateTime _lastMod;
|
||||
size_t _lastHash = 0;
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroConditionFileEdit : public QWidget {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
#pragma once
|
||||
#include "macro.hpp"
|
||||
#include "duration-control.hpp"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
#include "duration-control.hpp"
|
||||
|
||||
class MacroConditionIdle : public MacroCondition {
|
||||
public:
|
||||
bool CheckCondition();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroConditionIdle>();
|
||||
|
|
@ -19,7 +20,7 @@ public:
|
|||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
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 Save(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()
|
||||
{
|
||||
return std::make_shared<MacroConditionMedia>();
|
||||
|
|
@ -65,7 +65,7 @@ private:
|
|||
bool _playedToEnd = false;
|
||||
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroConditionMediaEdit : public QWidget {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ public:
|
|||
bool CheckCondition();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroConditionPluginState>();
|
||||
|
|
@ -22,7 +22,7 @@ public:
|
|||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroConditionPluginStateEdit : public QWidget {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public:
|
|||
bool CheckCondition();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroConditionProcess>();
|
||||
|
|
@ -19,7 +19,7 @@ public:
|
|||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroConditionProcessEdit : public QWidget {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#include "macro.hpp"
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
#include "duration-control.hpp"
|
||||
|
||||
enum class RecordState {
|
||||
STOP,
|
||||
|
|
@ -15,18 +14,17 @@ public:
|
|||
bool CheckCondition();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroConditionRecord>();
|
||||
}
|
||||
|
||||
RecordState _recordState;
|
||||
Duration _duration;
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroConditionRecordEdit : public QWidget {
|
||||
|
|
@ -47,12 +45,9 @@ public:
|
|||
|
||||
private slots:
|
||||
void StateChanged(int value);
|
||||
void DurationChanged(double seconds);
|
||||
void DurationUnitChanged(DurationUnit unit);
|
||||
|
||||
protected:
|
||||
QComboBox *_recordState;
|
||||
DurationSelection *_duration;
|
||||
std::shared_ptr<MacroConditionRecord> _entryData;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public:
|
|||
bool CheckCondition();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroConditionRegion>();
|
||||
|
|
@ -18,7 +18,7 @@ public:
|
|||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroConditionRegionEdit : public QWidget {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
#include "macro.hpp"
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
#include "duration-control.hpp"
|
||||
|
||||
enum class SceneType {
|
||||
CURRENT,
|
||||
|
|
@ -14,7 +13,7 @@ public:
|
|||
bool CheckCondition();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroConditionScene>();
|
||||
|
|
@ -22,11 +21,10 @@ public:
|
|||
|
||||
OBSWeakSource _scene;
|
||||
SceneType _type;
|
||||
Duration _duration;
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroConditionSceneEdit : public QWidget {
|
||||
|
|
@ -48,13 +46,10 @@ public:
|
|||
private slots:
|
||||
void SceneChanged(const QString &text);
|
||||
void TypeChanged(int value);
|
||||
void DurationChanged(double seconds);
|
||||
void DurationUnitChanged(DurationUnit unit);
|
||||
|
||||
protected:
|
||||
QComboBox *_sceneSelection;
|
||||
QComboBox *_sceneType;
|
||||
DurationSelection *_duration;
|
||||
std::shared_ptr<MacroConditionScene> _entryData;
|
||||
|
||||
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 <QWidget>
|
||||
#include <QComboBox>
|
||||
#include "duration-control.hpp"
|
||||
|
||||
enum class StreamState {
|
||||
STOP,
|
||||
|
|
@ -14,18 +13,17 @@ public:
|
|||
bool CheckCondition();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroConditionStream>();
|
||||
}
|
||||
|
||||
StreamState _streamState;
|
||||
Duration _duration;
|
||||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroConditionStreamEdit : public QWidget {
|
||||
|
|
@ -46,12 +44,9 @@ public:
|
|||
|
||||
private slots:
|
||||
void StateChanged(int value);
|
||||
void DurationChanged(double seconds);
|
||||
void DurationUnitChanged(DurationUnit unit);
|
||||
|
||||
protected:
|
||||
QComboBox *_streamState;
|
||||
DurationSelection *_duration;
|
||||
std::shared_ptr<MacroConditionStream> _entryData;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#pragma once
|
||||
#include "macro.hpp"
|
||||
#include "screenshot-helper.hpp"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QComboBox>
|
||||
#include <chrono>
|
||||
#include "duration-control.hpp"
|
||||
#include "screenshot-helper.hpp"
|
||||
|
||||
enum class VideoCondition {
|
||||
MATCH,
|
||||
|
|
@ -19,7 +19,7 @@ public:
|
|||
bool CheckCondition();
|
||||
bool Save(obs_data_t *obj);
|
||||
bool Load(obs_data_t *obj);
|
||||
int GetId() { return id; };
|
||||
std::string GetId() { return id; };
|
||||
QImage GetMatchImage() { return _matchImage; };
|
||||
static std::shared_ptr<MacroCondition> Create()
|
||||
{
|
||||
|
|
@ -30,7 +30,6 @@ public:
|
|||
|
||||
OBSWeakSource _videoSource;
|
||||
VideoCondition _condition = VideoCondition::MATCH;
|
||||
Duration _duration;
|
||||
std::string _file = obs_module_text("AdvSceneSwitcher.enterPath");
|
||||
|
||||
private:
|
||||
|
|
@ -39,7 +38,7 @@ private:
|
|||
std::unique_ptr<AdvSSScreenshotObj> _screenshotData = nullptr;
|
||||
QImage _matchImage;
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
class MacroConditionVideoEdit : public QWidget {
|
||||
|
|
@ -66,12 +65,9 @@ private slots:
|
|||
void ConditionChanged(int cond);
|
||||
void FilePathChanged();
|
||||
void BrowseButtonClicked();
|
||||
void DurationChanged(double seconds);
|
||||
void DurationUnitChanged(DurationUnit unit);
|
||||
|
||||
protected:
|
||||
QComboBox *_videoSelection;
|
||||
DurationSelection *_duration;
|
||||
QComboBox *_condition;
|
||||
QLineEdit *_filePath;
|
||||
QPushButton *_browseButton;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ public:
|
|||
bool CheckCondition();
|
||||
bool Save(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()
|
||||
{
|
||||
return std::make_shared<MacroConditionWindow>();
|
||||
|
|
@ -27,7 +27,7 @@ public:
|
|||
|
||||
private:
|
||||
static bool _registered;
|
||||
static const int id;
|
||||
static const std::string id;
|
||||
};
|
||||
|
||||
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
|
||||
#include "duration-control.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <obs.hpp>
|
||||
#include <obs-module.h>
|
||||
#include <QString>
|
||||
|
||||
constexpr auto macro_func = 10;
|
||||
constexpr auto default_priority_10 = macro_func;
|
||||
|
|
@ -38,14 +41,23 @@ public:
|
|||
virtual bool CheckCondition() = 0;
|
||||
virtual bool Save(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; }
|
||||
void SetLogicType(LogicType logic) { _logic = logic; }
|
||||
|
||||
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:
|
||||
LogicType _logic;
|
||||
DurationConstraint _duration;
|
||||
};
|
||||
|
||||
class MacroAction {
|
||||
|
|
@ -53,21 +65,24 @@ public:
|
|||
virtual bool PerformAction() = 0;
|
||||
virtual bool Save(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();
|
||||
};
|
||||
|
||||
class Macro {
|
||||
|
||||
public:
|
||||
Macro(std::string name = "");
|
||||
Macro(const std::string &name = "");
|
||||
virtual ~Macro();
|
||||
|
||||
bool CeckMatch();
|
||||
bool PerformAction();
|
||||
bool Matched() { return _matched; }
|
||||
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()
|
||||
{
|
||||
return _conditions;
|
||||
|
|
@ -76,13 +91,56 @@ public:
|
|||
|
||||
bool Save(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
|
||||
bool SwitchesScene();
|
||||
|
||||
private:
|
||||
void SetupHotkeys();
|
||||
void ClearHotkeys();
|
||||
void SetHotkeysDesc();
|
||||
|
||||
std::string _name = "";
|
||||
std::deque<std::shared_ptr<MacroCondition>> _conditions;
|
||||
std::deque<std::shared_ptr<MacroAction>> _actions;
|
||||
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;
|
||||
|
||||
inline SceneGroup(){};
|
||||
inline SceneGroup(std::string name_) : name(name_){};
|
||||
inline SceneGroup(std::string name_, AdvanceCondition type_,
|
||||
std::vector<OBSWeakSource> scenes_, int count_,
|
||||
inline SceneGroup(const std::string &name_) : name(name_){};
|
||||
inline SceneGroup(const std::string &name_, AdvanceCondition type_,
|
||||
const std::vector<OBSWeakSource> &scenes_, int count_,
|
||||
double time_, bool repeat_)
|
||||
: name(name_),
|
||||
type(type_),
|
||||
|
|
|
|||
|
|
@ -14,18 +14,31 @@ public:
|
|||
explicit Section(const int animationDuration = 300,
|
||||
QWidget *parent = 0);
|
||||
|
||||
void SetContent(QWidget *w);
|
||||
void SetContent(QWidget *w, bool collapsed = true);
|
||||
void AddHeaderWidget(QWidget *);
|
||||
|
||||
public slots:
|
||||
void Collapse(bool collapsed);
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void AnimationFinished();
|
||||
void Collapse(bool collapse);
|
||||
|
||||
private:
|
||||
void SetupAnimations();
|
||||
void CleanUpPreviousContent();
|
||||
|
||||
QGridLayout *_mainLayout;
|
||||
QHBoxLayout *_headerWidgetLayout;
|
||||
QToolButton *_toggleButton;
|
||||
QFrame *_headerLine;
|
||||
QParallelAnimationGroup *_toggleAnimation = nullptr;
|
||||
QParallelAnimationGroup *_contentAnimation = nullptr;
|
||||
QScrollArea *_contentArea = nullptr;
|
||||
QWidget *_content = nullptr;
|
||||
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();
|
||||
|
||||
bool ShouldSendSceneChange();
|
||||
bool ShouldSendFrontendSceneChange();
|
||||
bool ShouldSendPrviewSceneChange();
|
||||
|
||||
// Server
|
||||
bool ServerEnabled;
|
||||
uint64_t ServerPort;
|
||||
|
|
@ -42,7 +46,9 @@ public:
|
|||
bool ClientEnabled;
|
||||
std::string Address;
|
||||
uint64_t ClientPort;
|
||||
bool SendAll;
|
||||
bool SendSceneChange;
|
||||
bool SendSceneChangeAll;
|
||||
bool SendPreview;
|
||||
};
|
||||
|
||||
class WSServer : public QObject {
|
||||
|
|
@ -53,7 +59,7 @@ public:
|
|||
virtual ~WSServer();
|
||||
void start(quint16 port, bool lockToIPv4);
|
||||
void stop();
|
||||
void sendMessage(sceneSwitchInfo sceneSwitch);
|
||||
void sendMessage(sceneSwitchInfo sceneSwitch, bool preview = false);
|
||||
QThreadPool *threadPool() { return &_threadPool; }
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -192,6 +192,7 @@ struct SwitcherData {
|
|||
void Start();
|
||||
void Stop();
|
||||
|
||||
void setWaitScene();
|
||||
bool sceneChangedDuringWait();
|
||||
|
||||
bool prioFuncsValid();
|
||||
|
|
@ -200,7 +201,7 @@ struct SwitcherData {
|
|||
void resetTabOrder();
|
||||
|
||||
void writeSceneInfoToFile();
|
||||
void writeToStatusFile(QString status);
|
||||
void writeToStatusFile(const QString &msg);
|
||||
|
||||
bool checkForMatch(OBSWeakSource &scene, OBSWeakSource &transition,
|
||||
int &linger, bool &setPreviousSceneAsMatch,
|
||||
|
|
@ -253,7 +254,7 @@ struct SwitcherData {
|
|||
void saveNetworkSwitches(obs_data_t *obj);
|
||||
void saveGeneralSettings(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 loadMacros(obs_data_t *obj);
|
||||
|
|
|
|||
|
|
@ -1,118 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QTextStream>
|
||||
#include <QLayout>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QMetaObject>
|
||||
#include <QListWidget>
|
||||
#include <QPushButton>
|
||||
#include <QColor>
|
||||
#include <obs.hpp>
|
||||
#include <obs-module.h>
|
||||
#include <obs-frontend-api.h>
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
#include "scene-group.hpp"
|
||||
|
||||
static inline bool WeakSourceValid(obs_weak_source_t *ws)
|
||||
{
|
||||
obs_source_t *source = obs_weak_source_get_source(ws);
|
||||
if (source) {
|
||||
obs_source_release(source);
|
||||
}
|
||||
return !!source;
|
||||
}
|
||||
|
||||
static inline std::string GetWeakSourceName(obs_weak_source_t *weak_source)
|
||||
{
|
||||
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;
|
||||
}
|
||||
bool WeakSourceValid(obs_weak_source_t *ws);
|
||||
std::string GetWeakSourceName(obs_weak_source_t *weak_source);
|
||||
OBSWeakSource GetWeakSourceByName(const char *name);
|
||||
OBSWeakSource GetWeakSourceByQString(const QString &name);
|
||||
OBSWeakSource GetWeakTransitionByName(const char *transitionName);
|
||||
OBSWeakSource GetWeakTransitionByQString(const QString &name);
|
||||
OBSWeakSource GetWeakFilterByName(OBSWeakSource source, const char *name);
|
||||
OBSWeakSource GetWeakFilterByQString(OBSWeakSource source, const QString &name);
|
||||
bool compareIgnoringLineEnding(QString &s1, QString &s2);
|
||||
std::string getSourceSettings(OBSWeakSource ws);
|
||||
std::string getDataFilePath(const std::string &file);
|
||||
|
||||
/**
|
||||
* 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 addStretch Add addStretch() to layout.
|
||||
*/
|
||||
static inline void
|
||||
placeWidgets(std::string text, QBoxLayout *layout,
|
||||
std::unordered_map<std::string, QWidget *> placeholders,
|
||||
bool addStretch = true)
|
||||
{
|
||||
std::vector<std::pair<std::string, QWidget *>> labelsWidgetsPairs;
|
||||
|
||||
std::string delim = getNextDelim(text, placeholders);
|
||||
while (delim != "") {
|
||||
size_t pos = text.find(delim);
|
||||
if (pos != std::string::npos) {
|
||||
labelsWidgetsPairs.emplace_back(text.substr(0, pos),
|
||||
placeholders[delim]);
|
||||
text.erase(0, pos + delim.length());
|
||||
}
|
||||
delim = getNextDelim(text, placeholders);
|
||||
}
|
||||
|
||||
if (text != "") {
|
||||
labelsWidgetsPairs.emplace_back(text, nullptr);
|
||||
}
|
||||
|
||||
for (auto &lw : labelsWidgetsPairs) {
|
||||
if (lw.first != "") {
|
||||
layout->addWidget(new QLabel(lw.first.c_str()));
|
||||
}
|
||||
if (lw.second) {
|
||||
layout->addWidget(lw.second);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
void placeWidgets(std::string text, QBoxLayout *layout,
|
||||
std::unordered_map<std::string, QWidget *> placeholders,
|
||||
bool addStretch = true);
|
||||
void clearLayout(QLayout *layout);
|
||||
QMetaObject::Connection PulseWidget(QWidget *widget, QColor endColor,
|
||||
QColor = QColor(0, 0, 0, 0),
|
||||
QString specifier = "QLabel ");
|
||||
void listAddClicked(QListWidget *list, QWidget *newWidget,
|
||||
QPushButton *addButton = nullptr,
|
||||
QMetaObject::Connection *addHighlight = nullptr);
|
||||
bool listMoveUp(QListWidget *list);
|
||||
bool listMoveDown(QListWidget *list);
|
||||
bool DisplayMessage(const QString &msg, bool question = false);
|
||||
void addSelectionEntry(QComboBox *sel, const char *description,
|
||||
bool selectable = false, const char *tooltip = "");
|
||||
void populateTransitionSelection(QComboBox *sel, bool addCurrent = true,
|
||||
bool addSelect = true,
|
||||
bool selectable = false);
|
||||
void populateWindowSelection(QComboBox *sel, bool addSelect = true);
|
||||
void populateAudioSelection(QComboBox *sel, bool addSelect = true);
|
||||
void populateVideoSelection(QComboBox *sel, bool addSelect = true);
|
||||
void populateMediaSelection(QComboBox *sel, bool addSelect = true);
|
||||
void populateProcessSelection(QComboBox *sel, bool addSelect = true);
|
||||
void populateSourceSelection(QComboBox *list, bool addSelect = true);
|
||||
void populateSceneSelection(QComboBox *sel, bool addPrevious = false,
|
||||
bool addSceneGroup = false,
|
||||
std::deque<SceneGroup> *sceneGroups = nullptr,
|
||||
bool addSelect = true, std::string selectText = "",
|
||||
bool selectable = false);
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ std::pair<int, int> getCursorPos()
|
|||
return pos;
|
||||
}
|
||||
|
||||
bool isMaximized(std::string &title)
|
||||
bool isMaximized(const std::string &title)
|
||||
{
|
||||
if (!ewmhIsSupported())
|
||||
return false;
|
||||
|
|
@ -302,7 +302,7 @@ bool isMaximized(std::string &title)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool isFullscreen(std::string &title)
|
||||
bool isFullscreen(const std::string &title)
|
||||
{
|
||||
if (!ewmhIsSupported())
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
const int MacroActionAudio::id = 2;
|
||||
const std::string MacroActionAudio::id = "audio";
|
||||
|
||||
bool MacroActionAudio::_registered = MacroActionFactory::Register(
|
||||
MacroActionAudio::id,
|
||||
|
|
@ -94,7 +94,7 @@ MacroActionAudioEdit::MacroActionAudioEdit(
|
|||
_volumePercent->setSuffix("%");
|
||||
|
||||
populateActionSelection(_actions);
|
||||
AdvSceneSwitcher::populateAudioSelection(_audioSources);
|
||||
populateAudioSelection(_audioSources);
|
||||
|
||||
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ActionChanged(int)));
|
||||
|
|
@ -130,17 +130,8 @@ bool hasSourceControl(AudioAction action)
|
|||
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)) {
|
||||
_volumePercent->show();
|
||||
} 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)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
|
|
@ -172,7 +177,7 @@ void MacroActionAudioEdit::ActionChanged(int value)
|
|||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->_action = static_cast<AudioAction>(value);
|
||||
UpdateEntryData();
|
||||
SetWidgetVisibility();
|
||||
}
|
||||
|
||||
void MacroActionAudioEdit::VolumeChanged(int value)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
#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/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()) {
|
||||
_methods[id] = info;
|
||||
|
|
@ -14,7 +14,7 @@ bool MacroActionFactory::Register(int id, MacroActionInfo info)
|
|||
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())
|
||||
return it->second._createFunc();
|
||||
|
|
@ -22,7 +22,8 @@ std::shared_ptr<MacroAction> MacroActionFactory::Create(const int id)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
QWidget *MacroActionFactory::CreateWidget(const int id, QWidget *parent,
|
||||
QWidget *MacroActionFactory::CreateWidget(const std::string &id,
|
||||
QWidget *parent,
|
||||
std::shared_ptr<MacroAction> action)
|
||||
{
|
||||
if (auto it = _methods.find(id); it != _methods.end())
|
||||
|
|
@ -31,6 +32,24 @@ QWidget *MacroActionFactory::CreateWidget(const int id, QWidget *parent,
|
|||
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)
|
||||
{
|
||||
for (auto entry : MacroActionFactory::GetActionTypes()) {
|
||||
|
|
@ -40,14 +59,15 @@ static inline void populateActionSelection(QComboBox *list)
|
|||
|
||||
MacroActionEdit::MacroActionEdit(QWidget *parent,
|
||||
std::shared_ptr<MacroAction> *entryData,
|
||||
int type, bool startCollapsed)
|
||||
const std::string &id, bool startCollapsed)
|
||||
: QWidget(parent)
|
||||
{
|
||||
_actionSelection = new QComboBox();
|
||||
_section = new Section(300);
|
||||
|
||||
QWidget::connect(_actionSelection, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(ActionSelectionChanged(int)));
|
||||
QWidget::connect(_actionSelection,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(ActionSelectionChanged(const QString &)));
|
||||
|
||||
populateActionSelection(_actionSelection);
|
||||
|
||||
|
|
@ -58,38 +78,34 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
|
|||
setLayout(mainLayout);
|
||||
|
||||
_entryData = entryData;
|
||||
UpdateEntryData(type);
|
||||
UpdateEntryData(id, startCollapsed);
|
||||
|
||||
_loading = false;
|
||||
_section->Collapse(startCollapsed);
|
||||
}
|
||||
|
||||
void MacroActionEdit::ActionSelectionChanged(int idx)
|
||||
void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id = MacroActionFactory::GetIdByName(text);
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
_entryData->reset();
|
||||
*_entryData = MacroActionFactory::Create(idx);
|
||||
*_entryData = MacroActionFactory::Create(id);
|
||||
auto widget =
|
||||
MacroActionFactory::CreateWidget(idx, window(), *_entryData);
|
||||
_section->SetContent(widget);
|
||||
_section->Collapse(false);
|
||||
MacroActionFactory::CreateWidget(id, window(), *_entryData);
|
||||
_section->SetContent(widget, 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 =
|
||||
MacroActionFactory::CreateWidget(type, window(), *_entryData);
|
||||
_section->SetContent(widget);
|
||||
}
|
||||
|
||||
void MacroActionEdit::Collapse(bool collapsed)
|
||||
{
|
||||
_section->Collapse(collapsed);
|
||||
MacroActionFactory::CreateWidget(id, window(), *_entryData);
|
||||
_section->SetContent(widget, collapse);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_actionAdd_clicked()
|
||||
|
|
@ -98,12 +114,16 @@ void AdvSceneSwitcher::on_actionAdd_clicked()
|
|||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
MacroActionSwitchScene temp;
|
||||
std::string id = temp.GetId();
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
macro->Actions().emplace_back(MacroActionFactory::Create(0));
|
||||
auto newEntry = new MacroActionEdit(this, ¯o->Actions().back(), 0);
|
||||
macro->Actions().emplace_back(MacroActionFactory::Create(id));
|
||||
auto newEntry =
|
||||
new MacroActionEdit(this, ¯o->Actions().back(), id, false);
|
||||
ui->macroEditActionLayout->addWidget(newEntry);
|
||||
ui->macroEditActionHelp->setVisible(false);
|
||||
newEntry->Collapse(false);
|
||||
}
|
||||
|
||||
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/utility.hpp"
|
||||
|
||||
const int MacroActionRecord::id = 4;
|
||||
const std::string MacroActionRecord::id = "recording";
|
||||
|
||||
bool MacroActionRecord::_registered = MacroActionFactory::Register(
|
||||
MacroActionRecord::id,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "headers/advanced-scene-switcher.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
const int MacroActionReplayBuffer::id = 5;
|
||||
const std::string MacroActionReplayBuffer::id = "replay_buffer";
|
||||
|
||||
bool MacroActionReplayBuffer::_registered = MacroActionFactory::Register(
|
||||
MacroActionReplayBuffer::id,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include <QProcess>
|
||||
#include <QFileDialog>
|
||||
|
||||
const int MacroActionRun::id = 6;
|
||||
const std::string MacroActionRun::id = "run";
|
||||
|
||||
bool MacroActionRun::_registered = MacroActionFactory::Register(
|
||||
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/utility.hpp"
|
||||
|
||||
const int MacroActionSwitchScene::id = 0;
|
||||
const std::string MacroActionSwitchScene::id = "scene_switch";
|
||||
|
||||
bool MacroActionSwitchScene::_registered = MacroActionFactory::Register(
|
||||
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/utility.hpp"
|
||||
|
||||
const int MacroActionStream::id = 3;
|
||||
const std::string MacroActionStream::id = "streaming";
|
||||
|
||||
bool MacroActionStream::_registered = MacroActionFactory::Register(
|
||||
MacroActionStream::id,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include <random>
|
||||
|
||||
const int MacroActionWait::id = 1;
|
||||
const std::string MacroActionWait::id = "wait";
|
||||
|
||||
bool MacroActionWait::_registered = MacroActionFactory::Register(
|
||||
MacroActionWait::id,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "headers/utility.hpp"
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
const int MacroConditionAudio::id = 3;
|
||||
const std::string MacroConditionAudio::id = "audio";
|
||||
|
||||
bool MacroConditionAudio::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionAudio::id,
|
||||
|
|
@ -11,8 +11,8 @@ bool MacroConditionAudio::_registered = MacroConditionFactory::Register(
|
|||
"AdvSceneSwitcher.condition.audio"});
|
||||
|
||||
static std::map<AudioCondition, std::string> audioConditionTypes = {
|
||||
{AudioCondition::ABOVE, "AdvSceneSwitcher.ondition.audio.state.above"},
|
||||
{AudioCondition::BELOW, "AdvSceneSwitcher.ondition.audio.state.below"},
|
||||
{AudioCondition::ABOVE, "AdvSceneSwitcher.condition.audio.state.above"},
|
||||
{AudioCondition::BELOW, "AdvSceneSwitcher.condition.audio.state.below"},
|
||||
};
|
||||
|
||||
MacroConditionAudio::~MacroConditionAudio()
|
||||
|
|
@ -35,11 +35,7 @@ bool MacroConditionAudio::CheckCondition()
|
|||
// Reset for next check
|
||||
_peak = -std::numeric_limits<float>::infinity();
|
||||
|
||||
if (!volumeThresholdreached) {
|
||||
_duration.Reset();
|
||||
return false;
|
||||
}
|
||||
return _duration.DurationReached();
|
||||
return volumeThresholdreached;
|
||||
}
|
||||
|
||||
bool MacroConditionAudio::Save(obs_data_t *obj)
|
||||
|
|
@ -49,7 +45,6 @@ bool MacroConditionAudio::Save(obs_data_t *obj)
|
|||
GetWeakSourceName(_audioSource).c_str());
|
||||
obs_data_set_int(obj, "volume", _volume);
|
||||
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
||||
_duration.Save(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -75,12 +70,9 @@ bool MacroConditionAudio::Load(obs_data_t *obj)
|
|||
MacroCondition::Load(obj);
|
||||
const char *audioSourceName = obs_data_get_string(obj, "audioSource");
|
||||
_audioSource = GetWeakSourceByName(audioSourceName);
|
||||
|
||||
_volume = obs_data_get_int(obj, "volume");
|
||||
_condition =
|
||||
static_cast<AudioCondition>(obs_data_get_int(obj, "condition"));
|
||||
_duration.Load(obj);
|
||||
|
||||
_volmeter = AddVolmeterToSource(this, _audioSource);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -123,7 +115,6 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
|||
_audioSources = new QComboBox();
|
||||
_condition = new QComboBox();
|
||||
_volume = new QSpinBox();
|
||||
_duration = new DurationSelection(parent, false);
|
||||
|
||||
_volume->setSuffix("%");
|
||||
_volume->setMaximum(100);
|
||||
|
|
@ -133,13 +124,11 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
|||
SLOT(VolumeThresholdChanged(int)));
|
||||
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(ConditionChanged(int)));
|
||||
QWidget::connect(_duration, SIGNAL(DurationChanged(double)), this,
|
||||
SLOT(DurationChanged(double)));
|
||||
QWidget::connect(_audioSources,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(SourceChanged(const QString &)));
|
||||
|
||||
AdvSceneSwitcher::populateAudioSelection(_audioSources);
|
||||
populateAudioSelection(_audioSources);
|
||||
populateConditionSelection(_condition);
|
||||
|
||||
QHBoxLayout *switchLayout = new QHBoxLayout;
|
||||
|
|
@ -147,7 +136,7 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
|
|||
{"{{audioSources}}", _audioSources},
|
||||
{"{{volume}}", _volume},
|
||||
{"{{condition}}", _condition},
|
||||
{"{{duration}}", _duration}};
|
||||
};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.audio.entry"),
|
||||
switchLayout, widgetPlaceholders);
|
||||
|
||||
|
|
@ -214,16 +203,6 @@ void MacroConditionAudioEdit::ConditionChanged(int 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()
|
||||
{
|
||||
if (!_entryData) {
|
||||
|
|
@ -234,6 +213,5 @@ void MacroConditionAudioEdit::UpdateEntryData()
|
|||
GetWeakSourceName(_entryData->_audioSource).c_str());
|
||||
_volume->setValue(_entryData->_volume);
|
||||
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||
_duration->SetDuration(_entryData->_duration);
|
||||
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-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()) {
|
||||
_methods[id] = info;
|
||||
|
|
@ -11,24 +13,51 @@ bool MacroConditionFactory::Register(int id, MacroConditionInfo info)
|
|||
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 nullptr;
|
||||
}
|
||||
|
||||
QWidget *
|
||||
MacroConditionFactory::CreateWidget(const int id, QWidget *parent,
|
||||
MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent,
|
||||
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 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)
|
||||
{
|
||||
if (root) {
|
||||
|
|
@ -57,24 +86,34 @@ static inline void populateConditionSelection(QComboBox *list)
|
|||
}
|
||||
|
||||
MacroConditionEdit::MacroConditionEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData, int type,
|
||||
bool root, bool startCollapsed)
|
||||
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
|
||||
const std::string &id, bool root, bool startCollapsed)
|
||||
: QWidget(parent)
|
||||
{
|
||||
_logicSelection = new QComboBox();
|
||||
_conditionSelection = new QComboBox();
|
||||
_section = new Section(300);
|
||||
_dur = new DurationConstraintEdit();
|
||||
|
||||
QWidget::connect(_logicSelection, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(LogicSelectionChanged(int)));
|
||||
QWidget::connect(_conditionSelection, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(ConditionSelectionChanged(int)));
|
||||
QWidget::connect(_conditionSelection,
|
||||
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);
|
||||
populateConditionSelection(_conditionSelection);
|
||||
|
||||
_section->AddHeaderWidget(_logicSelection);
|
||||
_section->AddHeaderWidget(_conditionSelection);
|
||||
_section->AddHeaderWidget(_dur);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addWidget(_section);
|
||||
|
|
@ -82,9 +121,8 @@ MacroConditionEdit::MacroConditionEdit(
|
|||
|
||||
_entryData = entryData;
|
||||
_isRoot = root;
|
||||
UpdateEntryData(type);
|
||||
UpdateEntryData(id, startCollapsed);
|
||||
_loading = false;
|
||||
_section->Collapse(startCollapsed);
|
||||
}
|
||||
|
||||
void MacroConditionEdit::LogicSelectionChanged(int idx)
|
||||
|
|
@ -109,11 +147,12 @@ bool MacroConditionEdit::IsRootNode()
|
|||
return _isRoot;
|
||||
}
|
||||
|
||||
void MacroConditionEdit::UpdateEntryData(int type)
|
||||
void MacroConditionEdit::UpdateEntryData(const std::string &id, bool collapse)
|
||||
{
|
||||
_conditionSelection->setCurrentIndex(type);
|
||||
auto widget = MacroConditionFactory::CreateWidget(type, window(),
|
||||
*_entryData);
|
||||
_conditionSelection->setCurrentText(obs_module_text(
|
||||
MacroConditionFactory::GetConditionName(id).c_str()));
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, window(), *_entryData);
|
||||
auto logic = (*_entryData)->GetLogicType();
|
||||
if (IsRootNode()) {
|
||||
_logicSelection->setCurrentIndex(static_cast<int>(logic));
|
||||
|
|
@ -121,29 +160,63 @@ void MacroConditionEdit::UpdateEntryData(int type)
|
|||
_logicSelection->setCurrentIndex(static_cast<int>(logic) -
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
auto logic = (*_entryData)->GetLogicType();
|
||||
_entryData->reset();
|
||||
*_entryData = MacroConditionFactory::Create(idx);
|
||||
(*_entryData)->SetLogicType(logic);
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(idx, window(), *_entryData);
|
||||
_section->SetContent(widget);
|
||||
_section->Collapse(false);
|
||||
(*_entryData)->SetDuration(seconds);
|
||||
}
|
||||
|
||||
void MacroConditionEdit::DurationConditionChanged(DurationCondition cond)
|
||||
{
|
||||
if (_loading || !_entryData) {
|
||||
return;
|
||||
}
|
||||
|
||||
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()
|
||||
|
|
@ -152,17 +225,18 @@ void AdvSceneSwitcher::on_conditionAdd_clicked()
|
|||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
MacroConditionScene temp;
|
||||
std::string id = temp.GetId();
|
||||
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
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;
|
||||
macro->Conditions().back()->SetLogicType(logic);
|
||||
auto newEntry = new MacroConditionEdit(
|
||||
this, ¯o->Conditions().back(), 0, root);
|
||||
this, ¯o->Conditions().back(), id, root, false);
|
||||
ui->macroEditConditionLayout->addWidget(newEntry);
|
||||
ui->macroEditConditionHelp->setVisible(false);
|
||||
newEntry->Collapse(false);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_conditionRemove_clicked()
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include <QTextStream>
|
||||
#include <QFileDialog>
|
||||
|
||||
const int MacroConditionFile::id = 4;
|
||||
const std::string MacroConditionFile::id = "file";
|
||||
|
||||
bool MacroConditionFile::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionFile::id,
|
||||
|
|
|
|||
|
|
@ -3,12 +3,12 @@
|
|||
#include "headers/utility.hpp"
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
const int MacroConditionIdle::id = 10;
|
||||
const std::string MacroConditionIdle::id = "idle";
|
||||
|
||||
bool MacroConditionIdle::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionIdle::id,
|
||||
{MacroConditionIdle::Create, MacroConditionIdleEdit::Create,
|
||||
"AdvSceneSwitcher.condition.idle"});
|
||||
"AdvSceneSwitcher.condition.idle", false});
|
||||
|
||||
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/advanced-scene-switcher.hpp"
|
||||
|
||||
const int MacroConditionMedia::id = 5;
|
||||
const std::string MacroConditionMedia::id = "media";
|
||||
|
||||
bool MacroConditionMedia::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionMedia::id,
|
||||
|
|
@ -256,7 +256,7 @@ MacroConditionMediaEdit::MacroConditionMediaEdit(
|
|||
QWidget::connect(_time, SIGNAL(UnitChanged(DurationUnit)), this,
|
||||
SLOT(TimeUnitChanged(DurationUnit)));
|
||||
|
||||
AdvSceneSwitcher::populateMediaSelection(_mediaSources);
|
||||
populateMediaSelection(_mediaSources);
|
||||
populateMediaStates(_states);
|
||||
populateMediaTimeRestrictions(_timeRestrictions);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@
|
|||
#include "headers/utility.hpp"
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
const int MacroConditionPluginState::id = 11;
|
||||
const std::string MacroConditionPluginState::id = "plugin_state";
|
||||
|
||||
bool MacroConditionPluginState::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionPluginState::id,
|
||||
{MacroConditionPluginState::Create,
|
||||
MacroConditionPluginStateEdit::Create,
|
||||
"AdvSceneSwitcher.condition.pluginState"});
|
||||
"AdvSceneSwitcher.condition.pluginState", false});
|
||||
|
||||
static std::map<PluginStateCondition, std::string> pluginStateConditionTypes = {
|
||||
{PluginStateCondition::SCENESWITCHED,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include <regex>
|
||||
|
||||
const int MacroConditionProcess::id = 9;
|
||||
const std::string MacroConditionProcess::id = "process";
|
||||
|
||||
bool MacroConditionProcess::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionProcess::id,
|
||||
|
|
@ -61,7 +61,7 @@ MacroConditionProcessEdit::MacroConditionProcessEdit(
|
|||
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(FocusChanged(int)));
|
||||
|
||||
AdvSceneSwitcher::populateProcessSelection(_processSelection);
|
||||
populateProcessSelection(_processSelection);
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{processes}}", _processSelection},
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "headers/utility.hpp"
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
const int MacroConditionRecord::id = 8;
|
||||
const std::string MacroConditionRecord::id = "recording";
|
||||
|
||||
bool MacroConditionRecord::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionRecord::id,
|
||||
|
|
@ -32,20 +32,13 @@ bool MacroConditionRecord::CheckCondition()
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!stateMatch) {
|
||||
_duration.Reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
return _duration.DurationReached();
|
||||
return stateMatch;
|
||||
}
|
||||
|
||||
bool MacroConditionRecord::Save(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
obs_data_set_int(obj, "state", static_cast<int>(_recordState));
|
||||
_duration.Save(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +46,6 @@ bool MacroConditionRecord::Load(obs_data_t *obj)
|
|||
{
|
||||
MacroCondition::Load(obj);
|
||||
_recordState = static_cast<RecordState>(obs_data_get_int(obj, "state"));
|
||||
_duration.Load(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -69,14 +61,9 @@ MacroConditionRecordEdit::MacroConditionRecordEdit(
|
|||
: QWidget(parent)
|
||||
{
|
||||
_recordState = new QComboBox();
|
||||
_duration = new DurationSelection();
|
||||
|
||||
QWidget::connect(_recordState, SIGNAL(currentIndexChanged(int)), this,
|
||||
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);
|
||||
|
||||
|
|
@ -84,7 +71,6 @@ MacroConditionRecordEdit::MacroConditionRecordEdit(
|
|||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{recordState}}", _recordState},
|
||||
{"{{duration}}", _duration},
|
||||
};
|
||||
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.record.entry"),
|
||||
|
|
@ -106,26 +92,6 @@ void MacroConditionRecordEdit::StateChanged(int 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()
|
||||
{
|
||||
if (!_entryData) {
|
||||
|
|
@ -134,5 +100,4 @@ void MacroConditionRecordEdit::UpdateEntryData()
|
|||
|
||||
_recordState->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_recordState));
|
||||
_duration->SetDuration(_entryData->_duration);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "headers/utility.hpp"
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
const int MacroConditionRegion::id = 2;
|
||||
const std::string MacroConditionRegion::id = "region";
|
||||
|
||||
bool MacroConditionRegion::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionRegion::id,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "headers/utility.hpp"
|
||||
#include "headers/advanced-scene-switcher.hpp"
|
||||
|
||||
const int MacroConditionScene::id = 0;
|
||||
const std::string MacroConditionScene::id = "scene";
|
||||
|
||||
bool MacroConditionScene::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionScene::id,
|
||||
|
|
@ -29,11 +29,7 @@ bool MacroConditionScene::CheckCondition()
|
|||
sceneMatch = switcher->previousScene == _scene;
|
||||
}
|
||||
|
||||
if (!sceneMatch) {
|
||||
_duration.Reset();
|
||||
return false;
|
||||
}
|
||||
return _duration.DurationReached();
|
||||
return sceneMatch;
|
||||
}
|
||||
|
||||
bool MacroConditionScene::Save(obs_data_t *obj)
|
||||
|
|
@ -41,7 +37,6 @@ bool MacroConditionScene::Save(obs_data_t *obj)
|
|||
MacroCondition::Save(obj);
|
||||
obs_data_set_string(obj, "scene", GetWeakSourceName(_scene).c_str());
|
||||
obs_data_set_int(obj, "type", static_cast<int>(_type));
|
||||
_duration.Save(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -50,7 +45,6 @@ bool MacroConditionScene::Load(obs_data_t *obj)
|
|||
MacroCondition::Load(obj);
|
||||
_scene = GetWeakSourceByName(obs_data_get_string(obj, "scene"));
|
||||
_type = static_cast<SceneType>(obs_data_get_int(obj, "type"));
|
||||
_duration.Load(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -67,26 +61,20 @@ MacroConditionSceneEdit::MacroConditionSceneEdit(
|
|||
{
|
||||
_sceneSelection = new QComboBox();
|
||||
_sceneType = new QComboBox();
|
||||
_duration = new DurationSelection();
|
||||
|
||||
QWidget::connect(_sceneSelection,
|
||||
SIGNAL(currentTextChanged(const QString &)), this,
|
||||
SLOT(SceneChanged(const QString &)));
|
||||
QWidget::connect(_sceneType, SIGNAL(currentIndexChanged(int)), this,
|
||||
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);
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{scenes}}", _sceneSelection},
|
||||
{"{{sceneType}}", _sceneType},
|
||||
{"{{duration}}", _duration},
|
||||
};
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.scene.entry"),
|
||||
mainLayout, widgetPlaceholders);
|
||||
|
|
@ -117,26 +105,6 @@ void MacroConditionSceneEdit::TypeChanged(int 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()
|
||||
{
|
||||
if (!_entryData) {
|
||||
|
|
@ -146,5 +114,4 @@ void MacroConditionSceneEdit::UpdateEntryData()
|
|||
_sceneSelection->setCurrentText(
|
||||
GetWeakSourceName(_entryData->_scene).c_str());
|
||||
_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/advanced-scene-switcher.hpp"
|
||||
|
||||
const int MacroConditionStream::id = 7;
|
||||
const std::string MacroConditionStream::id = "streaming";
|
||||
|
||||
bool MacroConditionStream::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionStream::id,
|
||||
|
|
@ -28,20 +28,13 @@ bool MacroConditionStream::CheckCondition()
|
|||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!stateMatch) {
|
||||
_duration.Reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
return _duration.DurationReached();
|
||||
return stateMatch;
|
||||
}
|
||||
|
||||
bool MacroConditionStream::Save(obs_data_t *obj)
|
||||
{
|
||||
MacroCondition::Save(obj);
|
||||
obs_data_set_int(obj, "state", static_cast<int>(_streamState));
|
||||
_duration.Save(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -49,7 +42,6 @@ bool MacroConditionStream::Load(obs_data_t *obj)
|
|||
{
|
||||
MacroCondition::Load(obj);
|
||||
_streamState = static_cast<StreamState>(obs_data_get_int(obj, "state"));
|
||||
_duration.Load(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -65,14 +57,9 @@ MacroConditionStreamEdit::MacroConditionStreamEdit(
|
|||
: QWidget(parent)
|
||||
{
|
||||
_streamState = new QComboBox();
|
||||
_duration = new DurationSelection();
|
||||
|
||||
QWidget::connect(_streamState, SIGNAL(currentIndexChanged(int)), this,
|
||||
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);
|
||||
|
||||
|
|
@ -80,7 +67,6 @@ MacroConditionStreamEdit::MacroConditionStreamEdit(
|
|||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{streamState}}", _streamState},
|
||||
{"{{duration}}", _duration},
|
||||
};
|
||||
|
||||
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.stream.entry"),
|
||||
|
|
@ -102,26 +88,6 @@ void MacroConditionStreamEdit::StateChanged(int 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()
|
||||
{
|
||||
if (!_entryData) {
|
||||
|
|
@ -130,5 +96,4 @@ void MacroConditionStreamEdit::UpdateEntryData()
|
|||
|
||||
_streamState->setCurrentIndex(
|
||||
static_cast<int>(_entryData->_streamState));
|
||||
_duration->SetDuration(_entryData->_duration);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#include <QToolTip>
|
||||
#include <QMessageBox>
|
||||
|
||||
const int MacroConditionVideo::id = 6;
|
||||
const std::string MacroConditionVideo::id = "video";
|
||||
|
||||
bool MacroConditionVideo::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionVideo::id,
|
||||
|
|
@ -39,15 +39,7 @@ bool MacroConditionVideo::CheckCondition()
|
|||
|
||||
if (_screenshotData) {
|
||||
if (_screenshotData->done) {
|
||||
bool imageMatch = Compare();
|
||||
|
||||
if (!imageMatch) {
|
||||
_duration.Reset();
|
||||
}
|
||||
|
||||
if (imageMatch && _duration.DurationReached()) {
|
||||
match = true;
|
||||
}
|
||||
match = Compare();
|
||||
|
||||
if (!requiresFileInput(_condition)) {
|
||||
_matchImage = std::move(_screenshotData->image);
|
||||
|
|
@ -66,7 +58,6 @@ bool MacroConditionVideo::Save(obs_data_t *obj)
|
|||
obs_data_set_string(obj, "videoSource",
|
||||
GetWeakSourceName(_videoSource).c_str());
|
||||
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
|
||||
_duration.Save(obj);
|
||||
obs_data_set_string(obj, "filePath", _file.c_str());
|
||||
return true;
|
||||
}
|
||||
|
|
@ -77,7 +68,6 @@ bool MacroConditionVideo::Load(obs_data_t *obj)
|
|||
_videoSource = GetWeakSourceByName(videoSourceName);
|
||||
_condition =
|
||||
static_cast<VideoCondition>(obs_data_get_int(obj, "condition"));
|
||||
_duration.Load(obj);
|
||||
_file = obs_data_get_string(obj, "filePath");
|
||||
|
||||
if (requiresFileInput(_condition)) {
|
||||
|
|
@ -137,7 +127,6 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
|||
{
|
||||
_videoSelection = new QComboBox();
|
||||
_condition = new QComboBox();
|
||||
_duration = new DurationSelection();
|
||||
_filePath = new QLineEdit();
|
||||
_browseButton =
|
||||
new QPushButton(obs_module_text("AdvSceneSwitcher.browse"));
|
||||
|
|
@ -151,23 +140,18 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
|
|||
SLOT(SourceChanged(const QString &)));
|
||||
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
|
||||
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,
|
||||
SLOT(FilePathChanged()));
|
||||
QWidget::connect(_browseButton, SIGNAL(clicked()), this,
|
||||
SLOT(BrowseButtonClicked()));
|
||||
|
||||
AdvSceneSwitcher::populateVideoSelection(_videoSelection, false);
|
||||
populateVideoSelection(_videoSelection);
|
||||
populateConditionSelection(_condition);
|
||||
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout;
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{videoSources}}", _videoSelection},
|
||||
{"{{condition}}", _condition},
|
||||
{"{{duration}}", _duration},
|
||||
{"{{filePath}}", _filePath},
|
||||
{"{{browseButton}}", _browseButton},
|
||||
};
|
||||
|
|
@ -324,26 +308,6 @@ void MacroConditionVideoEdit::BrowseButtonClicked()
|
|||
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()
|
||||
{
|
||||
if (!_entryData) {
|
||||
|
|
@ -353,7 +317,6 @@ void MacroConditionVideoEdit::UpdateEntryData()
|
|||
_videoSelection->setCurrentText(
|
||||
GetWeakSourceName(_entryData->_videoSource).c_str());
|
||||
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
|
||||
_duration->SetDuration(_entryData->_duration);
|
||||
_filePath->setText(QString::fromStdString(_entryData->_file));
|
||||
|
||||
if (!requiresFileInput(_entryData->_condition)) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include <regex>
|
||||
|
||||
const int MacroConditionWindow::id = 1;
|
||||
const std::string MacroConditionWindow::id = "window";
|
||||
|
||||
bool MacroConditionWindow::_registered = MacroConditionFactory::Register(
|
||||
MacroConditionWindow::id,
|
||||
|
|
@ -83,12 +83,7 @@ bool MacroConditionWindow::Load(obs_data_t *obj)
|
|||
MacroCondition::Load(obj);
|
||||
_window = obs_data_get_string(obj, "window");
|
||||
_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");
|
||||
#endif
|
||||
_focus = obs_data_get_bool(obj, "focus");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -115,7 +110,7 @@ MacroConditionWindowEdit::MacroConditionWindowEdit(
|
|||
QWidget::connect(_focused, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(FocusChanged(int)));
|
||||
|
||||
AdvSceneSwitcher::populateWindowSelection(_windowSelection);
|
||||
populateWindowSelection(_windowSelection);
|
||||
|
||||
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
|
||||
{"{{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;
|
||||
|
||||
const auto conditionsCollapseThreshold = 4;
|
||||
const auto actionsCollapseThreshold = 2;
|
||||
const auto actionsCollapseThreshold = 4;
|
||||
|
||||
bool macroNameExists(std::string name)
|
||||
{
|
||||
for (auto &m : switcher->macros) {
|
||||
if (m.Name() == name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return !!GetMacroByName(name.c_str());
|
||||
}
|
||||
|
||||
bool AdvSceneSwitcher::addNewMacro(std::string &name)
|
||||
|
|
@ -69,10 +63,14 @@ void AdvSceneSwitcher::on_macroAdd_clicked()
|
|||
|
||||
QListWidgetItem *item = new QListWidgetItem(text, ui->macros);
|
||||
item->setData(Qt::UserRole, text);
|
||||
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(Qt::Checked);
|
||||
ui->macros->setCurrentItem(item);
|
||||
|
||||
ui->macroAdd->disconnect(addPulse);
|
||||
ui->macroHelp->setVisible(false);
|
||||
|
||||
emit MacroAdded(QString::fromStdString(name));
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_macroRemove_clicked()
|
||||
|
|
@ -81,9 +79,11 @@ void AdvSceneSwitcher::on_macroRemove_clicked()
|
|||
if (!item) {
|
||||
return;
|
||||
}
|
||||
QString name;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(switcher->m);
|
||||
int idx = ui->macros->currentRow();
|
||||
QString::fromStdString(switcher->macros[idx].Name());
|
||||
switcher->macros.erase(switcher->macros.begin() + idx);
|
||||
}
|
||||
|
||||
|
|
@ -92,6 +92,7 @@ void AdvSceneSwitcher::on_macroRemove_clicked()
|
|||
if (ui->macros->count() == 0) {
|
||||
ui->macroHelp->setVisible(true);
|
||||
}
|
||||
emit MacroRemoved(name);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_macroUp_clicked()
|
||||
|
|
@ -147,12 +148,17 @@ void AdvSceneSwitcher::on_macroName_editingFinished()
|
|||
if (nameValid) {
|
||||
macro->SetName(newName.toUtf8().constData());
|
||||
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);
|
||||
ui->macros->blockSignals(false);
|
||||
} else {
|
||||
ui->macroName->setText(oldName);
|
||||
}
|
||||
}
|
||||
|
||||
emit MacroRenamed(oldName, newName);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::SetEditMacro(Macro &m)
|
||||
|
|
@ -196,22 +202,14 @@ void AdvSceneSwitcher::SetEditMacro(Macro &m)
|
|||
|
||||
Macro *AdvSceneSwitcher::getSelectedMacro()
|
||||
{
|
||||
Macro *macro = nullptr;
|
||||
QListWidgetItem *item = ui->macros->currentItem();
|
||||
|
||||
if (!item) {
|
||||
return macro;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString name = item->data(Qt::UserRole).toString();
|
||||
for (auto &m : switcher->macros) {
|
||||
if (name.compare(m.Name().c_str()) == 0) {
|
||||
macro = &m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return macro;
|
||||
QString name = item->text();
|
||||
return GetMacroByQString(name);
|
||||
}
|
||||
|
||||
void AdvSceneSwitcher::on_macros_currentRowChanged(int idx)
|
||||
|
|
@ -226,13 +224,26 @@ void AdvSceneSwitcher::on_macros_currentRowChanged(int idx)
|
|||
}
|
||||
|
||||
QListWidgetItem *item = ui->macros->item(idx);
|
||||
QString macroName = item->data(Qt::UserRole).toString();
|
||||
QString macroName = item->text();
|
||||
|
||||
for (auto &m : switcher->macros) {
|
||||
if (macroName.compare(m.Name().c_str()) == 0) {
|
||||
SetEditMacro(m);
|
||||
break;
|
||||
}
|
||||
auto macro = GetMacroByQString(macroName);
|
||||
if (macro) {
|
||||
SetEditMacro(*macro);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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) {
|
||||
addPulse = PulseWidget(ui->macroAdd, QColor(Qt::green));
|
||||
if (!switcher->disableHints) {
|
||||
addPulse = PulseWidget(ui->macroAdd, QColor(Qt::green));
|
||||
}
|
||||
ui->macroHelp->setVisible(true);
|
||||
} else {
|
||||
ui->macroHelp->setVisible(false);
|
||||
|
|
@ -286,5 +305,7 @@ void AdvSceneSwitcher::copyMacro()
|
|||
QString text = QString::fromStdString(name);
|
||||
QListWidgetItem *item = new QListWidgetItem(text, ui->macros);
|
||||
item->setData(Qt::UserRole, text);
|
||||
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(Qt::Checked);
|
||||
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-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 = {
|
||||
{LogicType::NONE, {"AdvSceneSwitcher.logic.none"}},
|
||||
|
|
@ -14,15 +17,26 @@ const std::map<LogicType, LogicTypeInfo> MacroCondition::logicTypes = {
|
|||
{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()
|
||||
{
|
||||
_matched = false;
|
||||
for (auto &c : _conditions) {
|
||||
bool cond = c->CheckCondition();
|
||||
if (!cond) {
|
||||
c->ResetDuration();
|
||||
}
|
||||
cond = cond && c->DurationReached();
|
||||
|
||||
switch (c->GetLogicType()) {
|
||||
case LogicType::NONE:
|
||||
|
|
@ -55,6 +69,21 @@ bool Macro::CeckMatch()
|
|||
_name.c_str());
|
||||
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;
|
||||
|
|
@ -70,13 +99,29 @@ bool Macro::PerformAction()
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret && _count != std::numeric_limits<int>::max()) {
|
||||
_count++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Macro::SetName(const std::string &name)
|
||||
{
|
||||
_name = name;
|
||||
SetHotkeysDesc();
|
||||
}
|
||||
|
||||
bool Macro::Save(obs_data_t *obj)
|
||||
{
|
||||
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();
|
||||
for (auto &c : _conditions) {
|
||||
|
|
@ -142,15 +187,27 @@ void setValidLogic(MacroCondition *c, bool root, std::string name)
|
|||
bool Macro::Load(obs_data_t *obj)
|
||||
{
|
||||
_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");
|
||||
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);
|
||||
|
||||
int id = obs_data_get_int(array_obj, "id");
|
||||
std::string id = obs_data_get_string(array_obj, "id");
|
||||
|
||||
auto newEntry = MacroConditionFactory::Create(id);
|
||||
if (newEntry) {
|
||||
|
|
@ -160,8 +217,8 @@ bool Macro::Load(obs_data_t *obj)
|
|||
setValidLogic(c, root, _name);
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"discarding condition entry with unkown id (%d) for macro %s",
|
||||
id, _name.c_str());
|
||||
"discarding condition entry with unkown id (%s) for macro %s",
|
||||
id.c_str(), _name.c_str());
|
||||
}
|
||||
|
||||
obs_data_release(array_obj);
|
||||
|
|
@ -175,7 +232,7 @@ bool Macro::Load(obs_data_t *obj)
|
|||
for (size_t i = 0; i < count; 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);
|
||||
if (newEntry) {
|
||||
|
|
@ -183,44 +240,154 @@ bool Macro::Load(obs_data_t *obj)
|
|||
_actions.back()->Load(array_obj);
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"discarding action entry with unkown id (%d) for macro %s",
|
||||
id, _name.c_str());
|
||||
"discarding action entry with unkown id (%s) for macro %s",
|
||||
id.c_str(), _name.c_str());
|
||||
}
|
||||
|
||||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_array_release(actions);
|
||||
|
||||
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()
|
||||
{
|
||||
MacroActionSwitchScene temp;
|
||||
auto sceneSwitchId = temp.GetId();
|
||||
for (auto &a : _actions) {
|
||||
if (a->GetId() == temp.GetId()) {
|
||||
if (a->GetId() == sceneSwitchId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
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));
|
||||
_duration.Save(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroCondition::Load(obs_data_t *obj)
|
||||
{
|
||||
_logic = static_cast<LogicType>(obs_data_get_int(obj, "logic"));
|
||||
_duration.Load(obj);
|
||||
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)
|
||||
{
|
||||
obs_data_set_int(obj, "id", GetId());
|
||||
obs_data_set_string(obj, "id", GetId().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +399,7 @@ bool MacroAction::Load(obs_data_t *obj)
|
|||
|
||||
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)
|
||||
|
|
@ -250,8 +417,71 @@ void SwitcherData::saveMacros(obs_data_t *obj)
|
|||
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)
|
||||
{
|
||||
// TODO: Remove conversion helper in future version
|
||||
std::string previousVersion = obs_data_get_string(obj, "version");
|
||||
if (previousVersion == "2ce0b35921be892c987c7dbb5fc90db38f15f0a6") {
|
||||
convertOldMacroIdsToString(obj);
|
||||
}
|
||||
|
||||
macros.clear();
|
||||
|
||||
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_array_release(macroArray);
|
||||
|
||||
for (auto &m : macros) {
|
||||
m.ResolveMacroRef();
|
||||
}
|
||||
}
|
||||
|
||||
bool SwitcherData::checkMacros()
|
||||
|
|
@ -286,7 +520,7 @@ bool SwitcherData::runMacros()
|
|||
{
|
||||
for (auto &m : macros) {
|
||||
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()) {
|
||||
blog(LOG_WARNING, "abort macro: %s",
|
||||
m.Name().c_str());
|
||||
|
|
@ -296,3 +530,69 @@ bool SwitcherData::runMacros()
|
|||
}
|
||||
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(
|
||||
kCGWindowListOptionAll, kCGNullWindowID);
|
||||
for (NSDictionary *app in apps) {
|
||||
// Construct string from NSString accounting for nil
|
||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowName"]
|
||||
|
|
@ -30,53 +29,26 @@ void GetWindowList(std::vector<std::string> &windows)
|
|||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
|
||||
// Check if name exists
|
||||
if (!name.empty() &&
|
||||
find(windows.begin(), windows.end(), name) ==
|
||||
windows.end())
|
||||
windows.emplace_back(name);
|
||||
// Check if owner exists
|
||||
else if (!owner.empty() &&
|
||||
find(windows.begin(), windows.end(), owner) ==
|
||||
windows.end())
|
||||
|
||||
if (!owner.empty() &&
|
||||
find(windows.begin(), windows.end(), owner) ==
|
||||
windows.end())
|
||||
windows.emplace_back(owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Overloaded
|
||||
void GetWindowList(QStringList &windows)
|
||||
{
|
||||
windows.clear();
|
||||
|
||||
@autoreleasepool {
|
||||
NSMutableArray *apps =
|
||||
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
|
||||
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);
|
||||
}
|
||||
std::vector<std::string> temp;
|
||||
GetWindowList(temp);
|
||||
for (auto &w : temp) {
|
||||
windows << QString::fromStdString(w);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -94,7 +66,6 @@ void GetCurrentWindowTitle(std::string &title)
|
|||
[[app objectForKey:@"kCGWindowLayer"] intValue];
|
||||
// True if window is frontmost
|
||||
if (layer == 0) {
|
||||
// Construct string from NSString accounting for nil
|
||||
std::string name(
|
||||
[[app objectForKey:@"kCGWindowName"]
|
||||
UTF8String],
|
||||
|
|
@ -130,23 +101,68 @@ std::pair<int, int> getCursorPos()
|
|||
return pos;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// not implemented on MacOS as I cannot test it
|
||||
bool isMaximized(std::string &title)
|
||||
bool isWindowOriginOnScreen(NSDictionary *app, NSScreen *screen,
|
||||
bool fullscreen = false)
|
||||
{
|
||||
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 {
|
||||
NSArray *screens = [NSScreen screens];
|
||||
NSMutableArray *apps =
|
||||
(__bridge NSMutableArray *)CGWindowListCopyWindowInfo(
|
||||
kCGWindowListOptionAll, kCGNullWindowID);
|
||||
for (NSDictionary *app in apps) {
|
||||
// Construct string from NSString accounting for nil
|
||||
std::string name([[app objectForKey:@"kCGWindowName"]
|
||||
UTF8String],
|
||||
[[app objectForKey:@"kCGWindowName"]
|
||||
|
|
@ -159,51 +175,69 @@ bool isFullscreen(std::string &title)
|
|||
lengthOfBytesUsingEncoding:
|
||||
NSUTF8StringEncoding]);
|
||||
|
||||
// True if switch equals app
|
||||
bool equals = (title == name || title == owner);
|
||||
// True if switch matches app
|
||||
bool matches = (QString::fromStdString(name).contains(
|
||||
QRegularExpression(
|
||||
QString::fromStdString(
|
||||
title))) ||
|
||||
QString::fromStdString(owner).contains(
|
||||
QRegularExpression(
|
||||
QString::fromStdString(
|
||||
title))));
|
||||
|
||||
// If found, check if fullscreen
|
||||
bool matches = nameMachesPattern(name, title) ||
|
||||
nameMachesPattern(owner, title);
|
||||
if (equals || matches) {
|
||||
// Get window bounds
|
||||
NSRect bounds;
|
||||
CGRectMakeWithDictionaryRepresentation(
|
||||
(CFDictionaryRef)[app
|
||||
objectForKey:@"kCGWindowBounds"],
|
||||
&bounds);
|
||||
|
||||
// Compare to screen bounds
|
||||
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 origin =
|
||||
(bounds.origin.x ==
|
||||
frame.origin.x &&
|
||||
([screens[0] visibleFrame]
|
||||
.size.height -
|
||||
frame.size.height -
|
||||
bounds.origin.y ==
|
||||
frame.origin.y));
|
||||
// True if window size equals screen size
|
||||
bool size = NSEqualSizes(bounds.size,
|
||||
frame.size);
|
||||
bool isWindowFullscreenOnScreen(NSDictionary *app, NSScreen *screen)
|
||||
{
|
||||
NSRect screenFrame = [screen frame];
|
||||
NSRect windowBounds;
|
||||
CGRectMakeWithDictionaryRepresentation(
|
||||
(CFDictionaryRef)[app objectForKey:@"kCGWindowBounds"],
|
||||
&windowBounds);
|
||||
|
||||
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 false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -499,7 +499,10 @@ void AdvSceneSwitcher::setupSceneGroupTab()
|
|||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
ui->sceneGroupHelp->setVisible(false);
|
||||
|
|
|
|||
|
|
@ -347,7 +347,10 @@ void AdvSceneSwitcher::setupTriggerTab()
|
|||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
ui->triggerHelp->setVisible(false);
|
||||
|
|
@ -381,7 +384,7 @@ void SceneTrigger::load(obs_data_t *obj)
|
|||
|
||||
static inline void populateTriggers(QComboBox *list)
|
||||
{
|
||||
AdvSceneSwitcher::addSelectionEntry(
|
||||
addSelectionEntry(
|
||||
list,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.none"));
|
||||
|
|
@ -396,7 +399,7 @@ static inline void populateTriggers(QComboBox *list)
|
|||
|
||||
inline void populateActions(QComboBox *list)
|
||||
{
|
||||
AdvSceneSwitcher::addSelectionEntry(
|
||||
addSelectionEntry(
|
||||
list,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.none"));
|
||||
|
|
@ -451,7 +454,7 @@ SceneTriggerWidget::SceneTriggerWidget(QWidget *parent, SceneTrigger *s)
|
|||
|
||||
populateTriggers(triggers);
|
||||
populateActions(actions);
|
||||
AdvSceneSwitcher::populateAudioSelection(audioSources);
|
||||
populateAudioSelection(audioSources);
|
||||
|
||||
if (s) {
|
||||
triggers->setCurrentIndex(static_cast<int>(s->triggerType));
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
#include <QPropertyAnimation>
|
||||
#include "headers/section.hpp"
|
||||
#include "headers/utility.hpp"
|
||||
|
||||
#include <QPropertyAnimation>
|
||||
#include <QEvent>
|
||||
|
||||
Section::Section(const int animationDuration, QWidget *parent)
|
||||
: QWidget(parent), _animationDuration(animationDuration)
|
||||
{
|
||||
|
|
@ -38,45 +40,74 @@ Section::Section(const int animationDuration, QWidget *parent)
|
|||
connect(_toggleButton, &QToolButton::toggled, this, &Section::Collapse);
|
||||
}
|
||||
|
||||
void Section::Collapse(bool collapsed)
|
||||
void Section::Collapse(bool collapse)
|
||||
{
|
||||
_toggleButton->setChecked(collapsed);
|
||||
_toggleButton->setArrowType(!collapsed ? Qt::ArrowType::DownArrow
|
||||
: Qt::ArrowType::RightArrow);
|
||||
_toggleAnimation->setDirection(!collapsed
|
||||
_toggleButton->setChecked(collapse);
|
||||
_toggleButton->setArrowType(!collapse ? Qt::ArrowType::DownArrow
|
||||
: Qt::ArrowType::RightArrow);
|
||||
_toggleAnimation->setDirection(!collapse
|
||||
? QAbstractAnimation::Forward
|
||||
: QAbstractAnimation::Backward);
|
||||
_transitioning = true;
|
||||
_collapsed = collapse;
|
||||
_toggleAnimation->start();
|
||||
}
|
||||
|
||||
void Section::SetContent(QWidget *w)
|
||||
void Section::SetContent(QWidget *w, bool collapsed)
|
||||
{
|
||||
// Clean up previous content
|
||||
if (_contentArea) {
|
||||
auto oldLayout = _contentArea->layout();
|
||||
if (oldLayout) {
|
||||
clearLayout(oldLayout);
|
||||
delete oldLayout;
|
||||
}
|
||||
}
|
||||
|
||||
CleanUpPreviousContent();
|
||||
delete _contentArea;
|
||||
delete _toggleAnimation;
|
||||
|
||||
// Setup contentArea
|
||||
_contentArea = new QScrollArea(this);
|
||||
_contentArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
|
||||
// Start out collapsed
|
||||
_contentArea->setStyleSheet("QScrollArea { border: none; }");
|
||||
_contentArea->setMaximumHeight(0);
|
||||
_contentArea->setMinimumHeight(0);
|
||||
|
||||
w->installEventFilter(this);
|
||||
_content = w;
|
||||
auto newLayout = new QVBoxLayout();
|
||||
newLayout->setContentsMargins(0, 0, 0, 0);
|
||||
newLayout->addWidget(w);
|
||||
_contentArea->setLayout(newLayout);
|
||||
_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->addAnimation(
|
||||
new QPropertyAnimation(this, "minimumHeight"));
|
||||
|
|
@ -85,17 +116,13 @@ void Section::SetContent(QWidget *w)
|
|||
_toggleAnimation->addAnimation(
|
||||
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) {
|
||||
QPropertyAnimation *SectionAnimation =
|
||||
static_cast<QPropertyAnimation *>(
|
||||
_toggleAnimation->animationAt(i));
|
||||
SectionAnimation->setDuration(_animationDuration);
|
||||
SectionAnimation->setStartValue(collapsedHeight);
|
||||
SectionAnimation->setEndValue(collapsedHeight + contentHeight);
|
||||
SectionAnimation->setStartValue(_headerHeight);
|
||||
SectionAnimation->setEndValue(_headerHeight + _contentHeight);
|
||||
}
|
||||
|
||||
QPropertyAnimation *contentAnimation =
|
||||
|
|
@ -103,10 +130,24 @@ void Section::SetContent(QWidget *w)
|
|||
_toggleAnimation->animationCount() - 1));
|
||||
contentAnimation->setDuration(_animationDuration);
|
||||
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) {
|
||||
addPulse = PulseWidget(ui->audioAdd, QColor(Qt::green));
|
||||
if (!switcher->disableHints) {
|
||||
addPulse = PulseWidget(ui->audioAdd, QColor(Qt::green));
|
||||
}
|
||||
ui->audioHelp->setVisible(true);
|
||||
} else {
|
||||
ui->audioHelp->setVisible(false);
|
||||
|
|
@ -447,7 +449,7 @@ AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
|
|||
QWidget::connect(ignoreInactiveSource, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(IgnoreInactiveChanged(int)));
|
||||
|
||||
AdvSceneSwitcher::populateAudioSelection(audioSources);
|
||||
populateAudioSelection(audioSources);
|
||||
populateConditionSelection(condition);
|
||||
|
||||
if (s) {
|
||||
|
|
|
|||
|
|
@ -187,7 +187,10 @@ void AdvSceneSwitcher::setupExecutableTab()
|
|||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
ui->exeHelp->setVisible(false);
|
||||
|
|
@ -223,7 +226,7 @@ ExecutableSwitchWidget::ExecutableSwitchWidget(QWidget *parent,
|
|||
QWidget::connect(requiresFocus, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(FocusChanged(int)));
|
||||
|
||||
AdvSceneSwitcher::populateProcessSelection(processes);
|
||||
populateProcessSelection(processes);
|
||||
|
||||
processes->setEditable(true);
|
||||
processes->setMaxVisibleItems(20);
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ void SwitcherData::writeSceneInfoToFile()
|
|||
obs_source_release(currentSource);
|
||||
}
|
||||
|
||||
void SwitcherData::writeToStatusFile(QString msg)
|
||||
void SwitcherData::writeToStatusFile(const QString &msg)
|
||||
{
|
||||
if (!fileIO.writeEnabled || fileIO.writePath.empty()) {
|
||||
return;
|
||||
|
|
@ -415,7 +415,9 @@ void AdvSceneSwitcher::setupFileTab()
|
|||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
ui->fileHelp->setVisible(false);
|
||||
|
|
|
|||
|
|
@ -228,10 +228,9 @@ SwitchWidget::SwitchWidget(QWidget *parent, SceneSwitcherEntry *s,
|
|||
SIGNAL(SceneGroupRenamed(const QString &, const QString &)),
|
||||
this, SLOT(SceneGroupRename(const QString &, const QString &)));
|
||||
|
||||
AdvSceneSwitcher::populateSceneSelection(scenes, usePreviousScene,
|
||||
addSceneGroup);
|
||||
AdvSceneSwitcher::populateTransitionSelection(transitions,
|
||||
addCurrentTransition);
|
||||
populateSceneSelection(scenes, usePreviousScene, addSceneGroup,
|
||||
&switcher->sceneGroups);
|
||||
populateTransitionSelection(transitions, addCurrentTransition);
|
||||
|
||||
switchData = s;
|
||||
showSwitchData();
|
||||
|
|
|
|||
|
|
@ -244,7 +244,9 @@ void AdvSceneSwitcher::setupMediaTab()
|
|||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
ui->mediaHelp->setVisible(false);
|
||||
|
|
@ -458,7 +460,7 @@ MediaSwitchWidget::MediaSwitchWidget(QWidget *parent, MediaSwitch *s)
|
|||
QWidget::connect(time, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(TimeChanged(int)));
|
||||
|
||||
AdvSceneSwitcher::populateMediaSelection(mediaSources);
|
||||
populateMediaSelection(mediaSources);
|
||||
populateMediaStates(states);
|
||||
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_PORT "ClientPort"
|
||||
#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 SCENE_ENTRY "scene"
|
||||
#define TRANSITION_ENTRY "transition"
|
||||
#define TRANSITION_DURATION "duration"
|
||||
#define SET_PREVIEW "preview"
|
||||
|
||||
using websocketpp::lib::placeholders::_1;
|
||||
using websocketpp::lib::placeholders::_2;
|
||||
|
|
@ -36,7 +39,9 @@ NetworkConfig::NetworkConfig()
|
|||
ClientEnabled(false),
|
||||
Address(""),
|
||||
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);
|
||||
Address = obs_data_get_string(obj, PARAM_ADDRESS);
|
||||
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)
|
||||
|
|
@ -63,7 +72,10 @@ void NetworkConfig::Save(obs_data_t *obj)
|
|||
obs_data_set_bool(obj, PARAM_CLIENT_ENABLE, ClientEnabled);
|
||||
obs_data_set_string(obj, PARAM_ADDRESS, Address.c_str());
|
||||
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)
|
||||
|
|
@ -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_string(obj, PARAM_ADDRESS, Address.c_str());
|
||||
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()
|
||||
|
|
@ -83,6 +99,21 @@ std::string NetworkConfig::GetClientUri()
|
|||
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()
|
||||
: QObject(nullptr), _connections(), _clMutex(QMutex::Recursive)
|
||||
{
|
||||
|
|
@ -192,7 +223,7 @@ void WSServer::stop()
|
|||
blog(LOG_INFO, "server stopped successfully");
|
||||
}
|
||||
|
||||
void WSServer::sendMessage(sceneSwitchInfo sceneSwitch)
|
||||
void WSServer::sendMessage(sceneSwitchInfo sceneSwitch, bool preview)
|
||||
{
|
||||
if (!sceneSwitch.scene) {
|
||||
return;
|
||||
|
|
@ -204,6 +235,7 @@ void WSServer::sendMessage(sceneSwitchInfo sceneSwitch)
|
|||
obs_data_set_string(data, TRANSITION_ENTRY,
|
||||
GetWeakSourceName(sceneSwitch.transition).c_str());
|
||||
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);
|
||||
obs_data_release(data);
|
||||
|
||||
|
|
@ -248,7 +280,8 @@ std::string processMessage(std::string payload)
|
|||
|
||||
if (!obs_data_has_user_value(data, SCENE_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";
|
||||
}
|
||||
|
||||
|
|
@ -256,6 +289,7 @@ std::string processMessage(std::string payload)
|
|||
std::string transitionName =
|
||||
obs_data_get_string(data, TRANSITION_ENTRY);
|
||||
int duration = obs_data_get_int(data, TRANSITION_DURATION);
|
||||
bool preview = obs_data_get_bool(data, SET_PREVIEW);
|
||||
|
||||
obs_data_release(data);
|
||||
|
||||
|
|
@ -271,8 +305,11 @@ std::string processMessage(std::string payload)
|
|||
ret += " - ignoring invalid transition: '" + transitionName +
|
||||
"'";
|
||||
}
|
||||
|
||||
switchScene({scene, transition, duration});
|
||||
if (preview) {
|
||||
switchPreviewScene(scene);
|
||||
} else {
|
||||
switchScene({scene, transition, duration});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -478,7 +515,12 @@ void AdvSceneSwitcher::setupNetworkTab()
|
|||
ui->clientSettings->setChecked(switcher->networkConfig.ClientEnabled);
|
||||
ui->clientHostname->setText(switcher->networkConfig.Address.c_str());
|
||||
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);
|
||||
connect(statusTimer, SIGNAL(timeout()), this,
|
||||
|
|
@ -592,6 +634,17 @@ void AdvSceneSwitcher::on_clientPort_valueChanged(int 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)
|
||||
{
|
||||
if (loading) {
|
||||
|
|
@ -599,7 +652,17 @@ void AdvSceneSwitcher::on_restrictSend_stateChanged(int state)
|
|||
}
|
||||
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -222,7 +222,6 @@ void SwitcherData::savePauseSwitches(obs_data_t *obj)
|
|||
obs_data_release(array_obj);
|
||||
}
|
||||
obs_data_set_array(obj, "pauseEntries", pauseScenesArray);
|
||||
obs_data_set_int(obj, "oldPauseValuesImported", 1);
|
||||
obs_data_array_release(pauseScenesArray);
|
||||
}
|
||||
|
||||
|
|
@ -265,7 +264,9 @@ void AdvSceneSwitcher::setupPauseTab()
|
|||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
ui->pauseHelp->setVisible(false);
|
||||
|
|
@ -316,7 +317,7 @@ PauseEntryWidget::PauseEntryWidget(QWidget *parent, PauseEntry *s)
|
|||
|
||||
populatePauseTypes(pauseTypes);
|
||||
populatePauseTargets(pauseTargets);
|
||||
AdvSceneSwitcher::populateWindowSelection(windows);
|
||||
populateWindowSelection(windows);
|
||||
|
||||
windows->setEditable(true);
|
||||
windows->setMaxVisibleItems(20);
|
||||
|
|
|
|||
|
|
@ -125,15 +125,20 @@ void AdvSceneSwitcher::setupRandomTab()
|
|||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
ui->randomHelp->setVisible(false);
|
||||
}
|
||||
|
||||
if (switcher->switchIfNotMatching != RANDOM_SWITCH) {
|
||||
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
||||
QColor(0, 0, 0, 0), "QLabel ");
|
||||
if (!switcher->disableHints) {
|
||||
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
|
||||
QColor(0, 0, 0, 0), "QLabel ");
|
||||
}
|
||||
} else {
|
||||
ui->randomDisabledWarning->setVisible(false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,7 +245,10 @@ void AdvSceneSwitcher::setupRegionTab()
|
|||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
ui->regionHelp->setVisible(false);
|
||||
|
|
@ -320,8 +323,8 @@ ScreenRegionWidget::ScreenRegionWidget(QWidget *parent, ScreenRegionSwitch *s)
|
|||
QWidget::connect(maxY, SIGNAL(valueChanged(int)), this,
|
||||
SLOT(MaxYChanged(int)));
|
||||
|
||||
AdvSceneSwitcher::populateSceneSelection(
|
||||
excludeScenes, false, false, true,
|
||||
populateSceneSelection(
|
||||
excludeScenes, false, false, nullptr, true,
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.screenRegionTab.excludeScenes.None"),
|
||||
true);
|
||||
|
|
|
|||
|
|
@ -289,7 +289,10 @@ void AdvSceneSwitcher::setupSequenceTab()
|
|||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
ui->sequenceHelp->setVisible(false);
|
||||
|
|
@ -440,8 +443,6 @@ void SceneSequenceSwitch::prepareUninterruptibleMatch(
|
|||
{
|
||||
int dur = delay.seconds * 1000;
|
||||
if (dur > 0) {
|
||||
switcher->waitScene = obs_weak_source_get_source(currentScene);
|
||||
obs_source_release(switcher->waitScene);
|
||||
linger = dur;
|
||||
}
|
||||
}
|
||||
|
|
@ -588,7 +589,7 @@ SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s,
|
|||
QWidget::connect(reduce, SIGNAL(clicked()), this,
|
||||
SLOT(ReduceClicked()));
|
||||
|
||||
AdvSceneSwitcher::populateSceneSelection(startScenes, false);
|
||||
populateSceneSelection(startScenes);
|
||||
interruptible->setToolTip(obs_module_text(
|
||||
"AdvSceneSwitcher.sceneSequenceTab.interruptibleHint"));
|
||||
|
||||
|
|
|
|||
|
|
@ -191,7 +191,9 @@ void AdvSceneSwitcher::setupTimeTab()
|
|||
}
|
||||
|
||||
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);
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
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_data_t *data = obs_source_get_private_settings(scene);
|
||||
|
|
@ -257,7 +257,7 @@ void overwriteTransitionOverride(sceneSwitchInfo ssi, transitionData &td)
|
|||
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);
|
||||
|
||||
|
|
@ -267,7 +267,7 @@ void restoreTransitionOverride(obs_source_t *scene, transitionData td)
|
|||
obs_data_release(data);
|
||||
}
|
||||
|
||||
void setNextTransition(sceneSwitchInfo &sceneSwitch,
|
||||
void setNextTransition(const sceneSwitchInfo &sceneSwitch,
|
||||
obs_source_t *currentSource, transitionData &td)
|
||||
{
|
||||
// Priority:
|
||||
|
|
@ -495,7 +495,7 @@ TransitionSwitchWidget::TransitionSwitchWidget(QWidget *parent,
|
|||
QWidget::connect(duration, SIGNAL(valueChanged(double)), this,
|
||||
SLOT(DurationChanged(double)));
|
||||
|
||||
AdvSceneSwitcher::populateSceneSelection(scenes2, false);
|
||||
populateSceneSelection(scenes2);
|
||||
|
||||
if (s) {
|
||||
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