Compare commits

..

1 Commits
1.22.1 ... osx

Author SHA1 Message Date
WarmUpTill
b74e9d2e2a Enable executing AppleScripts on MacOS 2023-03-04 18:14:16 +01:00
321 changed files with 4469 additions and 74971 deletions

View File

@@ -1,37 +0,0 @@
name: 'Package plugin'
description: 'Packages the plugin for specified architecture and build config.'
inputs:
target:
description: 'Build target'
required: true
workingDirectory:
description: 'Working directory'
required: false
default: ${{ github.workspace }}
runs:
using: 'composite'
steps:
- name: Run macOS tests
if: ${{ runner.os == 'macOS' }}
shell: zsh {0}
run: |
if [[ '${{ inputs.target }}' != 'x86_64' ]]; then
echo tests skipped!
exit 0
fi
${{ inputs.workingDirectory }}/build_x86_64/tests/advanced-scene-switcher-tests
- name: Run Linux packaging
if: ${{ runner.os == 'Linux' }}
shell: bash
run: |
if [[ '${{ inputs.target }}' != 'x86_64' ]]; then
exit 0
fi
${{ inputs.workingDirectory }}/build_x86_64/tests/advanced-scene-switcher-tests
- name: Run Windows packaging
if: ${{ runner.os == 'Windows' }}
shell: pwsh
run: |
${{ inputs.workingDirectory }}/build_x64/tests/RelWithDebInfo/advanced-scene-switcher-tests.exe

View File

@@ -170,17 +170,11 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
local product_name
local product_version
local git_tag="$(git describe --tags)"
read -r product_name product_version <<< \
"$(jq -r '. | {name, version} | join(" ")' ${buildspec_file})"
if [[ "${git_tag}" =~ '^([0-9]+\.){0,2}(\*|[0-9]+)$' ]] {
log_info "Using git tag as version identifier '${git_tag}'"
product_version="${git_tag}"
} else {
log_info "Using buildspec.json version identifier '${product_version}'"
}
case ${host_os} {
macos)

View File

@@ -128,18 +128,9 @@ Usage: %B${functrace[1]%:*}%b <option> [<options>]
local product_name
local product_version
local git_tag="$(git describe --tags)"
read -r product_name product_version <<< \
"$(jq -r '. | {name, version} | join(" ")' ${project_root}/buildspec.json)"
if [[ "${git_tag}" =~ '^([0-9]+\.){0,2}(\*|[0-9]+)$' ]] {
log_info "Using git tag as version identifier '${git_tag}'"
product_version="${git_tag}"
} else {
log_info "Using buildspec.json version identifier '${product_version}'"
}
if [[ ${host_os} == 'macos' ]] {
autoload -Uz check_packages read_codesign read_codesign_installer read_codesign_pass

View File

@@ -155,12 +155,6 @@ jobs:
codesign: 'true'
codesignIdent: ${{ env.CODESIGN_IDENT }}
- name: Run tests
uses: ./plugin/.github/actions/run-tests
with:
workingDirectory: ${{ github.workspace }}/plugin
target: ${{ matrix.arch }}
- name: Package Plugin
uses: ./plugin/.github/actions/package-plugin
with:
@@ -256,12 +250,6 @@ jobs:
config: RelWithDebInfo
portable: ${{ matrix.portable }}
- name: Run tests
uses: ./plugin/.github/actions/run-tests
with:
workingDirectory: ${{ github.workspace }}/plugin
target: ${{ matrix.arch }}
- name: Package Plugin
uses: ./plugin/.github/actions/package-plugin
with:
@@ -365,12 +353,6 @@ jobs:
config: RelWithDebInfo
visualStudio: 'Visual Studio 17 2022'
- name: Run tests
uses: ./plugin/.github/actions/run-tests
with:
workingDirectory: ${{ github.workspace }}/plugin
target: ${{ matrix.arch }}
- name: Package Plugin
uses: ./plugin/.github/actions/package-plugin
with:
@@ -425,11 +407,10 @@ jobs:
for file in ${{ github.workspace }}/**/@(*.pkg|*.exe|*.deb|*.zip); do
echo " ${file##*/}: $(sha256sum "${file}" | cut -d " " -f 1)" >> ${{ github.workspace }}/CHECKSUMS.txt
done
cat ${{ github.workspace }}/CHECKSUMS.txt
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@1e07f4398721186383de40550babbdf2b84acfc5
with:
draft: true
prerelease: true

3
.gitmodules vendored
View File

@@ -16,6 +16,3 @@
[submodule "deps/tesseract"]
path = deps/tesseract
url = https://github.com/tesseract-ocr/tesseract.git
[submodule "deps/libremidi"]
path = deps/libremidi
url = https://github.com/jcelerier/libremidi.git

View File

@@ -42,20 +42,21 @@ target_sources(
src/general.cpp
src/hotkey.cpp
src/hotkey.hpp
src/hotkey.hpp
src/platform-funcs.hpp
src/scene-group.cpp
src/scene-group.hpp
src/status-control.cpp
src/status-control.hpp
src/switcher-data.cpp
src/switcher-data.hpp
src/switcher-data-structs.cpp
src/switcher-data-structs.hpp
src/version.cpp
src/version.h)
# Legacy function sources
target_sources(
${LIB_NAME}
PRIVATE src/legacy/scene-group.cpp
src/legacy/scene-group.hpp
src/legacy/scene-trigger.cpp
PRIVATE src/legacy/scene-trigger.cpp
src/legacy/scene-trigger.hpp
src/legacy/switch-audio.cpp
src/legacy/switch-audio.hpp
@@ -73,6 +74,7 @@ target_sources(
src/legacy/switch-network.hpp
src/legacy/switch-pause.cpp
src/legacy/switch-pause.hpp
src/legacy/switch-priority.cpp
src/legacy/switch-random.cpp
src/legacy/switch-random.hpp
src/legacy/switch-screen-region.cpp
@@ -107,8 +109,6 @@ target_sources(
src/macro-core/macro-action-macro.hpp
src/macro-core/macro-action-media.cpp
src/macro-core/macro-action-media.hpp
src/macro-core/macro-action-osc.cpp
src/macro-core/macro-action-osc.hpp
src/macro-core/macro-action-plugin-state.cpp
src/macro-core/macro-action-plugin-state.hpp
src/macro-core/macro-action-profile.cpp
@@ -165,8 +165,6 @@ target_sources(
src/macro-core/macro-condition-cursor.hpp
src/macro-core/macro-condition-date.cpp
src/macro-core/macro-condition-date.hpp
src/macro-core/macro-condition-display.cpp
src/macro-core/macro-condition-display.hpp
src/macro-core/macro-condition-edit.cpp
src/macro-core/macro-condition-edit.hpp
src/macro-core/macro-condition-file.cpp
@@ -193,8 +191,6 @@ target_sources(
src/macro-core/macro-condition-recording.hpp
src/macro-core/macro-condition-replay-buffer.cpp
src/macro-core/macro-condition-replay-buffer.hpp
src/macro-core/macro-condition-run.cpp
src/macro-core/macro-condition-run.hpp
src/macro-core/macro-condition-scene-order.cpp
src/macro-core/macro-condition-scene-order.hpp
src/macro-core/macro-condition-scene-transform.cpp
@@ -223,8 +219,6 @@ target_sources(
src/macro-core/macro-condition-window.hpp
src/macro-core/macro-condition.cpp
src/macro-core/macro-condition.hpp
src/macro-core/macro-dock.cpp
src/macro-core/macro-dock.hpp
src/macro-core/macro-properties.cpp
src/macro-core/macro-properties.hpp
src/macro-core/macro-ref.cpp
@@ -252,28 +246,12 @@ target_sources(
src/utils/duration-control.hpp
src/utils/item-selection-helpers.cpp
src/utils/item-selection-helpers.hpp
src/utils/log-helper.hpp
src/utils/file-selection.cpp
src/utils/file-selection.hpp
src/utils/filter-selection.cpp
src/utils/filter-selection.hpp
src/utils/macro-list.cpp
src/utils/macro-list.hpp
src/utils/math-helpers.cpp
src/utils/math-helpers.hpp
src/utils/mouse-wheel-guard.cpp
src/utils/mouse-wheel-guard.hpp
src/utils/name-dialog.cpp
src/utils/name-dialog.hpp
src/utils/obs-dock.hpp
src/utils/obs-module-helper.cpp
src/utils/obs-module-helper.hpp
src/utils/osc-helpers.cpp
src/utils/osc-helpers.hpp
src/utils/priority-helper.cpp
src/utils/priority-helper.hpp
src/utils/process-config.cpp
src/utils/process-config.hpp
src/utils/regex-config.cpp
src/utils/regex-config.hpp
src/utils/resizing-text-edit.cpp
@@ -282,8 +260,6 @@ target_sources(
src/utils/scene-item-selection.hpp
src/utils/scene-selection.cpp
src/utils/scene-selection.hpp
src/utils/scene-switch-helpers.cpp
src/utils/scene-switch-helpers.hpp
src/utils/screenshot-helper.cpp
src/utils/screenshot-helper.hpp
src/utils/section.cpp
@@ -292,26 +268,12 @@ target_sources(
src/utils/slider-spinbox.hpp
src/utils/source-selection.cpp
src/utils/source-selection.hpp
src/utils/string-list.cpp
src/utils/string-list.hpp
src/utils/striped-frame.cpp
src/utils/striped-frame.hpp
src/utils/sync-helper.cpp
src/utils/sync-helper.hpp
src/utils/transition-selection.cpp
src/utils/transition-selection.hpp
src/utils/utility.cpp
src/utils/utility.hpp
src/utils/variable.cpp
src/utils/variable.hpp
src/utils/variable-line-edit.cpp
src/utils/variable-line-edit.hpp
src/utils/variable-number.tpp
src/utils/variable-number.hpp
src/utils/variable-spinbox.cpp
src/utils/variable-spinbox.hpp
src/utils/variable-string.cpp
src/utils/variable-string.hpp
src/utils/variable-text-edit.cpp
src/utils/variable-text-edit.hpp
src/utils/volume-control.cpp
@@ -358,8 +320,7 @@ target_include_directories(
${LIB_NAME}
PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/deps/asio/asio/include"
"${CMAKE_CURRENT_SOURCE_DIR}/deps/websocketpp"
"${CMAKE_CURRENT_SOURCE_DIR}/deps/obs-websocket/lib"
"${CMAKE_CURRENT_SOURCE_DIR}/deps/exprtk")
"${CMAKE_CURRENT_SOURCE_DIR}/deps/obs-websocket/lib")
# --- End of section ---
@@ -370,8 +331,7 @@ if(OS_WINDOWS)
target_compile_definitions(${LIB_NAME} PRIVATE UNICODE _UNICODE)
if(MSVC)
target_compile_options(${LIB_NAME} PUBLIC /MP /d2FH4- /wd4267 /wd4267
/bigobj)
target_compile_options(${LIB_NAME} PUBLIC /MP /d2FH4- /wd4267 /wd4267)
endif()
target_sources(${LIB_NAME} PRIVATE src/win/advanced-scene-switcher-win.cpp)
add_definitions(-D_WEBSOCKETPP_CPP11_STL_)
@@ -488,4 +448,3 @@ endif()
# --- End of section ---
add_subdirectory(src/macro-external)
add_subdirectory(tests)

View File

@@ -22,5 +22,9 @@
</array>
<key>LSMinimumSystemVersion</key>
<string>10.13</string>
<key>com.apple.security.automation.apple-events</key>
<true/>
<key>NSAppleEventsUsageDescription</key>
<string>Advanced scene switcher needs additional permissions to be able to run AppleScript applications</string>
</dict>
</plist>

View File

@@ -25,7 +25,7 @@ DirExistsWarning=no
Name: "english"; MessagesFile: "compiler:Default.isl"
[Files]
Source: "..\release\*"; Excludes: "*.zip"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "..\release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "..\LICENSE"; Flags: dontcopy
; NOTE: Don't use "Flags: ignoreversion" on any shared system files

View File

@@ -219,7 +219,7 @@ AdvSceneSwitcher.condition.stream.state.start="Stream läuft"
AdvSceneSwitcher.condition.stream.state.stop="Stream gestoppt"
AdvSceneSwitcher.condition.stream.state.starting="Stream wird gestartet"
AdvSceneSwitcher.condition.stream.state.stopping="Stream wird gestoppt"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.record="Aufnahme"
AdvSceneSwitcher.condition.record.state.start="Aufnahme läuft"
AdvSceneSwitcher.condition.record.state.pause="Aufnahme pausiert"
@@ -428,7 +428,7 @@ AdvSceneSwitcher.action.recording.type.unpause="Aufnahme nicht mehr pausieren"
AdvSceneSwitcher.action.recording.type.split="Aufnahme-Datei teilen"
AdvSceneSwitcher.action.recording.pause.hint="Bitte beachten, dass je nach Aufnahmeeinstellung die Aufnahme möglicherweise nicht unterbrochen werden kann"
AdvSceneSwitcher.action.recording.split.hint="Vergewissern, dass die automatische Dateiaufteilung in den OBS-Einstellungen aktiviert ist!"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="Replay Buffer"
AdvSceneSwitcher.action.replay.saveWarn="Warnung: Ein zu häufiges Speichern kann dazu führen, dass der Replay Buffer nicht gespeichert wird!"
AdvSceneSwitcher.action.replay.type.stop="Replay Buffer stoppen"
@@ -438,7 +438,7 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="Stream"
AdvSceneSwitcher.action.streaming.type.stop="Stream stoppen"
AdvSceneSwitcher.action.streaming.type.start="Stream starten"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.run="Ausführen"
AdvSceneSwitcher.action.run.arguments="Argumente:"
AdvSceneSwitcher.action.run.addArgument="Argument hinzufügen"
@@ -506,7 +506,7 @@ AdvSceneSwitcher.action.hotkey.leftMeta="Linke Meta-Taste"
AdvSceneSwitcher.action.hotkey.rightMeta="Rechte Meta-Taste"
AdvSceneSwitcher.action.hotkey.onlyOBS="Tastendruck nur an OBS senden"
AdvSceneSwitcher.action.hotkey.disabled="Globale Tastendrücke können nicht simuliert werden - die Funktionalität beschränkt sich auf das Senden von Tastendrücken an OBS!"
AdvSceneSwitcher.action.hotkey.entry="Drücke {{keys}} für {{duration}}"
AdvSceneSwitcher.action.hotkey.entry="Drücke {{keys}} für {{duration}} Millisekunden"
AdvSceneSwitcher.action.sceneOrder="Reihenfolge der Szenenelemente"
AdvSceneSwitcher.action.sceneOrder.type.moveUp="Nach oben verschieben"
AdvSceneSwitcher.action.sceneOrder.type.moveDown="Nach unten verschieben"
@@ -545,6 +545,7 @@ AdvSceneSwitcher.action.random="Zufall"
AdvSceneSwitcher.action.random.allowRepeat="Aufeinanderfolgende Ausführung desselben Makros zulassen"
AdvSceneSwitcher.action.random.entry="Zufällige Ausführung eines der folgenden Makros (pausierte Makros werden ignoriert)"
AdvSceneSwitcher.action.systray="Benachrichtigung im System-Tray"
AdvSceneSwitcher.action.systray.entry="Benachrichtigung anzeigen: {{message}}"
AdvSceneSwitcher.action.screenshot="Screenshot"
AdvSceneSwitcher.action.screenshot.save.default="Standard"
AdvSceneSwitcher.action.screenshot.save.custom="Benutzerdefiniert"
@@ -586,7 +587,7 @@ AdvSceneSwitcher.action.variable.invalidSelection="Ungültige Auswahl!"
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Aktionen wird nicht unterstützt!"
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Das Abrufen von Variablenwerten aus %1 Bedingungen wird nicht unterstützt!"
AdvSceneSwitcher.action.variable.currentSegmentValue="Aktueller Wert:"
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}"
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}"
; Transition Tab

View File

@@ -30,8 +30,6 @@ AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Enable verbose loggi
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Save window position and size"
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Show system tray notifications"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Disable UI hints"
AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailure="Display warning if plugins cannot be loaded"
AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailureMessage="<html><body>Loading of the following plugin libraries was unsuccessful, which could result in some Advanced Scene Switcher functions not being available:%1Check the OBS logs for details.<br>This message can be disabled on the General tab.</body></html>"
AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs="Hide tabs which can be represented via macros"
AdvSceneSwitcher.generalTab.matchBehavior="Match behavior"
AdvSceneSwitcher.generalTab.priority="Priority"
@@ -85,7 +83,6 @@ AdvSceneSwitcher.macroTab.defaultGroupName="Group %1"
AdvSceneSwitcher.macroTab.exists="Macro name exists already"
AdvSceneSwitcher.macroTab.groupDeleteConfirm="Are you sure you want to delete \"%1\" and all its elements?"
AdvSceneSwitcher.macroTab.deleteMultipleMacrosConfirmation="Are you sure you want to delete %1 macros?"
AdvSceneSwitcher.macroTab.deleteSingleMacroConfirmation="Are you sure you want to delete \"%1\"?"
AdvSceneSwitcher.macroTab.contextMenuAdd="Add"
AdvSceneSwitcher.macroTab.copy="Duplicate Macro"
AdvSceneSwitcher.macroTab.group="Group Selected Macros"
@@ -98,22 +95,11 @@ AdvSceneSwitcher.macroTab.maximize="Maximize"
AdvSceneSwitcher.macroTab.minimize="Minimize"
AdvSceneSwitcher.macroTab.highlightSettings="Visual settings"
AdvSceneSwitcher.macroTab.hotkeySettings="Hotkey settings"
AdvSceneSwitcher.macroTab.dockSettings="Dock settings"
AdvSceneSwitcher.macroTab.highlightExecutedMacros="Highlight recently executed macros"
AdvSceneSwitcher.macroTab.highlightTrueConditions="Highlight conditions of currently selected macro that evaluated to true recently"
AdvSceneSwitcher.macroTab.highlightPerformedActions="Highlight recently performed actions of currently selected macro"
AdvSceneSwitcher.macroTab.newMacroRegisterHotkey="Register hotkeys to control the pause state of new macros"
AdvSceneSwitcher.macroTab.currentDisableHotkeys="Register hotkeys to control the pause state of selected macro"
AdvSceneSwitcher.macroTab.currentRegisterDock="Register dock widget to control the pause state of selected macro or run it manually"
AdvSceneSwitcher.macroTab.currentDockAddRunButton="Add button to run the macro"
AdvSceneSwitcher.macroTab.currentDockAddPauseButton="Add button to pause or unpause the macro"
AdvSceneSwitcher.macroTab.currentDockButtonText.run="Run button text:"
AdvSceneSwitcher.macroTab.currentDockButtonText.pause="Pause button text:"
AdvSceneSwitcher.macroTab.currentDockButtonText.unpause="Unpause button text:"
AdvSceneSwitcher.macroDock.pause="Pause"
AdvSceneSwitcher.macroDock.unpause="Unpause"
AdvSceneSwitcher.macroDock.run="Run"
; Macro List
AdvSceneSwitcher.macroList.deleted="deleted"
@@ -164,14 +150,9 @@ AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="During transi
AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}"
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
AdvSceneSwitcher.condition.window="Window"
AdvSceneSwitcher.condition.window.entry.window="{{checkTitle}}Window title matches{{windowRegex}}{{windows}}"
AdvSceneSwitcher.condition.window.entry.fullscreen="{{fullscreen}}Window is fullscreen"
AdvSceneSwitcher.condition.window.entry.maximized="{{maximized}}Window is maximized"
AdvSceneSwitcher.condition.window.entry.focused="{{focused}}Window is focused"
AdvSceneSwitcher.condition.window.entry.focusedChange="{{windowFocusChanged}}Focus window changed"
AdvSceneSwitcher.condition.window.entry.text="{{checkText}}Window contains text{{textRegex}}{{windowText}}"
AdvSceneSwitcher.condition.window.entry.text.note="This option might not work on every text being displayed in a window.\nIf that is the case, you can consider using the Video conditions OCR check instead."
AdvSceneSwitcher.condition.window.entry.currentFocus="Current focus window:{{focusWindow}}"
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} exist and ..."
AdvSceneSwitcher.condition.window.entry.line2="... is {{fullscreen}} fullscreen {{maximized}} maximized {{focused}} focused {{windowFocusChanged}} foreground window changed"
AdvSceneSwitcher.condition.window.entry.line3="Current foreground window: {{focusWindow}}"
AdvSceneSwitcher.condition.file="File"
AdvSceneSwitcher.condition.file.type.match="matches"
AdvSceneSwitcher.condition.file.type.contentChange="content changed"
@@ -261,8 +242,7 @@ AdvSceneSwitcher.condition.stream.state.start="Stream running"
AdvSceneSwitcher.condition.stream.state.stop="Stream stopped"
AdvSceneSwitcher.condition.stream.state.starting="Stream starting"
AdvSceneSwitcher.condition.stream.state.stopping="Stream stopping"
AdvSceneSwitcher.condition.stream.state.keyFrameInterval="Keyframe interval equals"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.record="Recording"
AdvSceneSwitcher.condition.record.state.start="Recording running"
AdvSceneSwitcher.condition.record.state.pause="Recording paused"
@@ -327,7 +307,7 @@ AdvSceneSwitcher.condition.filter.type.settings="Settings match"
AdvSceneSwitcher.condition.filter.getSettings="Get current settings"
AdvSceneSwitcher.condition.filter.entry.line1="On {{sources}} {{filters}} {{conditions}}"
AdvSceneSwitcher.condition.filter.entry.line2="{{settings}}"
AdvSceneSwitcher.condition.filter.entry.line3="{{regex}}{{getSettings}}"
AdvSceneSwitcher.condition.filter.entry.line3="{{regex}} {{getSettings}}"
AdvSceneSwitcher.condition.sceneOrder="Scene item order"
AdvSceneSwitcher.condition.sceneOrder.type.above="Is above"
AdvSceneSwitcher.condition.sceneOrder.type.below="Is below"
@@ -436,16 +416,6 @@ AdvSceneSwitcher.condition.variable.type.equalsVariable="equals variable"
AdvSceneSwitcher.condition.variable.type.lessThanVariable="is less than variable"
AdvSceneSwitcher.condition.variable.type.greaterThanVariable="is greater than variable"
AdvSceneSwitcher.condition.variable.entry="{{variables}}{{conditions}}{{strValue}}{{numValue}}{{variables2}}"
AdvSceneSwitcher.condition.run="Run"
AdvSceneSwitcher.condition.run.entry="Process exits before timeout of{{timeout}} seconds"
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}Check for exit code{{exitCode}}"
AdvSceneSwitcher.condition.midi="MIDI"
AdvSceneSwitcher.condition.midi.entry="Mesasge was received from {{device}} which matches:"
AdvSceneSwitcher.condition.midi.entry.listen="Set MIDI message selection to messages incoming on selected device: {{listenButton}}"
AdvSceneSwitcher.condition.display="Display"
AdvSceneSwitcher.condition.display.type.displayName="Name of connected displays matches"
AdvSceneSwitcher.condition.display.type.displayCount="Number of connected displays is"
AdvSceneSwitcher.condition.display.entry="{{conditions}}{{displays}}{{regex}}{{displayCount}}"
; Macro Actions
AdvSceneSwitcher.action.switchScene="Switch scene"
@@ -479,11 +449,9 @@ AdvSceneSwitcher.action.recording.type.start="Start recording"
AdvSceneSwitcher.action.recording.type.pause="Pause recording"
AdvSceneSwitcher.action.recording.type.unpause="Unpause recording"
AdvSceneSwitcher.action.recording.type.split="Split recording file"
AdvSceneSwitcher.action.recording.type.changeOutputFolder="Change output folder"
AdvSceneSwitcher.action.recording.type.changeOutputFileFormat="Change filename formatting"
AdvSceneSwitcher.action.recording.pause.hint="Note that depending on your recording settings you might not be able to pause recording"
AdvSceneSwitcher.action.recording.split.hint="Make sure to enable automatic file splitting in the OBS settings first!"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="Replay buffer"
AdvSceneSwitcher.action.replay.saveWarn="Warning: Saving too frequently might result in the replay buffer not actually being saved!"
AdvSceneSwitcher.action.replay.type.stop="Stop replay buffer"
@@ -493,9 +461,13 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="Streaming"
AdvSceneSwitcher.action.streaming.type.stop="Stop streaming"
AdvSceneSwitcher.action.streaming.type.start="Start streaming"
AdvSceneSwitcher.action.streaming.type.keyFrameInterval="Set keyframe interval"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.run="Run"
AdvSceneSwitcher.action.run.arguments="Arguments:"
AdvSceneSwitcher.action.run.addArgument="Add argument"
AdvSceneSwitcher.action.run.addArgumentDescription="Add new argument:"
AdvSceneSwitcher.action.run.entry="Run {{filePath}}"
AdvSceneSwitcher.action.run.entry.workingDirectory="Working directory:{{workingDirectory}}"
AdvSceneSwitcher.action.sceneVisibility="Scene item visibility"
AdvSceneSwitcher.action.sceneVisibility.type.show="Show"
AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
@@ -541,8 +513,6 @@ AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher
AdvSceneSwitcher.action.pluginState.type.noMatch="Change the no-match behaviour:"
AdvSceneSwitcher.action.pluginState.type.import="Import settings from"
AdvSceneSwitcher.action.pluginState.importWarning="Note: Action will be ignored while settings window is opened."
AdvSceneSwitcher.action.pluginState.type.terminate="Shut down OBS"
AdvSceneSwitcher.action.pluginState.terminateConfirm="OBS will be shut down automatically in 10 seconds!\nDo you want to continue shutting down OBS?"
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
AdvSceneSwitcher.action.virtualCamera="Virtual camera"
AdvSceneSwitcher.action.virtualCamera.type.stop="Stop virtual camera"
@@ -559,7 +529,7 @@ AdvSceneSwitcher.action.hotkey.leftMeta="Left Meta"
AdvSceneSwitcher.action.hotkey.rightMeta="Right Meta"
AdvSceneSwitcher.action.hotkey.onlyOBS="Send keypress only to OBS"
AdvSceneSwitcher.action.hotkey.disabled="Cannot simulate global key presses - functionality limited to sending key press to OBS!"
AdvSceneSwitcher.action.hotkey.entry="Press {{keys}} for {{duration}}"
AdvSceneSwitcher.action.hotkey.entry="Press {{keys}} for {{duration}} milliseconds"
AdvSceneSwitcher.action.sceneOrder="Scene item order"
AdvSceneSwitcher.action.sceneOrder.type.moveUp="Move up"
AdvSceneSwitcher.action.sceneOrder.type.moveDown="Move down"
@@ -598,10 +568,7 @@ AdvSceneSwitcher.action.random="Random"
AdvSceneSwitcher.action.random.allowRepeat="Allow consecutive execution of the same macro"
AdvSceneSwitcher.action.random.entry="Randomly run any of the following macros (paused macros are ignored)"
AdvSceneSwitcher.action.systray="System tray notification"
AdvSceneSwitcher.action.systray.title="Title:"
AdvSceneSwitcher.action.systray.message="Message:"
AdvSceneSwitcher.action.systray.icon="Icon:"
AdvSceneSwitcher.action.systray.iconHint="Leave blank to use the default icon"
AdvSceneSwitcher.action.systray.entry="Show notification: {{message}}"
AdvSceneSwitcher.action.screenshot="Screenshot"
AdvSceneSwitcher.action.screenshot.save.default="Default"
AdvSceneSwitcher.action.screenshot.save.custom="Custom"
@@ -627,9 +594,6 @@ AdvSceneSwitcher.action.websocket.type.event="Event"
AdvSceneSwitcher.action.websocket.entry.request="Send scene switcher {{type}} via {{connection}}"
AdvSceneSwitcher.action.websocket.entry.event="Send scene switcher {{type}} to connected clients"
AdvSceneSwitcher.action.http="Http"
AdvSceneSwitcher.action.http.setHeaders="Set headers"
AdvSceneSwitcher.action.http.headers="Headers:"
AdvSceneSwitcher.action.http.addHeader="Add header"
AdvSceneSwitcher.action.http.type.get="GET"
AdvSceneSwitcher.action.http.type.post="POST"
AdvSceneSwitcher.action.http.entry.line1="Send {{method}} to {{url}}"
@@ -644,21 +608,15 @@ AdvSceneSwitcher.action.variable.type.setActionValue="Set to action value"
AdvSceneSwitcher.action.variable.type.setConditionValue="Set to condition value"
AdvSceneSwitcher.action.variable.type.roundToInt="Round to nearest integer"
AdvSceneSwitcher.action.variable.type.subString="Set to substring of current value"
AdvSceneSwitcher.action.variable.type.findAndReplace="Find and replace in current value"
AdvSceneSwitcher.action.variable.type.mathExpression="Mathematical expression"
AdvSceneSwitcher.action.variable.mathExpression.example="( 1 + 2 * 3 ) / 4"
AdvSceneSwitcher.action.variable.findAndReplace.find="Text to find"
AdvSceneSwitcher.action.variable.findAndReplace.replace="Text to replace with"
AdvSceneSwitcher.action.variable.subString.begin="Beginning"
AdvSceneSwitcher.action.variable.subString.all="All"
AdvSceneSwitcher.action.variable.invalidSelection="Invalid selection!"
AdvSceneSwitcher.action.variable.actionNoVariableSupport="Getting variable values from %1 actions is not supported!"
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="Getting variable values from %1 conditions is not supported!"
AdvSceneSwitcher.action.variable.currentSegmentValue="Current value:"
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}"
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}"
AdvSceneSwitcher.action.variable.entry.substringIndex="Substring start:{{subStringStart}} Substring size:{{subStringSize}}"
AdvSceneSwitcher.action.variable.entry.substringRegex="Assign value of{{regexMatchIdx}}match using regular expression:"
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{replaceStr}}"
AdvSceneSwitcher.action.projector="Projector"
AdvSceneSwitcher.action.projector.type.source="Source"
AdvSceneSwitcher.action.projector.type.scene="Scene"
@@ -670,10 +628,7 @@ AdvSceneSwitcher.action.projector.windowed="Windowed"
AdvSceneSwitcher.action.projector.fullscreen="Fullscreen"
AdvSceneSwitcher.action.projector.entry="Open{{windowTypes}}projector of{{types}}{{scenes}}{{sources}}"
AdvSceneSwitcher.action.projector.entry.monitor="on{{monitors}}"
AdvSceneSwitcher.action.midi="MIDI"
AdvSceneSwitcher.action.midi.entry="Send message to {{device}}:"
AdvSceneSwitcher.action.midi.entry.listen="Set MIDI message selection to messages incoming on {{listenDevices}}: {{listenButton}}"
AdvSceneSwitcher.action.osc="Open Sound Control"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="Transition"
@@ -953,7 +908,6 @@ AdvSceneSwitcher.connection.password="Password:"
AdvSceneSwitcher.connection.reconnect="Reconnect automatically:"
AdvSceneSwitcher.connection.reconnectDelay="Automatically reconnect after:"
AdvSceneSwitcher.connection.connectOnStart="Connect on startup:"
AdvSceneSwitcher.connection.useOBSWebsocketProtocol="<html><head/><body><p>Use the obs-websocket <a href=\"https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md\"><span style=\" text-decoration: underline; color:#268bd2;\">protocol</span></a></p></body></html>"
AdvSceneSwitcher.connection.test="Test connection"
AdvSceneSwitcher.connection.status.disconnected="Disconnected"
AdvSceneSwitcher.connection.status.connecting="Connecting"
@@ -967,68 +921,6 @@ AdvSceneSwitcher.regex.dotMatchNewline=". matches newlines"
AdvSceneSwitcher.regex.multiLine="^ and $ match start/end of line"
AdvSceneSwitcher.regex.extendedPattern="Enable Qt's ExtendedPatternSyntax"
AdvSceneSwitcher.process.showAdvanced="Show advanced settings"
AdvSceneSwitcher.process.arguments="Arguments:"
AdvSceneSwitcher.process.addArgument="Add argument"
AdvSceneSwitcher.process.addArgumentDescription="Add new argument:"
AdvSceneSwitcher.process.entry="Run{{filePath}}{{advancedSettings}}"
AdvSceneSwitcher.process.entry.workingDirectory="Working directory:{{workingDirectory}}"
AdvSceneSwitcher.math.expressionFail="Failed evaluate expression"
AdvSceneSwitcher.midi.deviceNamePattern="[Port #%1] %2"
AdvSceneSwitcher.midi.message.type="Type:"
AdvSceneSwitcher.midi.message.type.optional="Any"
AdvSceneSwitcher.midi.message.type.invalid="Invalid"
AdvSceneSwitcher.midi.message.type.noteOff="Note Off"
AdvSceneSwitcher.midi.message.type.noteOn="Note On"
AdvSceneSwitcher.midi.message.type.polyphonicPressure="Polyphonic Pressure"
AdvSceneSwitcher.midi.message.type.controlChange="Control Change"
AdvSceneSwitcher.midi.message.type.programChange="Program Change"
AdvSceneSwitcher.midi.message.type.channelAftertouch="Channel Aftertouch"
AdvSceneSwitcher.midi.message.type.pitchBend="Pitch Bend"
AdvSceneSwitcher.midi.message.type.systemExclusive="System Exclusive"
AdvSceneSwitcher.midi.message.type.timeCode="Time Code"
AdvSceneSwitcher.midi.message.type.songPositionPointer="Song Position Pointer"
AdvSceneSwitcher.midi.message.type.songSelect="Song Select"
AdvSceneSwitcher.midi.message.type.reserved1="Reserved (1)"
AdvSceneSwitcher.midi.message.type.reserved2="Reserved (2)"
AdvSceneSwitcher.midi.message.type.tuneRequest="Tune Request"
AdvSceneSwitcher.midi.message.type.endOfSystemExclusive="End of System Exclusive"
AdvSceneSwitcher.midi.message.type.timeClock="Time Clock"
AdvSceneSwitcher.midi.message.type.reserved3="Reserved (3)"
AdvSceneSwitcher.midi.message.type.startFile="Start File"
AdvSceneSwitcher.midi.message.type.continueFile="Continue File"
AdvSceneSwitcher.midi.message.type.stopFile="Stop File"
AdvSceneSwitcher.midi.message.type.reserved4="Reserved (4)"
AdvSceneSwitcher.midi.message.type.activeSensing="Active Sensing"
AdvSceneSwitcher.midi.message.type.systemReset="System Reset"
AdvSceneSwitcher.midi.message.type.unknown="Unknown"
AdvSceneSwitcher.midi.message.channel="Channel:"
AdvSceneSwitcher.midi.message.note="Note / Value(1):"
AdvSceneSwitcher.midi.message.value="Value(2):"
AdvSceneSwitcher.midi.message.placeholder="Any"
AdvSceneSwitcher.midi.resetDevices="Reconnect all MIDI devices"
AdvSceneSwitcher.midi.startListen="Start listening"
AdvSceneSwitcher.midi.stopListen="Stop listening"
AdvSceneSwitcher.midi.startListenFail="Device is busy!\nSomething else is already listening!"
AdvSceneSwitcher.midi.deviceOpenFail="Failed to initialize MIDI device!"
AdvSceneSwitcher.osc.network="Network"
AdvSceneSwitcher.osc.network.protocol="Protocol:"
AdvSceneSwitcher.osc.network.address="Address:"
AdvSceneSwitcher.osc.network.port="Port:"
AdvSceneSwitcher.osc.message="Message"
AdvSceneSwitcher.osc.message.type.none="None"
AdvSceneSwitcher.osc.message.type.float="Float"
AdvSceneSwitcher.osc.message.type.int="Integer"
AdvSceneSwitcher.osc.message.type.string="String"
AdvSceneSwitcher.osc.message.type.binaryBlob="Binary blob"
AdvSceneSwitcher.osc.message.type.true="True"
AdvSceneSwitcher.osc.message.type.false="False"
AdvSceneSwitcher.osc.message.type.infinity="Infinitum"
AdvSceneSwitcher.osc.message.type.null="Nil"
AdvSceneSwitcher.selectScene="--select scene--"
AdvSceneSwitcher.selectPreviousScene="Previous Scene"
AdvSceneSwitcher.selectCurrentScene="Current Scene"

View File

@@ -179,7 +179,7 @@ AdvSceneSwitcher.condition.stream.state.start="Transmisión en ejecución"
AdvSceneSwitcher.condition.stream.state.stop="Transmisión detenida"
AdvSceneSwitcher.condition.stream.state.starting="Inicio de transmisión"
AdvSceneSwitcher.condition.stream.state.stopping="Detener transmisión"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.record="Grabación"
AdvSceneSwitcher.condition.record.state.start="Grabación en ejecución"
AdvSceneSwitcher.condition.record.state.pause="Grabación en pausa"
@@ -350,7 +350,7 @@ AdvSceneSwitcher.action.recording.type.start="Iniciar grabación"
AdvSceneSwitcher.action.recording.type.pause="Pausar grabación"
AdvSceneSwitcher.action.recording.type.unpause="Reanudar grabación"
AdvSceneSwitcher.action.recording.pause.hint="Tenga en cuenta que, dependiendo de la configuración de grabación, es posible que no pueda pausar la grabación"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="Búfer de reproducción"
AdvSceneSwitcher.action.replay.saveWarn="Advertencia: ¡Guardar con demasiada frecuencia puede hacer que el búfer de reproducción no se guarde realmente!"
AdvSceneSwitcher.action.replay.type.stop="Detener el búfer de reproducción"
@@ -360,7 +360,7 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="Transmisión"
AdvSceneSwitcher.action.streaming.type.stop="Detener transmisión"
AdvSceneSwitcher.action.streaming.type.start="Iniciar transmisión"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.run="Ejecutar"
AdvSceneSwitcher.action.run.arguments="Argumentos:"
AdvSceneSwitcher.action.run.addArgument="Agregar argumento"
@@ -422,7 +422,7 @@ AdvSceneSwitcher.action.hotkey.leftMeta="Meta izquierda"
AdvSceneSwitcher.action.hotkey.rightMeta="Meta derecho"
AdvSceneSwitcher.action.hotkey.onlyOBS="Enviar pulsación de tecla solo a OBS"
AdvSceneSwitcher.action.hotkey.disabled="No se puede simular la pulsación de teclas: ¡funcionalidad desactivada!"
AdvSceneSwitcher.action.hotkey.entry="Presione {{keys}} durante {{duration}}"
AdvSceneSwitcher.action.hotkey.entry="Presione {{keys}} durante {{duration}} milisegundos"
AdvSceneSwitcher.action.sceneOrder="Orden de elementos de escena"
AdvSceneSwitcher.action.sceneOrder.type.moveUp="Mover hacia arriba"
AdvSceneSwitcher.action.sceneOrder.type.moveDown="Mover hacia abajo"
@@ -460,6 +460,7 @@ AdvSceneSwitcher.action.timer.entry="{{timerAction}} temporizadores en {{macros}
AdvSceneSwitcher.action.random="Aleatorio"
AdvSceneSwitcher.action.random.entry="Ejecute aleatoriamente cualquiera de las siguientes macros (las macros en pausa se ignoran)"
AdvSceneSwitcher.action.systray="Notificación de la bandeja del sistema"
AdvSceneSwitcher.action.systray.entry="Mostrar notificación: {{message}}"
AdvSceneSwitcher.action.screenshot="Captura de pantalla"
AdvSceneSwitcher.action.screenshot.mainOutput="Salida principal de OBS"
AdvSceneSwitcher.action.profile="Perfil"

View File

@@ -135,7 +135,7 @@ 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}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="Буфер воспроизведения"
AdvSceneSwitcher.action.replay.type.stop="Остановить буфер воспроизведения"
AdvSceneSwitcher.action.replay.type.start="Начать воспроизведение буфера"
@@ -144,7 +144,7 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="Потоковое вещание"
AdvSceneSwitcher.action.streaming.type.stop="Остановить потоковое вещание"
AdvSceneSwitcher.action.streaming.type.start="Начать потоковое вещание"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.run="Запустить"

View File

@@ -156,7 +156,7 @@ AdvSceneSwitcher.condition.stream.state.start="Yayın çalışıyor"
AdvSceneSwitcher.condition.stream.state.stop="Yayın durdu"
AdvSceneSwitcher.condition.stream.state.starting="Yayın başlıyor"
AdvSceneSwitcher.condition.stream.state.stopping="Yayın duruyor"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.record="Kayıt"
AdvSceneSwitcher.condition.record.state.start="Kayıt Çalışıyor"
AdvSceneSwitcher.condition.record.state.pause="Kayıt durakladı"
@@ -281,7 +281,7 @@ AdvSceneSwitcher.action.recording.type.start="Kayıt Başlat"
AdvSceneSwitcher.action.recording.type.pause="Kayıt Duraklat"
AdvSceneSwitcher.action.recording.type.unpause="Kayıt Duraklatma"
AdvSceneSwitcher.action.recording.pause.hint="Kayıt ayarlarınıza bağlı olarak kaydı duraklatamayabileceğinizi unutmayın."
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="Tekrar arabelleği"
AdvSceneSwitcher.action.replay.type.stop="Tekrar arabelleğini durdur"
AdvSceneSwitcher.action.replay.type.start="Tekrar arabelleğini başlat"
@@ -290,7 +290,7 @@ AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="Yayın"
AdvSceneSwitcher.action.streaming.type.stop="Yayın durdur"
AdvSceneSwitcher.action.streaming.type.start="Yayın başlat"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.run="Çalıştır"
AdvSceneSwitcher.action.run.arguments="Argümanlar:"
AdvSceneSwitcher.action.run.addArgument="Argüman ekle"
@@ -350,7 +350,7 @@ AdvSceneSwitcher.action.hotkey.leftMeta="Sol Meta"
AdvSceneSwitcher.action.hotkey.rightMeta="Sağ Meta"
AdvSceneSwitcher.action.hotkey.onlyOBS="Tuşa basımı yalnızca OBS'ye gönder"
AdvSceneSwitcher.action.hotkey.disabled="Tuşa basma simülasyonu yapılamıyor - işlevsellik devre dışı!"
AdvSceneSwitcher.action.hotkey.entry="Bas {{keys}} uygun {{duration}}"
AdvSceneSwitcher.action.hotkey.entry="Bas {{keys}} uygun {{duration}} millisaniye"
AdvSceneSwitcher.action.sceneOrder="Sahne öğesi sırası"
AdvSceneSwitcher.action.sceneOrder.type.moveUp="Yukarı taşı"
AdvSceneSwitcher.action.sceneOrder.type.moveDown="Aşağı indir"
@@ -377,6 +377,7 @@ AdvSceneSwitcher.action.timer.entry="{{timerAction}} zamanlayıcılar açık {{m
AdvSceneSwitcher.action.random="Rastgele"
AdvSceneSwitcher.action.random.entry="Aşağıdaki makrolardan herhangi birini rastgele çalıştırın (duraklatılmış makrolar yoksayılır)"
AdvSceneSwitcher.action.systray="Sistem tepsisi bildirimi"
AdvSceneSwitcher.action.systray.entry="Bildirimleri göster: {{message}}"
AdvSceneSwitcher.action.screenshot="Ekran görüntüsü"
AdvSceneSwitcher.action.screenshot.mainOutput="OBS'nin ana çıkışı"
AdvSceneSwitcher.action.profile="Profil"

View File

@@ -4,7 +4,7 @@ AdvSceneSwitcher.windowTitle="高级场景切换器"
; General Tab
AdvSceneSwitcher.generalTab.title="通用"
AdvSceneSwitcher.generalTab.status="状态"
AdvSceneSwitcher.generalTab.status.hotkeytips="快捷键可在OBS设置中设置<br><br>汉化作者:[ 从不咕咕的阿坤 ] - 全平台统一名 - 如对你有所帮助,劳烦点个关注!"
AdvSceneSwitcher.generalTab.status.hotkeytips="快捷键可在OBS设置中设置"
AdvSceneSwitcher.generalTab.status.currentStatus="当前状态:"
AdvSceneSwitcher.generalTab.status.onStartup="在OBS启动时"
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="按照最后运行时的状态"
@@ -24,14 +24,11 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="时间精度最
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="不切换"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="切换到随机场景列表中任意随机场景"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="切换到"
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="执行完操作后,跳过执行操作,为"
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="在此期间,可能的匹配项将被忽略!"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="详细日志输出"
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="保存窗口位置和大小"
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="显示系统托盘通知"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="禁用UI提示"
AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailure="如果无法加载插件显示警告"
AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailureMessage="<html><body>加载以下插件库失败,这可能导致某些高级场景切换器功能不可用:%1 查看 OBS 日志了解详细信息.<br>可以在“常规”选项卡上禁用此消息.</body></html>"
AdvSceneSwitcher.generalTab.generalBehavior.hideLegacyTabs="隐藏可通过宏操作的分组栏"
AdvSceneSwitcher.generalTab.matchBehavior="场景匹配设置"
AdvSceneSwitcher.generalTab.priority="优先级"
@@ -81,39 +78,17 @@ AdvSceneSwitcher.macroTab.runFail="运行 \"%1\" 失败!\n其中一个操作失
AdvSceneSwitcher.macroTab.runInParallel="与其他宏同时运行宏"
AdvSceneSwitcher.macroTab.onChange="仅在条件更改时执行操作"
AdvSceneSwitcher.macroTab.defaultname="宏 %1"
AdvSceneSwitcher.macroTab.defaultGroupName="组 %1"
AdvSceneSwitcher.macroTab.exists="宏名称已存在"
AdvSceneSwitcher.macroTab.groupDeleteConfirm="您确定要删除 \"%1\"及其所有元素吗?"
AdvSceneSwitcher.macroTab.deleteMultipleMacrosConfirmation="您确定要删除 %1 宏吗?"
AdvSceneSwitcher.macroTab.deleteSingleMacroConfirmation="你确定你要删除 \"%1\"?"
AdvSceneSwitcher.macroTab.contextMenuAdd="增加"
AdvSceneSwitcher.macroTab.copy="创建副本"
AdvSceneSwitcher.macroTab.group="对选定的宏进行分组"
AdvSceneSwitcher.macroTab.ungroup="解除选定的组的分组"
AdvSceneSwitcher.macroTab.rename="重命名"
AdvSceneSwitcher.macroTab.remove="删除"
AdvSceneSwitcher.macroTab.expandAll="全部展开"
AdvSceneSwitcher.macroTab.collapseAll="全部收回"
AdvSceneSwitcher.macroTab.maximize="最大化"
AdvSceneSwitcher.macroTab.minimize="最小化"
AdvSceneSwitcher.macroTab.highlightSettings="显示 设置"
AdvSceneSwitcher.macroTab.hotkeySettings="热键 设置"
AdvSceneSwitcher.macroTab.dockSettings="停靠 设置"
AdvSceneSwitcher.macroTab.highlightExecutedMacros="突出显示最近执行的宏"
AdvSceneSwitcher.macroTab.highlightTrueConditions="突出显示最近运算为 真 的当前选定宏的条件"
AdvSceneSwitcher.macroTab.highlightPerformedActions="突出显示当前选定宏的最近执行的操作"
AdvSceneSwitcher.macroTab.newMacroRegisterHotkey="使用快捷键控制新增宏的暂停状态"
AdvSceneSwitcher.macroTab.currentDisableHotkeys="使用快捷键控制所选宏的暂停状态"
AdvSceneSwitcher.macroTab.currentRegisterDock="注册停靠小部件以控制所选宏的暂停状态或手动运行它"
AdvSceneSwitcher.macroTab.currentDockAddRunButton="添加按钮以运行宏"
AdvSceneSwitcher.macroTab.currentDockAddPauseButton="添加按钮以暂停或取消暂停宏"
AdvSceneSwitcher.macroTab.currentDockButtonText.run="运行按钮文本:"
AdvSceneSwitcher.macroTab.currentDockButtonText.pause="暂停按钮文本:"
AdvSceneSwitcher.macroTab.currentDockButtonText.unpause="取消暂停按钮文本:"
AdvSceneSwitcher.macroDock.pause="暂停"
AdvSceneSwitcher.macroDock.unpause="取消暂停"
AdvSceneSwitcher.macroDock.run="运行"
; Macro List
AdvSceneSwitcher.macroList.deleted="删除"
@@ -137,17 +112,10 @@ AdvSceneSwitcher.condition.audio.state.mute="静音"
AdvSceneSwitcher.condition.audio.state.unmute="取消静音"
AdvSceneSwitcher.condition.audio.type.output="输出音频"
AdvSceneSwitcher.condition.audio.type.volume="配置音量级别"
AdvSceneSwitcher.condition.audio.type.syncOffset="同步偏移"
AdvSceneSwitcher.condition.audio.type.monitor="音频监控"
AdvSceneSwitcher.condition.audio.type.balance="音频平衡"
AdvSceneSwitcher.condition.audio.entry="{{checkType}} 的 {{audioSources}} 是 {{condition}}{{volume}}{{syncOffset}}{{monitorTypes}}"
AdvSceneSwitcher.condition.cursor="屏幕区域"
AdvSceneSwitcher.condition.cursor.type.region="当前位置"
AdvSceneSwitcher.condition.cursor.type.moving="正在移动"
AdvSceneSwitcher.condition.cursor.type.click="点击"
AdvSceneSwitcher.condition.cursor.button.left="鼠标左键"
AdvSceneSwitcher.condition.cursor.button.middle="鼠标中键"
AdvSceneSwitcher.condition.cursor.button.right="鼠标右键"
AdvSceneSwitcher.condition.cursor.showFrame="显示帧率"
AdvSceneSwitcher.condition.cursor.hideFrame="隐藏帧率"
AdvSceneSwitcher.condition.cursor.entry.line1="鼠标 处于{{conditions}}{{buttons}}{{minX}}{{minY}}{{maxX}}{{maxY}}{{toggleFrameButton}}"
@@ -157,47 +125,36 @@ AdvSceneSwitcher.condition.scene.type.current="当前场景是"
AdvSceneSwitcher.condition.scene.type.previous="上一个场景是"
AdvSceneSwitcher.condition.scene.type.changed="场景改变了"
AdvSceneSwitcher.condition.scene.type.notChanged="场景没有改变"
AdvSceneSwitcher.condition.scene.type.currentPattern="当前场景匹配"
AdvSceneSwitcher.condition.scene.type.previousPattern="上一个场景匹配"
AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="在转场过程中检查转场源场景"
AdvSceneSwitcher.condition.scene.previousSceneTransitionBehaviour="在转场过程中检查转场源场景"
AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}}{{scenes}}{{pattern}}"
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
AdvSceneSwitcher.condition.window="窗口"
AdvSceneSwitcher.condition.window.entry.window="{{checkTitle}}窗口标题匹配{{windowRegex}}{{windows}}"
AdvSceneSwitcher.condition.window.entry.fullscreen="{{fullscreen}}窗口为全屏"
AdvSceneSwitcher.condition.window.entry.maximized="{{maximized}}窗口为最大化"
AdvSceneSwitcher.condition.window.entry.focused="{{focused}}窗口为焦点"
AdvSceneSwitcher.condition.window.entry.focusedChange="{{windowFocusChanged}}焦点窗口被改变"
AdvSceneSwitcher.condition.window.entry.text="{{checkText}}窗口包含文本{{textRegex}}{{windowText}}"
AdvSceneSwitcher.condition.window.entry.text.note="此选项可能不会对窗口中显示的每个文本起作用。\n如果是这种情况您可以考虑使用视频条件OCR检查来代替。"
AdvSceneSwitcher.condition.window.entry.currentFocus="当前焦点窗口:{{focusWindow}}"
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} 存在..."
AdvSceneSwitcher.condition.window.entry.line2="... 并且是 {{fullscreen}} 全屏 {{maximized}} 最大化 {{focused}} 获得焦点 {{windowFocusChanged}} 焦点窗口已更改"
AdvSceneSwitcher.condition.window.entry.line3="当前焦点窗口: {{focusWindow}}"
AdvSceneSwitcher.condition.file="文件"
AdvSceneSwitcher.condition.file.type.match="内容完全匹配"
AdvSceneSwitcher.condition.file.type.contentChange="内容已更改"
AdvSceneSwitcher.condition.file.type.dateChange="修改日期已更改"
AdvSceneSwitcher.condition.file.remote="远程文件"
AdvSceneSwitcher.condition.file.local="本地文件"
AdvSceneSwitcher.condition.file.entry.line1="{{fileType}}{{filePath}}{{conditions}}"
AdvSceneSwitcher.condition.file.entry.line1="文件内容来自{{fileType}}{{filePath}}{{conditions}}"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
AdvSceneSwitcher.condition.media="媒体"
AdvSceneSwitcher.condition.media.source="源"
AdvSceneSwitcher.condition.media.anyOnScene="任何媒体源"
AdvSceneSwitcher.condition.media.allOnScene="所有媒体源"
AdvSceneSwitcher.condition.media.anyOnScene="任何媒体来源"
AdvSceneSwitcher.condition.media.allOnScene="所有媒体源"
AdvSceneSwitcher.condition.media.matchOnChange="仅在更改时匹配(注意:此选项将在未来版本中删除-请改用时间限制)"
AdvSceneSwitcher.condition.media.inconsistencyInfo="不幸的是并非所有媒体源类型的行为都相同例如媒体源与VLC视频源“停止”状态。\n所以请尝试适合您的设置"
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}} 的状态是 {{states}}{{timeRestrictions}}{{time}}"
AdvSceneSwitcher.condition.media.entry="{{sourceTypes}}{{mediaSources}}{{scenes}}的状态是{{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.hasChanged="改变"
AdvSceneSwitcher.condition.video.condition.hasNotChanged="没有改变"
AdvSceneSwitcher.condition.video.condition.noImage="没有输出"
AdvSceneSwitcher.condition.video.condition.pattern="匹配模式"
AdvSceneSwitcher.condition.video.condition.object="包含对象"
AdvSceneSwitcher.condition.video.condition.brightness="亮度"
AdvSceneSwitcher.condition.video.condition.ocr="包含文本"
AdvSceneSwitcher.condition.video.askFileAction="是否要使用现有文件或创建当前选定源的屏幕截图?"
AdvSceneSwitcher.condition.video.askFileAction.file="使用现有文件"
AdvSceneSwitcher.condition.video.askFileAction.screenshot="创建屏幕截图"
@@ -207,49 +164,28 @@ AdvSceneSwitcher.condition.video.usePatternForChangedCheck="使用模式匹配"
AdvSceneSwitcher.condition.video.usePatternForChangedCheck.tooltip="这将允许您控制图像必须更改多少才能使条件为真."
AdvSceneSwitcher.condition.video.patternThreshold="阈值: "
AdvSceneSwitcher.condition.video.patternThresholdDescription="较高的阈值意味着模式需要更紧密地匹配视频源."
AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask="使用alpha通道作为模式的遮罩."
AdvSceneSwitcher.condition.video.patternMatchMode="使用模式匹配方式 {{patternMatchingModes}}"
AdvSceneSwitcher.condition.video.patternMatchMode.crossCorrelation="交叉相关"
AdvSceneSwitcher.condition.video.patternMatchMode.correlationCoefficient="相关系数"
AdvSceneSwitcher.condition.video.patternMatchMode.squaredDifference="平方差"
AdvSceneSwitcher.condition.video.patternMatchMode.tip="使用的最佳方法取决于具体问题和所涉及图像的特性。\n在实践中通常需要使用不同的方法和参数进行实验以找到对特定用例的最佳匹配。"
AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask="使用alpha通道作为图案的遮罩."
AdvSceneSwitcher.condition.video.brightnessThreshold="平均亮度:"
AdvSceneSwitcher.condition.video.brightnessThresholdDescription="高的值表示明亮的图像,低的值表示较暗的图像。"
AdvSceneSwitcher.condition.video.brightnessThresholdDescription="高的值表示图像较亮,较低的值表示图像较暗。"
AdvSceneSwitcher.condition.video.currentBrightness="当前平均亮度: %1"
AdvSceneSwitcher.condition.video.objectScaleThreshold="模型比例: "
AdvSceneSwitcher.condition.video.objectScaleThresholdDescription="较低的模比例会产生更多的匹配,但导致CPU负载更高."
AdvSceneSwitcher.condition.video.objectScaleThresholdDescription="较低的模比例将导致更多的匹配,但导致更高的CPU负载."
AdvSceneSwitcher.condition.video.minNeighborDescription="较高的“最小区域”值将导致较少但质量较高的匹配."
AdvSceneSwitcher.condition.video.showMatch="显示模式"
AdvSceneSwitcher.condition.video.showMatch.loading="检查是否匹配"
AdvSceneSwitcher.condition.video.showMatch.loading="Checking for match"
AdvSceneSwitcher.condition.video.screenshotFail="无法获取源的屏幕截图!"
AdvSceneSwitcher.condition.video.screenshotEmpty="屏幕截图为空 - 源是否可见?"
AdvSceneSwitcher.condition.video.screenshotEmpty="Screenshot is empty - Is the source visible?"
AdvSceneSwitcher.condition.video.patternMatchFail="没有找到模式!"
AdvSceneSwitcher.condition.video.patternMatchSuccess="模式以红色突出显示"
AdvSceneSwitcher.condition.video.patternMatchSuccess="Pattern is highlighted in red"
AdvSceneSwitcher.condition.video.objectMatchFail="找不到对象!"
AdvSceneSwitcher.condition.video.objectMatchSuccess="对象以红色突出显示"
AdvSceneSwitcher.condition.video.ocrMatchSuccess="检测到的文本:\n\n%1"
AdvSceneSwitcher.condition.video.objectMatchSuccess="Object is highlighted in red"
AdvSceneSwitcher.condition.video.modelLoadFail="无法加载模型数据!"
AdvSceneSwitcher.condition.video.selectColor="选择颜色"
AdvSceneSwitcher.condition.video.ocrMode.singleColumn="单列可变大小的文本"
AdvSceneSwitcher.condition.video.ocrMode.singleBlockVertText="垂直对齐的单个统一文本块"
AdvSceneSwitcher.condition.video.ocrMode.singleBlock="单个统一的文本块"
AdvSceneSwitcher.condition.video.ocrMode.singleLine="单个文本行"
AdvSceneSwitcher.condition.video.ocrMode.singleWord="单词"
AdvSceneSwitcher.condition.video.ocrMode.circleWord="圆圈中的单个单词"
AdvSceneSwitcher.condition.video.ocrMode.singleChar="单个字符"
AdvSceneSwitcher.condition.video.ocrMode.sparseText="不按特定顺序查找文本"
AdvSceneSwitcher.condition.video.ocrMode.sparseTextOSD="不按特定顺序查找文本OSD"
AdvSceneSwitcher.condition.video.type.main="OBS的主输出"
AdvSceneSwitcher.condition.video.type.source="源"
AdvSceneSwitcher.condition.video.type.scene="场景"
AdvSceneSwitcher.condition.video.entry="{{videoInputTypes}}{{sources}}{{scenes}}{{condition}}{{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="模型数据 (haar级联分类器): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="最小区域: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}每隔一段时间检查一次,来减少CPU负载 {{throttleCount}} 毫秒"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}通过只执行每一次检查来减少CPU负载 {{throttleCount}} 毫秒"
AdvSceneSwitcher.condition.video.entry.checkAreaEnable="仅在区域内执行检查"
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.entry.orcColorPick="检查文本颜色:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="检查文本类型:{{textType}}"
AdvSceneSwitcher.condition.video.minSize="最小尺寸:"
AdvSceneSwitcher.condition.video.maxSize="最大尺寸:"
AdvSceneSwitcher.condition.video.selectArea="选择区域"
@@ -261,25 +197,21 @@ AdvSceneSwitcher.condition.stream.state.start="推流启动"
AdvSceneSwitcher.condition.stream.state.stop="推流停止"
AdvSceneSwitcher.condition.stream.state.starting="推流启动中"
AdvSceneSwitcher.condition.stream.state.stopping="推流停止中"
AdvSceneSwitcher.condition.stream.state.keyFrameInterval="关键帧间隔等于"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}{{keyFrameInterval}}"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.record="录制"
AdvSceneSwitcher.condition.record.state.start="录制运行中"
AdvSceneSwitcher.condition.record.state.pause="录制暂停"
AdvSceneSwitcher.condition.record.state.stop="录制停止"
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
AdvSceneSwitcher.condition.process="进程"
AdvSceneSwitcher.condition.process.entry="{{processes}} 是正在运行 {{focused}} 且是获得焦点"
AdvSceneSwitcher.condition.process.entry="{{processes}} 是正在运行 {{focused}} 且是获得焦点"
AdvSceneSwitcher.condition.process.entry.focus="当前焦点进程: {{focusProcess}}"
AdvSceneSwitcher.condition.idle="闲置检测"
AdvSceneSwitcher.condition.idle.entry="没有键盘或鼠标输入{{duration}}"
AdvSceneSwitcher.condition.pluginState="插件状态"
AdvSceneSwitcher.condition.pluginState.state.start="插件已启动"
AdvSceneSwitcher.condition.pluginState.state.restart="插件已重新启动"
AdvSceneSwitcher.condition.pluginState.state.running="插件正在运行"
AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="在此时间间隔内触发了自动场景更改"
AdvSceneSwitcher.condition.pluginState.state.running="高级场景切换程序正在运行"
AdvSceneSwitcher.condition.pluginState.state.shutdown="OBS正在关闭"
AdvSceneSwitcher.condition.pluginState.state.sceneCollection="场景集合已加载"
AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="场景被上一个宏改变"
AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
AdvSceneSwitcher.condition.timer="计时器"
AdvSceneSwitcher.condition.timer.type.fixed="固定"
@@ -304,11 +236,11 @@ AdvSceneSwitcher.condition.macro.state.type.above="大于"
AdvSceneSwitcher.condition.macro.state.type.equal="等于"
AdvSceneSwitcher.condition.macro.count.reset="重置"
AdvSceneSwitcher.condition.macro.pausedWarning="所选宏当前已暂停!"
AdvSceneSwitcher.condition.macro.state.entry="{{macros}} 的条件为真"
AdvSceneSwitcher.condition.macro.multistate.entry=" 以下宏的 {{multiStateConditions}}{{multiStateCount}} 的条件为真:"
AdvSceneSwitcher.condition.macro.count.entry.line1="{{macros}} 行 {{conditions}} {{count}} 次(相对于下面计数匹配)"
AdvSceneSwitcher.condition.macro.state.entry="条件 {{macros}} 运行结果为真"
AdvSceneSwitcher.condition.macro.multistate.entry="条件 {{multiStateConditions}}{{multiStateCount}} 以下宏运行结果为真:"
AdvSceneSwitcher.condition.macro.count.entry.line1="{{macros}} 行 {{conditions}} {{count}} 次(相对于下面计数匹配)"
AdvSceneSwitcher.condition.macro.count.entry.line2="当前计数: {{currentCount}} {{resetCount}}"
AdvSceneSwitcher.condition.source="源"
AdvSceneSwitcher.condition.source="源"
AdvSceneSwitcher.condition.source.type.active="是激活状态"
AdvSceneSwitcher.condition.source.type.showing="是显示状态"
AdvSceneSwitcher.condition.source.type.settings="设置完全匹配"
@@ -325,7 +257,7 @@ AdvSceneSwitcher.condition.filter.type.active="已启用"
AdvSceneSwitcher.condition.filter.type.showing="已关闭"
AdvSceneSwitcher.condition.filter.type.settings="设置完全匹配"
AdvSceneSwitcher.condition.filter.getSettings="获取当前设置"
AdvSceneSwitcher.condition.filter.entry.line1="在 {{sources}} {{filters}} {{conditions}}"
AdvSceneSwitcher.condition.filter.entry.line1="在 {{sources}} {{filters}} {{conditions}}"
AdvSceneSwitcher.condition.filter.entry.line2="{{settings}}"
AdvSceneSwitcher.condition.filter.entry.line3="{{regex}} {{getSettings}}"
AdvSceneSwitcher.condition.sceneOrder="场景项目顺序"
@@ -357,8 +289,7 @@ AdvSceneSwitcher.condition.date.state.at="现在"
AdvSceneSwitcher.condition.date.state.after="之后"
AdvSceneSwitcher.condition.date.state.before="之前"
AdvSceneSwitcher.condition.date.state.between="之间"
AdvSceneSwitcher.condition.date.state.pattern="模式"
AdvSceneSwitcher.condition.date.separator="到"
AdvSceneSwitcher.condition.date.separator=""
AdvSceneSwitcher.condition.date.ignoreDate="如果未选中,日期组件将被忽略"
AdvSceneSwitcher.condition.date.ignoreTime="如果未选中,时间组件将被忽略"
AdvSceneSwitcher.condition.date.showAdvancedSettings="显示高级设置"
@@ -366,9 +297,8 @@ AdvSceneSwitcher.condition.date.showSimpleSettings="显示简单设置"
AdvSceneSwitcher.condition.date.entry.simple="在 {{dayOfWeek}} {{weekCondition}} {{ignoreWeekTime}}{{weekTime}}"
AdvSceneSwitcher.condition.date.entry.advanced="{{condition}} {{ignoreDate}}{{date}} {{ignoreTime}}{{time}} {{separator}} {{date2}} {{time2}}"
AdvSceneSwitcher.condition.date.entry.repeat="{{repeat}} 在匹配到日期时间后,每隔 {{duration}} 重复一次"
AdvSceneSwitcher.condition.date.entry.pattern="当前日期 \"{{currentDate}}\" 匹配模式 {{pattern}}"
AdvSceneSwitcher.condition.date.entry.nextMatchDate="下一次匹配 在: %1"
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} 重复时,将选定的日期更新为重复日期"
AdvSceneSwitcher.condition.date.entry.nextMatchDate="Next match at: %1"
AdvSceneSwitcher.condition.date.entry.updateOnRepeat="{{updateOnRepeat}} On repeat update selected date to repeat date"
AdvSceneSwitcher.condition.sceneTransform="场景项目被改变"
AdvSceneSwitcher.condition.sceneTransform.getTransform="内容或者设置被改变了"
AdvSceneSwitcher.condition.sceneTransform.entry.line1="在 {{scenes}} {{sources}} 匹配变换"
@@ -386,7 +316,6 @@ AdvSceneSwitcher.condition.transition.entry="{{conditions}}{{transitions}}{{scen
AdvSceneSwitcher.condition.sceneVisibility="场景项目可见"
AdvSceneSwitcher.condition.sceneVisibility.type.shown="显示的"
AdvSceneSwitcher.condition.sceneVisibility.type.hidden="隐藏的"
AdvSceneSwitcher.condition.sceneVisibility.type.changed="可见性已更改"
AdvSceneSwitcher.condition.sceneVisibility.entry="在 {{scenes}} {{sources}} 是 {{conditions}} "
AdvSceneSwitcher.condition.studioMode="工作室模式"
AdvSceneSwitcher.condition.studioMode.state.active="工作室模式处于活动状态"
@@ -416,7 +345,7 @@ AdvSceneSwitcher.condition.stats.condition.above="大于"
AdvSceneSwitcher.condition.stats.condition.equals="等于"
AdvSceneSwitcher.condition.stats.condition.below="少于"
AdvSceneSwitcher.condition.stats.dockHint="你可以打开“统计”窗口查看当前状态"
AdvSceneSwitcher.condition.stats.entry="{{stats}} {{condition}} {{value}}"
AdvSceneSwitcher.condition.stats.entry="{{stats}} is {{condition}} {{value}}"
AdvSceneSwitcher.condition.profile="配置文件"
AdvSceneSwitcher.condition.profile.entry="当前活动的配置文件为 {{profiles}}"
AdvSceneSwitcher.condition.websocket="websocket"
@@ -432,20 +361,7 @@ AdvSceneSwitcher.condition.variable.type.number="是一个数字"
AdvSceneSwitcher.condition.variable.type.lessThan="小于"
AdvSceneSwitcher.condition.variable.type.greaterThan="大于"
AdvSceneSwitcher.condition.variable.type.valueChanged="值已更改"
AdvSceneSwitcher.condition.variable.type.equalsVariable="等于变量"
AdvSceneSwitcher.condition.variable.type.lessThanVariable="小于变量"
AdvSceneSwitcher.condition.variable.type.greaterThanVariable="大于变量"
AdvSceneSwitcher.condition.variable.entry="{{variables}}{{conditions}}{{strValue}}{{numValue}}{{variables2}}"
AdvSceneSwitcher.condition.run="运行"
AdvSceneSwitcher.condition.run.entry="进程在超时 {{timeout}} 秒之前退出"
AdvSceneSwitcher.condition.run.entry.exit="{{checkExitCode}}检查退出代码{{exitCode}}"
AdvSceneSwitcher.condition.midi="MIDI"
AdvSceneSwitcher.condition.midi.entry="从{{device}} 收到的信息,符合:(从不咕咕的阿坤:这个好像是声卡工作是录音相关的功能,英文太抽象了,我就硬译过来了,如有相关设备,音乐好的,可以根据英文翻译好发给我!)"
AdvSceneSwitcher.condition.midi.entry.listen="将MIDI信息选择设置为从选定设备上接收的信息: {{listenButton}}"
AdvSceneSwitcher.condition.display="显示器"
AdvSceneSwitcher.condition.display.type.displayName="连接的显示器的名称匹配"
AdvSceneSwitcher.condition.display.type.displayCount="连接的显示器的数量为"
AdvSceneSwitcher.condition.display.entry="{{conditions}}{{displays}}{{regex}}{{displayCount}}"
; Macro Actions
AdvSceneSwitcher.action.switchScene="切换场景"
@@ -462,10 +378,6 @@ AdvSceneSwitcher.action.audio.type.mute="静音"
AdvSceneSwitcher.action.audio.type.unmute="取消静音"
AdvSceneSwitcher.action.audio.type.sourceVolume="来源音量"
AdvSceneSwitcher.action.audio.type.masterVolume="主音量"
AdvSceneSwitcher.action.audio.type.syncOffset="设置同步偏移"
AdvSceneSwitcher.action.audio.type.monitor="设置音频监听"
AdvSceneSwitcher.action.audio.type.balance="设置平衡"
AdvSceneSwitcher.action.audio.balance.description="选择的音频源将滑块方向移动(从不咕咕的阿坤的理解:左/右声道偏侧向)"
AdvSceneSwitcher.action.audio.fade.type.duration="持续时间"
AdvSceneSwitcher.action.audio.fade.type.rate="百分比"
AdvSceneSwitcher.action.audio.fade.duration="{{fade}}淡出 {{fadeTypes}} {{duration}} 秒."
@@ -479,44 +391,42 @@ AdvSceneSwitcher.action.recording.type.start="开始录制"
AdvSceneSwitcher.action.recording.type.pause="暂停录制"
AdvSceneSwitcher.action.recording.type.unpause="取消录制暂停"
AdvSceneSwitcher.action.recording.type.split="分割录制文件"
AdvSceneSwitcher.action.recording.type.changeOutputFolder="更改输出文件夹"
AdvSceneSwitcher.action.recording.type.changeOutputFileFormat="改变文件名的格式"
AdvSceneSwitcher.action.recording.pause.hint="请注意,根据您的录制设置,您可能无法暂停录制"
AdvSceneSwitcher.action.recording.split.hint="确保先在OBS设置中启用自动分割文件!"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{recordFolder}}{{recordFileFormat}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="回放缓"
AdvSceneSwitcher.action.replay.saveWarn="警告:保存过于频繁可能会导致回放缓存实际上未保存!"
AdvSceneSwitcher.action.replay.type.stop="停止回放缓"
AdvSceneSwitcher.action.replay.type.start="启动回放缓"
AdvSceneSwitcher.action.replay.type.save="保存回放缓"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}{{splitHint}}"
AdvSceneSwitcher.action.replay="回放缓冲区"
AdvSceneSwitcher.action.replay.saveWarn="警告:保存过于频繁可能会导致重播缓冲区实际上未保存!"
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.type.keyFrameInterval="设置关键帧间隔"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.run="运行"
AdvSceneSwitcher.action.run.arguments="参数:"
AdvSceneSwitcher.action.run.addArgument="添加参数"
AdvSceneSwitcher.action.run.addArgumentDescription="添加新参数:"
AdvSceneSwitcher.action.run.entry="运行 {{filePath}}"
AdvSceneSwitcher.action.sceneVisibility="场景项目可见性"
AdvSceneSwitcher.action.sceneVisibility.type.show="显示"
AdvSceneSwitcher.action.sceneVisibility.type.hide="隐藏"
AdvSceneSwitcher.action.sceneVisibility.type.toggle="切换"
AdvSceneSwitcher.action.sceneVisibility.type.source="来源"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="全部"
AdvSceneSwitcher.action.sceneVisibility.entry="置{{scenes}}{{actions}}{{sourceTypes}}{{sources}}{{sourceGroups}}"
AdvSceneSwitcher.action.sceneVisibility.entry="置{{scenes}}{{actions}}{{sourceTypes}}{{sources}}{{sourceGroups}}"
AdvSceneSwitcher.action.filter="滤镜"
AdvSceneSwitcher.action.filter.type.enable="开启"
AdvSceneSwitcher.action.filter.type.disable="关闭"
AdvSceneSwitcher.action.filter.type.settings="参数设置"
AdvSceneSwitcher.action.filter.entry=" {{sources}} {{actions}} {{filters}}"
AdvSceneSwitcher.action.filter.entry=" {{sources}} {{actions}} {{filters}}"
AdvSceneSwitcher.action.filter.getSettings="获取当前设置"
AdvSceneSwitcher.action.source="源"
AdvSceneSwitcher.action.source="源"
AdvSceneSwitcher.action.source.type.enable="启用"
AdvSceneSwitcher.action.source.type.disable="停用"
AdvSceneSwitcher.action.source.type.settings="配置设置"
AdvSceneSwitcher.action.source.type.refreshSettings="刷新源设置"
AdvSceneSwitcher.action.source.type.pressSettingsButton="按下设置按钮"
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="可用于刷新浏览器、媒体、源、etc"
AdvSceneSwitcher.action.source.noSettingsButtons="未找到按钮!"
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="可用于刷新浏览器、媒体等源"
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}"
AdvSceneSwitcher.action.source.warning="警告OBS UI无法控制全局启用和禁用源注意通过这个设置禁用我测试你必须通过这个在启用才行不然点击小眼睛你无法显示"
AdvSceneSwitcher.action.source.getSettings="获取当前设置"
@@ -533,16 +443,14 @@ AdvSceneSwitcher.action.macro="宏"
AdvSceneSwitcher.action.macro.type.pause="暂停"
AdvSceneSwitcher.action.macro.type.unpause="取消暂停"
AdvSceneSwitcher.action.macro.type.resetCounter="复位计数器"
AdvSceneSwitcher.action.macro.type.run="运行操作"
AdvSceneSwitcher.action.macro.type.stop="停止操作"
AdvSceneSwitcher.action.macro.type.run="运行"
AdvSceneSwitcher.action.macro.type.stop="停止"
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
AdvSceneSwitcher.action.pluginState="插件状态"
AdvSceneSwitcher.action.pluginState.type.stop="停止高级场景切换插件"
AdvSceneSwitcher.action.pluginState.type.noMatch="没有匹配项:"
AdvSceneSwitcher.action.pluginState.type.noMatch="没有匹配项:"
AdvSceneSwitcher.action.pluginState.type.import="从设置导入"
AdvSceneSwitcher.action.pluginState.importWarning="注意:当“设置”窗口打开时,操作将被忽略。"
AdvSceneSwitcher.action.pluginState.type.terminate="关闭 OBS"
AdvSceneSwitcher.action.pluginState.terminateConfirm="OBS将在10秒后自动关闭/n你想继续关闭OBS吗"
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
AdvSceneSwitcher.action.virtualCamera="虚拟摄像机"
AdvSceneSwitcher.action.virtualCamera.type.stop="停止虚拟摄像机"
@@ -559,7 +467,7 @@ AdvSceneSwitcher.action.hotkey.leftMeta="左 Meta"
AdvSceneSwitcher.action.hotkey.rightMeta="右 Meta"
AdvSceneSwitcher.action.hotkey.onlyOBS="仅向OBS发送按键"
AdvSceneSwitcher.action.hotkey.disabled="无法模拟按键-功能已禁用!"
AdvSceneSwitcher.action.hotkey.entry="按下 {{keys}} {{duration}} 秒"
AdvSceneSwitcher.action.hotkey.entry="按下 {{keys}} for {{duration}} 秒"
AdvSceneSwitcher.action.sceneOrder="场景项目顺序"
AdvSceneSwitcher.action.sceneOrder.type.moveUp="上移"
AdvSceneSwitcher.action.sceneOrder.type.moveDown="下移"
@@ -567,9 +475,9 @@ AdvSceneSwitcher.action.sceneOrder.type.moveTop="顶部"
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="底部"
AdvSceneSwitcher.action.sceneOrder.type.movePosition="移动到数值位置"
AdvSceneSwitcher.action.sceneOrder.entry="在 {{scenes}} {{actions}} {{sources}} {{position}}"
AdvSceneSwitcher.action.sceneTransform="场景项目换"
AdvSceneSwitcher.action.sceneTransform.getTransform="获得转换"
AdvSceneSwitcher.action.sceneTransform.entry="在 {{scenes}} 上转换 {{sources}}"
AdvSceneSwitcher.action.sceneTransform="场景项目换"
AdvSceneSwitcher.action.sceneTransform.getTransform="得到变换"
AdvSceneSwitcher.action.sceneTransform.entry="在 {{scenes}} 换 {{sources}}"
AdvSceneSwitcher.action.file="文件"
AdvSceneSwitcher.action.file.type.write="写入"
AdvSceneSwitcher.action.file.type.append="追加写入"
@@ -595,13 +503,9 @@ AdvSceneSwitcher.action.timer.type.reset="重置"
AdvSceneSwitcher.action.timer.type.setTimeRemaining="设置剩余时间"
AdvSceneSwitcher.action.timer.entry="{{timerAction}} 定时在 {{macros}} {{duration}}"
AdvSceneSwitcher.action.random="随机"
AdvSceneSwitcher.action.random.allowRepeat="允许连续执行同一宏"
AdvSceneSwitcher.action.random.entry="随机运行以下任何宏(忽略暂停的宏)"
AdvSceneSwitcher.action.systray="系统托盘通知"
AdvSceneSwitcher.action.systray.title="标题:"
AdvSceneSwitcher.action.systray.message="信息:"
AdvSceneSwitcher.action.systray.icon="图标:"
AdvSceneSwitcher.action.systray.iconHint="留空以使用默认图标"
AdvSceneSwitcher.action.systray.entry="显示通知: {{message}}"
AdvSceneSwitcher.action.screenshot="截图"
AdvSceneSwitcher.action.screenshot.save.default="默认"
AdvSceneSwitcher.action.screenshot.save.custom="其他"
@@ -624,56 +528,21 @@ AdvSceneSwitcher.action.sequence.continueFrom="继续所选项目"
AdvSceneSwitcher.action.websocket="websocket"
AdvSceneSwitcher.action.websocket.type.request="request"
AdvSceneSwitcher.action.websocket.type.event="event"
AdvSceneSwitcher.action.websocket.entry.request="通过{{connection}} 发送场景切换器 {{type}}"
AdvSceneSwitcher.action.websocket.entry.request="发送场景切换器 {{type}}{{connection}}"
AdvSceneSwitcher.action.websocket.entry.event="发送场景切换器 {{type}} 到连接的客户端"
AdvSceneSwitcher.action.http="Http"
AdvSceneSwitcher.action.http.setHeaders="设置头信息(SET headers)"
AdvSceneSwitcher.action.http.headers="头信息(headers):"
AdvSceneSwitcher.action.http.addHeader="增加头信息(ADD headers)"
AdvSceneSwitcher.action.http.type.get="获取(GET)"
AdvSceneSwitcher.action.http.type.post="发送(POST)"
AdvSceneSwitcher.action.http.type.get="GET"
AdvSceneSwitcher.action.http.type.post="POST"
AdvSceneSwitcher.action.http.entry.line1="发送 {{method}} 到 {{url}}"
AdvSceneSwitcher.action.http.entry.line2="超时: {{timeout}} 秒"
AdvSceneSwitcher.action.variable="变量"
AdvSceneSwitcher.action.variable.type.set="设置为固定值"
AdvSceneSwitcher.action.variable.type.set="设置"
AdvSceneSwitcher.action.variable.type.append="追加"
AdvSceneSwitcher.action.variable.type.appendVar="追加变量"
AdvSceneSwitcher.action.variable.type.increment="增加"
AdvSceneSwitcher.action.variable.type.decrement="减少"
AdvSceneSwitcher.action.variable.type.setActionValue="设置为操作值"
AdvSceneSwitcher.action.variable.type.setConditionValue="设置为条件值"
AdvSceneSwitcher.action.variable.type.roundToInt="取整到最近的整数"
AdvSceneSwitcher.action.variable.type.subString="设置为当前值的子字符串"
AdvSceneSwitcher.action.variable.type.findAndReplace="在当前值中查找并替换"
AdvSceneSwitcher.action.variable.type.mathExpression="数学表达式"
AdvSceneSwitcher.action.variable.mathExpression.example="( 1 + 2 * 3 ) / 4"
AdvSceneSwitcher.action.variable.findAndReplace.find="要查找的文本"
AdvSceneSwitcher.action.variable.findAndReplace.replace="要替换为的文本"
AdvSceneSwitcher.action.variable.subString.begin="开始"
AdvSceneSwitcher.action.variable.subString.all="全部"
AdvSceneSwitcher.action.variable.invalidSelection="无效选择!"
AdvSceneSwitcher.action.variable.actionNoVariableSupport="不支持从 %1 个操作获取变量值!"
AdvSceneSwitcher.action.variable.conditionNoVariableSupport="不支持从 %1 条件中获取变量值!"
AdvSceneSwitcher.action.variable.currentSegmentValue="当前值:"
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}{{mathExpression}}"
AdvSceneSwitcher.action.variable.entry.substringIndex="子字符串开始:{{subStringStart}} 子字符串大小:{{subStringSize}}"
AdvSceneSwitcher.action.variable.entry.substringRegex="使用正则表达式为 {{regexMatchIdx}} 匹配的值:"
AdvSceneSwitcher.action.variable.entry.findAndReplace="{{findStr}}{{replaceStr}}"
AdvSceneSwitcher.action.projector="投影仪"
AdvSceneSwitcher.action.projector.type.source="源"
AdvSceneSwitcher.action.projector.type.scene="场景"
AdvSceneSwitcher.action.projector.type.preview="预览"
AdvSceneSwitcher.action.projector.type.program="程序"
AdvSceneSwitcher.action.projector.type.multiview="多视图"
AdvSceneSwitcher.action.projector.display="显示"
AdvSceneSwitcher.action.projector.windowed="窗口"
AdvSceneSwitcher.action.projector.fullscreen="全屏"
AdvSceneSwitcher.action.projector.entry="打开为{{windowTypes}} 的 {{types}}{{scenes}}{{sources}}投影"
AdvSceneSwitcher.action.projector.entry.monitor="在 {{monitors}} 上 (从不咕咕的阿坤说:谨慎开启!)"
AdvSceneSwitcher.action.midi="MIDI"
AdvSceneSwitcher.action.midi.entry="发送消息到 {{device}}:"
AdvSceneSwitcher.action.midi.entry.listen="将MIDI消息选择设置为 {{listenDevices}} 上传入的消息: {{listenButton}}"
AdvSceneSwitcher.action.osc="打开声音控制"
AdvSceneSwitcher.action.variable.entry="{{actions}}{{variables}}{{variables2}}{{strValue}}{{numValue}}{{segmentIndex}}"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="转场特效"
@@ -953,7 +822,6 @@ AdvSceneSwitcher.connection.password="密码:"
AdvSceneSwitcher.connection.reconnect="自动重新连接:"
AdvSceneSwitcher.connection.reconnectDelay="自动重新连接延迟:"
AdvSceneSwitcher.connection.connectOnStart="启动时自动连接:"
AdvSceneSwitcher.connection.useOBSWebsocketProtocol="<html><head/><body><p>如何使用 obs-websocket <a href=\"https://github.com/obsproject/obs-websocket/blob/master/docs/generated/protocol.md\"><span style=\" text-decoration: underline; color:#268bd2;\">protocol</span></a></p></body></html>"
AdvSceneSwitcher.connection.test="测试连接"
AdvSceneSwitcher.connection.status.disconnected="断开"
AdvSceneSwitcher.connection.status.connecting="连接"
@@ -967,68 +835,6 @@ AdvSceneSwitcher.regex.dotMatchNewline=". 匹配换行符"
AdvSceneSwitcher.regex.multiLine="^ 和 $ 是匹配行的开始/结束"
AdvSceneSwitcher.regex.extendedPattern="启用Qt的扩展模式语法"
AdvSceneSwitcher.process.showAdvanced="显示高级设置"
AdvSceneSwitcher.process.arguments="参数:"
AdvSceneSwitcher.process.addArgument="增加参数"
AdvSceneSwitcher.process.addArgumentDescription="添加新参数:"
AdvSceneSwitcher.process.entry="运行{{filePath}}{{advancedSettings}}"
AdvSceneSwitcher.process.entry.workingDirectory="工作目录:{{workingDirectory}}"
AdvSceneSwitcher.math.expressionFail="计算表达式失败"
AdvSceneSwitcher.midi.deviceNamePattern="[端口 #%1] %2"
AdvSceneSwitcher.midi.message.type="类型:"
AdvSceneSwitcher.midi.message.type.optional="任意"
AdvSceneSwitcher.midi.message.type.invalid="无效"
AdvSceneSwitcher.midi.message.type.noteOff="关闭音符"
AdvSceneSwitcher.midi.message.type.noteOn="打开音符"
AdvSceneSwitcher.midi.message.type.polyphonicPressure="合成音压力"
AdvSceneSwitcher.midi.message.type.controlChange="控制更改"
AdvSceneSwitcher.midi.message.type.programChange="程序更改"
AdvSceneSwitcher.midi.message.type.channelAftertouch="频道余音"
AdvSceneSwitcher.midi.message.type.pitchBend="音高弯曲"
AdvSceneSwitcher.midi.message.type.systemExclusive="系统独占"
AdvSceneSwitcher.midi.message.type.timeCode="时间码"
AdvSceneSwitcher.midi.message.type.songPositionPointer="歌曲位置指针"
AdvSceneSwitcher.midi.message.type.songSelect="歌曲选择"
AdvSceneSwitcher.midi.message.type.reserved1="保留 (1)"
AdvSceneSwitcher.midi.message.type.reserved2="保留 (2)"
AdvSceneSwitcher.midi.message.type.tuneRequest="调音请求"
AdvSceneSwitcher.midi.message.type.endOfSystemExclusive="系统独占结束"
AdvSceneSwitcher.midi.message.type.timeClock="时间时钟"
AdvSceneSwitcher.midi.message.type.reserved3="保留 (3)"
AdvSceneSwitcher.midi.message.type.startFile="开始文件"
AdvSceneSwitcher.midi.message.type.continueFile="继续文件"
AdvSceneSwitcher.midi.message.type.stopFile="停止文件"
AdvSceneSwitcher.midi.message.type.reserved4="保留 (4)"
AdvSceneSwitcher.midi.message.type.activeSensing="主动感应"
AdvSceneSwitcher.midi.message.type.systemReset="系统充值"
AdvSceneSwitcher.midi.message.type.unknown="未知"
AdvSceneSwitcher.midi.message.channel="频道 :"
AdvSceneSwitcher.midi.message.note="音符 / 值(1):"
AdvSceneSwitcher.midi.message.value="值(2):"
AdvSceneSwitcher.midi.message.placeholder="任意"
AdvSceneSwitcher.midi.resetDevices="重新连接所有 MIDI 设备"
AdvSceneSwitcher.midi.startListen="开始监听"
AdvSceneSwitcher.midi.stopListen="停止监听"
AdvSceneSwitcher.midi.startListenFail="设备正忙!\n其他设备已经在监听!"
AdvSceneSwitcher.midi.deviceOpenFail="初始化 MIDI 设备失败!"
AdvSceneSwitcher.osc.network="网络"
AdvSceneSwitcher.osc.network.protocol="协议:"
AdvSceneSwitcher.osc.network.address="地址:"
AdvSceneSwitcher.osc.network.port="端口:"
AdvSceneSwitcher.osc.message="信息"
AdvSceneSwitcher.osc.message.type.none="无"
AdvSceneSwitcher.osc.message.type.float="浮点数哦"
AdvSceneSwitcher.osc.message.type.int="整数"
AdvSceneSwitcher.osc.message.type.string="字符串"
AdvSceneSwitcher.osc.message.type.binaryBlob="二进制"
AdvSceneSwitcher.osc.message.type.true="真"
AdvSceneSwitcher.osc.message.type.false="假"
AdvSceneSwitcher.osc.message.type.infinity="无限"
AdvSceneSwitcher.osc.message.type.null="无"
AdvSceneSwitcher.selectScene="--选择场景--"
AdvSceneSwitcher.selectPreviousScene="上个场景"
AdvSceneSwitcher.selectCurrentScene="当前场景"
@@ -1038,7 +844,7 @@ AdvSceneSwitcher.currentTransition="当前转场特效"
AdvSceneSwitcher.anyTransition="任何转场特效"
AdvSceneSwitcher.selectTransition="--选择转场特效--"
AdvSceneSwitcher.selectWindow="--选择窗口--"
AdvSceneSwitcher.selectSource="--选择源--"
AdvSceneSwitcher.selectSource="--选择源--"
AdvSceneSwitcher.selectAudioSource="--选择音频源--"
AdvSceneSwitcher.selectVideoSource="--选择视频源--"
AdvSceneSwitcher.OBSVideoOutput="OBS的主要输出"
@@ -1059,8 +865,8 @@ AdvSceneSwitcher.sceneItemSelection.any="任何"
AdvSceneSwitcher.status.active="运行中"
AdvSceneSwitcher.status.inactive="已停止"
AdvSceneSwitcher.running="插件正在运行"
AdvSceneSwitcher.stopped="插件停止"
AdvSceneSwitcher.running="插件运行"
AdvSceneSwitcher.stopped="插件停止"
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>这似乎是第一次启动高级场景切换程序.<br>请看一下 <a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> 查看指南和示例列表.<br>如果有问题在在OBS论坛插件帖子内提问 <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">thread</span></a></p></body></html>"
@@ -1074,8 +880,4 @@ AdvSceneSwitcher.duration.condition.none="没有时间限制"
AdvSceneSwitcher.duration.condition.more="时间少于"
AdvSceneSwitcher.duration.condition.equal="时间等于"
AdvSceneSwitcher.duration.condition.less="时间大于"
AdvSceneSwitcher.duration.condition.within="在最后"
AdvSceneSwitcher.audio.monitor.none="关闭监听"
AdvSceneSwitcher.audio.monitor.monitorOnly="仅监听(输出静音)"
AdvSceneSwitcher.audio.monitor.both="监听并输出"
AdvSceneSwitcher.duration.condition.within="保留结果后余存"

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 13.855469 0 l -1.539063 1.4375 c -0.453125 0.421875 -0.53125 1.148438 -0.269531 1.707031 l -5.886719 5.996094 c -0.011718 0 -0.019531 0 -0.03125 0 c -0.257812 -0.128906 -0.550781 -0.183594 -0.839844 -0.148437 c -0.328124 0.046874 -0.632812 0.199218 -0.867187 0.441406 l -3.945313 3.996094 c -0.3906245 0.375 -0.5468745 0.933593 -0.4062495 1.457031 c 0.1406255 0.523437 0.5546875 0.929687 1.0820315 1.058593 c 0.527344 0.132813 1.082031 -0.03125 1.453125 -0.425781 l 3.945312 -3.996093 c 0.472657 -0.453126 0.59375 -1.15625 0.296875 -1.738282 l 5.890625 -5.964844 c 0.558594 0.25 1.273438 0.148438 1.707031 -0.289062 l 1.414063 -1.5625 z m -10.308594 0.0898438 c -0.398437 0 -0.785156 0.0937502 -1.140625 0.2187502 l 1.882812 1.878906 c 0.390626 0.382812 0.390626 1 0 1.386719 l -0.710937 0.707031 c -0.386719 0.386719 -1 0.386719 -1.390625 0 l -1.882812 -1.878906 c -0.125 0.355468 -0.2187505 0.742187 -0.2187505 1.140625 c 0 1.90625 1.5507815 3.453125 3.4609375 3.453125 c 0.402344 0 0.789063 -0.09375 1.144531 -0.21875 l 1.175782 1.171875 h 0.058593 l 2.070313 -2.0625 l -1.203125 -1.203125 c 0.125 -0.359375 0.214843 -0.742188 0.214843 -1.140625 c 0 -1.90625 -1.546874 -3.4531252 -3.460937 -3.4531252 z m 6.550781 7.8906252 l -2.070312 2.066406 c 0.011718 0.027344 0.023437 0.058594 0.03125 0.089844 l 1.144531 1.140625 c -0.125 0.355468 -0.21875 0.742187 -0.21875 1.140625 c 0 1.902343 1.550781 3.449219 3.460937 3.449219 c 0.433594 0 0.855469 -0.101563 1.238282 -0.246094 l -2.007813 -2 c -0.386719 -0.386719 -0.386719 -1.035156 0 -1.417969 l 0.679688 -0.679687 c 0.195312 -0.191407 0.457031 -0.308594 0.710937 -0.308594 s 0.515625 0.117187 0.710938 0.308594 l 1.945312 1.941406 c 0.105469 -0.328125 0.183594 -0.683594 0.183594 -1.046875 c 0 -1.90625 -1.546875 -3.453125 -3.460938 -3.453125 c -0.398437 0 -0.785156 0.09375 -1.140624 0.21875 z m 0 0" fill="#fefefe"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<g fill="#fefefe">
<path d="m 3 1 c -1.644531 0 -3 1.355469 -3 3 v 8 c 0 1.644531 1.355469 3 3 3 h 8.882812 c 0.832032 0 1.578126 -0.402344 2.054688 -0.9375 c 0.472656 -0.53125 0.738281 -1.167969 0.910156 -1.800781 l 0.972656 -2.609375 c 0.390626 -1.449219 -0.09375 -2.652344 -0.820312 -3.167969 c -0.484375 -0.34375 -0.714844 -0.292969 -1 -0.324219 v -1.160156 c 0 -0.855469 -0.558594 -1.589844 -1.09375 -1.828125 c -0.53125 -0.238281 -1.011719 -0.167969 -1.011719 -0.167969 l 0.105469 -0.003906 h -3.585938 l -1.707031 -1.707031 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707031 -0.292969 z m 0 2 h 2.585938 l 1.707031 1.707031 c 0.1875 0.1875 0.441406 0.292969 0.707031 0.292969 h 4 c 0.035156 0 0.070312 -0.003906 0.105469 -0.007812 c 0 0 0.019531 0.019531 -0.011719 0.003906 c -0.035156 -0.011719 -0.09375 -0.25 -0.09375 0.003906 v 2 c 0 0.550781 0.449219 1 1 1 c 1 0 1.046875 0.703125 0.886719 1.128906 l -0.972657 2.609375 c -0.117187 0.4375 -0.296874 0.800781 -0.472656 0.996094 c -0.175781 0.199219 -0.285156 0.265625 -0.558594 0.265625 h -8.882812 c -0.570312 0 -1 -0.429688 -1 -1 v -8 c 0 -0.570312 0.46875 -0.792969 1 -1 z m 0 0"/>
<path d="m 7 6 l 0.042969 0.003906 c -0.914063 -0.042968 -1.75 0.390625 -2.195313 0.96875 c -0.710937 1.222656 -1.15625 2.277344 -1.800781 3.71875 c -0.171875 0.523438 0.117187 1.089844 0.640625 1.261719 c 0.527344 0.171875 1.09375 -0.117187 1.261719 -0.640625 c 0.488281 -1.011719 0.921875 -1.816406 1.339843 -2.808594 c 0.210938 -0.503906 0.703126 -0.492187 0.898438 -0.503906 h 5.8125 c 0.550781 0 1 -0.449219 1 -1 s -0.449219 -1 -1 -1 z m 0 0"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,24 +0,0 @@
<?xml version="1.0"?>
<svg width="640" height="640" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" version="1.1">
<defs>
<path d="m599.62,325.49c0,151.77 -123.21,274.98 -274.98,274.98c-151.76,0 -274.97,-123.21 -274.97,-274.98c0,-151.76 123.21,-274.97 274.97,-274.97c151.77,0 274.98,123.21 274.98,274.97z" id="c3Wyq0kfYS"/>
<mask height="689.95" id="maskanTyyngos" maskUnits="userSpaceOnUse" width="689.95" x="-20.33" y="-19.48">
<rect fill="white" height="689.95" id="svg_1" width="689.95" x="-20.33" y="-19.48"/>
<use fill="black" id="svg_2" xlink:href="#c3Wyq0kfYS"/>
</mask>
<path d="m334.97,96.07c4.54,0 8.23,3.68 8.23,8.23c0,46.94 0,179.54 0,226.48c0,4.54 -3.69,8.22 -8.23,8.22c-5.77,0 -14.88,0 -20.66,0c-4.54,0 -8.22,-3.68 -8.22,-8.22c0,-46.94 0,-179.54 0,-226.48c0,-4.55 3.68,-8.23 8.22,-8.23c5.78,0 14.89,0 20.66,0z" id="fxMeu932c"/>
<path d="m471.96,338.21c0.01,3.1 -2.5,5.62 -5.59,5.63c-32.02,0.09 -122.45,0.37 -154.46,0.47c-3.1,0.01 -5.61,-2.49 -5.62,-5.59c-0.02,-6.3 -0.06,-19.59 -0.08,-25.89c-0.01,-3.1 2.49,-5.62 5.59,-5.63c32.01,-0.09 122.44,-0.37 154.45,-0.47c3.1,-0.01 5.62,2.5 5.63,5.59c0.02,6.3 0.06,19.59 0.08,25.89z" id="h65nGmP2BL"/>
</defs>
<g class="layer">
<title>Layer 1</title>
<path fill="none" fill-opacity="null" id="svg_11" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02"/>
<ellipse cx="103.84" cy="562.04" fill="#fefefe" id="svg_3" rx="80" ry="45" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-18.699, 103.843, 562.038)"/>
<ellipse cx="506" cy="554" fill="#fefefe" id="svg_4" rx="77" ry="45" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-18.699, 506, 554)"/>
<rect fill="#fefefe" height="359" id="svg_7" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" stroke-width="0" width="58" x="122" y="185"/>
<rect fill="#fefefe" height="453" id="svg_8" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" width="58" x="522" y="84.5"/>
<rect fill="#fefefe" height="37" id="svg_9" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-14.1985, 351.556, 146.245)" width="463.07" x="120.02" y="127.74"/>
<rect fill="none" fill-opacity="null" height="0" id="svg_10" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" width="0" x="538.25" y="107.12"/>
<path d="m537.42,112.06l0,-67.88l17.58,67.88z" fill="#fefefe" id="svg_16" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-90, 546.203, 78.1248)"/>
<rect fill="#fefefe" height="0" id="svg_18" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" width="0" x="82.12" y="287.56"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,10 +0,0 @@
<?xml version="1.0"?>
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" version="1.1">
<!-- Created with SVG-edit - https://github.com/SVG-Edit/svgedit-->
<g class="layer">
<title>Layer 1</title>
<text fill="#fefefe" font-family="Serif" font-size="24" id="svg_1" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" transform="matrix(1.0974, 0, 0, 1.0974, -4.98544, 4.97639)" x="14" xml:space="preserve" y="13">*</text>
<rect fill="#fefefe" height="3.3" id="svg_2" stroke="#fefefe" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="5" x="1" y="12"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 815 B

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 13.855469 0 l -1.539063 1.4375 c -0.453125 0.421875 -0.53125 1.148438 -0.269531 1.707031 l -5.886719 5.996094 c -0.011718 0 -0.019531 0 -0.03125 0 c -0.257812 -0.128906 -0.550781 -0.183594 -0.839844 -0.148437 c -0.328124 0.046874 -0.632812 0.199218 -0.867187 0.441406 l -3.945313 3.996094 c -0.3906245 0.375 -0.5468745 0.933593 -0.4062495 1.457031 c 0.1406255 0.523437 0.5546875 0.929687 1.0820315 1.058593 c 0.527344 0.132813 1.082031 -0.03125 1.453125 -0.425781 l 3.945312 -3.996093 c 0.472657 -0.453126 0.59375 -1.15625 0.296875 -1.738282 l 5.890625 -5.964844 c 0.558594 0.25 1.273438 0.148438 1.707031 -0.289062 l 1.414063 -1.5625 z m -10.308594 0.0898438 c -0.398437 0 -0.785156 0.0937502 -1.140625 0.2187502 l 1.882812 1.878906 c 0.390626 0.382812 0.390626 1 0 1.386719 l -0.710937 0.707031 c -0.386719 0.386719 -1 0.386719 -1.390625 0 l -1.882812 -1.878906 c -0.125 0.355468 -0.2187505 0.742187 -0.2187505 1.140625 c 0 1.90625 1.5507815 3.453125 3.4609375 3.453125 c 0.402344 0 0.789063 -0.09375 1.144531 -0.21875 l 1.175782 1.171875 h 0.058593 l 2.070313 -2.0625 l -1.203125 -1.203125 c 0.125 -0.359375 0.214843 -0.742188 0.214843 -1.140625 c 0 -1.90625 -1.546874 -3.4531252 -3.460937 -3.4531252 z m 6.550781 7.8906252 l -2.070312 2.066406 c 0.011718 0.027344 0.023437 0.058594 0.03125 0.089844 l 1.144531 1.140625 c -0.125 0.355468 -0.21875 0.742187 -0.21875 1.140625 c 0 1.902343 1.550781 3.449219 3.460937 3.449219 c 0.433594 0 0.855469 -0.101563 1.238282 -0.246094 l -2.007813 -2 c -0.386719 -0.386719 -0.386719 -1.035156 0 -1.417969 l 0.679688 -0.679687 c 0.195312 -0.191407 0.457031 -0.308594 0.710937 -0.308594 s 0.515625 0.117187 0.710938 0.308594 l 1.945312 1.941406 c 0.105469 -0.328125 0.183594 -0.683594 0.183594 -1.046875 c 0 -1.90625 -1.546875 -3.453125 -3.460938 -3.453125 c -0.398437 0 -0.785156 0.09375 -1.140624 0.21875 z m 0 0" fill="#202020"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<g fill="#202020">
<path d="m 3 1 c -1.644531 0 -3 1.355469 -3 3 v 8 c 0 1.644531 1.355469 3 3 3 h 8.882812 c 0.832032 0 1.578126 -0.402344 2.054688 -0.9375 c 0.472656 -0.53125 0.738281 -1.167969 0.910156 -1.800781 l 0.972656 -2.609375 c 0.390626 -1.449219 -0.09375 -2.652344 -0.820312 -3.167969 c -0.484375 -0.34375 -0.714844 -0.292969 -1 -0.324219 v -1.160156 c 0 -0.855469 -0.558594 -1.589844 -1.09375 -1.828125 c -0.53125 -0.238281 -1.011719 -0.167969 -1.011719 -0.167969 l 0.105469 -0.003906 h -3.585938 l -1.707031 -1.707031 c -0.1875 -0.1875 -0.441406 -0.292969 -0.707031 -0.292969 z m 0 2 h 2.585938 l 1.707031 1.707031 c 0.1875 0.1875 0.441406 0.292969 0.707031 0.292969 h 4 c 0.035156 0 0.070312 -0.003906 0.105469 -0.007812 c 0 0 0.019531 0.019531 -0.011719 0.003906 c -0.035156 -0.011719 -0.09375 -0.25 -0.09375 0.003906 v 2 c 0 0.550781 0.449219 1 1 1 c 1 0 1.046875 0.703125 0.886719 1.128906 l -0.972657 2.609375 c -0.117187 0.4375 -0.296874 0.800781 -0.472656 0.996094 c -0.175781 0.199219 -0.285156 0.265625 -0.558594 0.265625 h -8.882812 c -0.570312 0 -1 -0.429688 -1 -1 v -8 c 0 -0.570312 0.46875 -0.792969 1 -1 z m 0 0"/>
<path d="m 7 6 l 0.042969 0.003906 c -0.914063 -0.042968 -1.75 0.390625 -2.195313 0.96875 c -0.710937 1.222656 -1.15625 2.277344 -1.800781 3.71875 c -0.171875 0.523438 0.117187 1.089844 0.640625 1.261719 c 0.527344 0.171875 1.09375 -0.117187 1.261719 -0.640625 c 0.488281 -1.011719 0.921875 -1.816406 1.339843 -2.808594 c 0.210938 -0.503906 0.703126 -0.492187 0.898438 -0.503906 h 5.8125 c 0.550781 0 1 -0.449219 1 -1 s -0.449219 -1 -1 -1 z m 0 0"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,24 +0,0 @@
<?xml version="1.0"?>
<svg width="640" height="640" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" version="1.1">
<defs>
<path d="m599.62,325.49c0,151.77 -123.21,274.98 -274.98,274.98c-151.76,0 -274.97,-123.21 -274.97,-274.98c0,-151.76 123.21,-274.97 274.97,-274.97c151.77,0 274.98,123.21 274.98,274.97z" id="c3Wyq0kfYS"/>
<mask height="689.95" id="maskanTyyngos" maskUnits="userSpaceOnUse" width="689.95" x="-20.33" y="-19.48">
<rect fill="white" height="689.95" id="svg_1" width="689.95" x="-20.33" y="-19.48"/>
<use fill="black" id="svg_2" xlink:href="#c3Wyq0kfYS"/>
</mask>
<path d="m334.97,96.07c4.54,0 8.23,3.68 8.23,8.23c0,46.94 0,179.54 0,226.48c0,4.54 -3.69,8.22 -8.23,8.22c-5.77,0 -14.88,0 -20.66,0c-4.54,0 -8.22,-3.68 -8.22,-8.22c0,-46.94 0,-179.54 0,-226.48c0,-4.55 3.68,-8.23 8.22,-8.23c5.78,0 14.89,0 20.66,0z" id="fxMeu932c"/>
<path d="m471.96,338.21c0.01,3.1 -2.5,5.62 -5.59,5.63c-32.02,0.09 -122.45,0.37 -154.46,0.47c-3.1,0.01 -5.61,-2.49 -5.62,-5.59c-0.02,-6.3 -0.06,-19.59 -0.08,-25.89c-0.01,-3.1 2.49,-5.62 5.59,-5.63c32.01,-0.09 122.44,-0.37 154.45,-0.47c3.1,-0.01 5.62,2.5 5.63,5.59c0.02,6.3 0.06,19.59 0.08,25.89z" id="h65nGmP2BL"/>
</defs>
<g class="layer">
<title>Layer 1</title>
<path fill="none" fill-opacity="null" id="svg_11" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02"/>
<ellipse cx="103.84" cy="562.04" fill="#202020" id="svg_3" rx="80" ry="45" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-18.699, 103.843, 562.038)"/>
<ellipse cx="506" cy="554" fill="#202020" id="svg_4" rx="77" ry="45" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-18.699, 506, 554)"/>
<rect fill="#202020" height="359" id="svg_7" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" stroke-width="0" width="58" x="122" y="185"/>
<rect fill="#202020" height="453" id="svg_8" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" width="58" x="522" y="84.5"/>
<rect fill="#202020" height="37" id="svg_9" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-14.1985, 351.556, 146.245)" width="463.07" x="120.02" y="127.74"/>
<rect fill="none" fill-opacity="null" height="0" id="svg_10" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" width="0" x="538.25" y="107.12"/>
<path d="m537.42,112.06l0,-67.88l17.58,67.88z" fill="#202020" id="svg_16" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" transform="rotate(-90, 546.203, 78.1248)"/>
<rect fill="#202020" height="0" id="svg_18" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="0.02" width="0" x="82.12" y="287.56"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,10 +0,0 @@
<?xml version="1.0"?>
<svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet" version="1.1">
<!-- Created with SVG-edit - https://github.com/SVG-Edit/svgedit-->
<g class="layer">
<title>Layer 1</title>
<text fill="#202020" font-family="Serif" font-size="24" id="svg_1" stroke="#000000" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" stroke-opacity="null" stroke-width="0" text-anchor="middle" transform="matrix(1.0974, 0, 0, 1.0974, -4.98544, 4.97639)" x="14" xml:space="preserve" y="13">*</text>
<rect fill="#202020" height="3.3" id="svg_2" stroke="#202020" stroke-dasharray="null" stroke-linecap="null" stroke-linejoin="null" transform="matrix(1, 0, 0, 1, 0, 0)" width="5" x="1" y="12"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 815 B

View File

@@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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="#202020" stroke-width="70" stroke-opacity="1"></use></g></g><g><use xlink:href="#fxMeu932c" opacity="1" fill="#202020" fill-opacity="1"></use></g><g><use xlink:href="#h65nGmP2BL" opacity="1" fill="#202020" fill-opacity="1"></use></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,2 +1,3 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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="#fefefe" stroke-width="70" stroke-opacity="1"></use></g></g><g><use xlink:href="#fxMeu932c" opacity="1" fill="#fefefe" fill-opacity="1"></use></g><g><use xlink:href="#h65nGmP2BL" opacity="1" fill="#fefefe" fill-opacity="1"></use></g></g></g></svg>
<!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>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

41032
deps/exprtk/exprtk.hpp vendored

File diff suppressed because it is too large Load Diff

1
deps/libremidi vendored

Submodule deps/libremidi deleted from 56147984ee

View File

@@ -256,30 +256,6 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_26">
<item>
<widget class="QCheckBox" name="warnPluginLoadFailure">
<property name="text">
<string>AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailure</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_19">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_24">
<item>
@@ -658,7 +634,7 @@
</widget>
</item>
<item>
<widget class="advss::MacroTree" name="macros">
<widget class="MacroTree" name="macros">
<property name="showDropIndicator" stdset="0">
<bool>true</bool>
</property>
@@ -4563,7 +4539,7 @@
</widget>
<customwidgets>
<customwidget>
<class>advss::MacroTree</class>
<class>MacroTree</class>
<extends>QListView</extends>
<header>macro-tree.hpp</header>
</customwidget>

View File

@@ -9,15 +9,26 @@
#include <obs-frontend-api.h>
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "status-control.hpp"
#include "scene-switch-helpers.hpp"
#include "curl-helper.hpp"
#include "platform-funcs.hpp"
#include "utility.hpp"
#include "version.h"
namespace advss {
const char *obs_module_text(const char *text)
{
return switcher->translate(text);
}
obs_module_t *obs_current_module()
{
return switcher->modulePtr;
}
SwitcherData *switcher = nullptr;
SwitcherData *GetSwitcher()
{
return switcher;
}
AdvSceneSwitcher *AdvSceneSwitcher::window = nullptr;
@@ -29,9 +40,11 @@ AdvSceneSwitcher::AdvSceneSwitcher(QWidget *parent)
{
switcher->settingsWindowOpened = true;
ui->setupUi(this);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->Prune();
LoadUI();
loadUI();
}
AdvSceneSwitcher::~AdvSceneSwitcher()
@@ -42,76 +55,51 @@ AdvSceneSwitcher::~AdvSceneSwitcher()
}
}
static bool translationAvailable()
bool translationAvailable()
{
return !!strcmp(obs_module_text("AdvSceneSwitcher.pluginName"),
"AdvSceneSwitcher.pluginName");
}
static void DisplayMissingDependencyWarning()
void AdvSceneSwitcher::loadUI()
{
if (!switcher->warnPluginLoadFailure ||
switcher->loadFailureLibs.isEmpty()) {
return;
}
QString failedLibsString = "<ul>";
for (const auto &lib : switcher->loadFailureLibs) {
failedLibsString += "<li>" + lib + "</li>";
}
failedLibsString += "</ul>";
QString warning(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.warnPluginLoadFailureMessage"));
DisplayMessage(warning.arg(failedLibsString));
}
static void DisplayMissingDataDirWarning()
{
if (translationAvailable()) {
return;
}
QString msg = "Failed to find plug-in's 'data' directory.\n"
"Please check installation instructions!\n\n"
"Data most likely expected at:\n\n";
if (!translationAvailable()) {
QString msg = "Failed to find plug-in's 'data' directory.\n"
"Please check installation instructions!\n\n"
"Data most likely expected at:\n\n";
#ifdef _WIN32
msg += QString::fromStdString(
(std::filesystem::current_path().string()));
msg += "/";
msg += QString::fromStdString(
(std::filesystem::current_path().string()));
msg += "/";
#endif
msg += obs_get_module_data_path(obs_current_module());
DisplayMessage(msg);
}
msg += obs_get_module_data_path(obs_current_module());
(void)DisplayMessage(msg);
}
void AdvSceneSwitcher::LoadUI()
{
DisplayMissingDataDirWarning();
DisplayMissingDependencyWarning();
setupGeneralTab();
setupTitleTab();
setupExecutableTab();
setupRegionTab();
setupPauseTab();
setupSequenceTab();
setupTransitionsTab();
setupIdleTab();
setupRandomTab();
setupMediaTab();
setupFileTab();
setupTimeTab();
setupAudioTab();
setupVideoTab();
setupNetworkTab();
setupSceneGroupTab();
setupTriggerTab();
setupMacroTab();
SetupGeneralTab();
SetupTitleTab();
SetupExecutableTab();
SetupRegionTab();
SetupPauseTab();
SetupSequenceTab();
SetupTransitionsTab();
SetupIdleTab();
SetupRandomTab();
SetupMediaTab();
SetupFileTab();
SetupTimeTab();
SetupAudioTab();
SetupVideoTab();
SetupNetworkTab();
SetupSceneGroupTab();
SetupTriggerTab();
SetupMacroTab();
SetDeprecationWarnings();
SetTabOrder();
SetCurrentTab();
RestoreWindowGeo();
CheckFirstTimeSetup();
setDeprecationWarnings();
setTabOrder();
setCurrentTab();
restoreWindowGeo();
checkFirstTimeSetup();
loading = false;
}
@@ -119,15 +107,13 @@ void AdvSceneSwitcher::LoadUI()
/******************************************************************************
* Saving and loading
******************************************************************************/
static void AskForBackup(obs_data_t *obj);
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
{
if (saving) {
std::lock_guard<std::mutex> lock(switcher->m);
switcher->Prune();
obs_data_t *obj = obs_data_create();
switcher->SaveSettings(obj);
switcher->saveSettings(obj);
obs_data_set_obj(save_data, "advanced-scene-switcher", obj);
obs_data_release(obj);
} else {
@@ -141,10 +127,10 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
if (!obj) {
obj = obs_data_create();
}
if (switcher->VersionChanged(obj, g_GIT_SHA1)) {
if (switcher->versionChanged(obj, g_GIT_SHA1)) {
AskForBackup(obj);
}
switcher->LoadSettings(obj);
switcher->loadSettings(obj);
obs_data_release(obj);
switcher->m.unlock();
@@ -154,34 +140,6 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
}
}
static void AskForBackup(obs_data_t *obj)
{
bool backupSettings = DisplayMessage(
obs_module_text("AdvSceneSwitcher.askBackup"), true);
if (!backupSettings) {
return;
}
QString path = QFileDialog::getSaveFileName(
nullptr,
obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle"),
GetDefaultSettingsSaveLocation(),
obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType"));
if (path.isEmpty()) {
return;
}
QFile file(path);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return;
}
obs_data_save_json(obj, file.fileName().toUtf8().constData());
}
/******************************************************************************
* Main switcher thread
******************************************************************************/
@@ -225,7 +183,7 @@ void SwitcherData::Thread()
}
vblog(LOG_INFO, "try to sleep for %ld", duration.count());
SetWaitScene();
setWaitScene();
cv.wait_for(lock, duration);
startTime = std::chrono::high_resolution_clock::now();
@@ -239,13 +197,13 @@ void SwitcherData::Thread()
if (checkPause()) {
continue;
}
SetPreconditions();
match = CheckForMatch(scene, transition, linger,
setPreconditions();
match = checkForMatch(scene, transition, linger,
setPrevSceneAfterLinger, macroMatch);
if (stop) {
break;
}
CheckNoMatchSwitch(match, scene, transition, sleep);
checkNoMatchSwitch(match, scene, transition, sleep);
checkSwitchCooldown(match);
if (linger) {
@@ -253,14 +211,14 @@ void SwitcherData::Thread()
vblog(LOG_INFO, "sleep for %ld before switching scene",
duration.count());
SetWaitScene();
setWaitScene();
cv.wait_for(lock, duration);
if (stop) {
break;
}
if (SceneChangedDuringWait()) {
if (sceneChangedDuringWait()) {
vblog(LOG_INFO,
"scene was changed manually - ignoring match");
@@ -271,13 +229,13 @@ void SwitcherData::Thread()
}
}
ResetForNextInterval();
ClearWebsocketMessages();
if (match) {
if (macroMatch) {
RunMacros();
runMacros();
} else {
SwitchScene({scene, transition, 0});
switchScene({scene, transition, 0});
}
}
@@ -290,7 +248,7 @@ void SwitcherData::Thread()
blog(LOG_INFO, "stopped");
}
void SwitcherData::SetPreconditions()
void SwitcherData::setPreconditions()
{
// Window title
lastTitle = currentTitle;
@@ -318,23 +276,13 @@ void SwitcherData::SetPreconditions()
GetForegroundProcessName(currentForegroundProcess);
// Cursor
std::pair<int, int> cursorPos = GetCursorPos();
std::pair<int, int> cursorPos = getCursorPos();
cursorPosChanged = cursorPos.first != switcher->lastCursorPos.first ||
cursorPos.second != switcher->lastCursorPos.second;
lastCursorPos = GetCursorPos();
lastCursorPos = getCursorPos();
}
void SwitcherData::ResetForNextInterval()
{
// Core reset functions
ClearWebsocketMessages();
// Plugin reset functions
for (const auto &func : resetForNextIntervalFuncs) {
func();
}
}
bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
bool SwitcherData::checkForMatch(OBSWeakSource &scene,
OBSWeakSource &transition, int &linger,
bool &setPrevSceneAfterLinger,
bool &macroMatch)
@@ -384,7 +332,7 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
match = checkVideoSwitch(scene, transition);
break;
case macro_func:
if (CheckMacros()) {
if (checkMacros()) {
match = true;
macroMatch = true;
}
@@ -401,20 +349,48 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
return match;
}
static void ResetMacros()
void switchScene(const sceneSwitchInfo &sceneSwitch, bool force)
{
for (auto &m : switcher->macros) {
m->ResetRunCount();
m->ResetTimers();
if (!sceneSwitch.scene && switcher->verbose) {
blog(LOG_INFO, "nothing to switch to");
return;
}
obs_source_t *source = obs_weak_source_get_source(sceneSwitch.scene);
obs_source_t *currentSource = obs_frontend_get_current_scene();
if (source && (source != currentSource || force)) {
transitionData currentTransitionData;
setNextTransition(sceneSwitch, currentSource,
currentTransitionData);
obs_frontend_set_current_scene(source);
if (switcher->transitionOverrideOverride) {
restoreTransitionOverride(source,
currentTransitionData);
}
if (switcher->verbose) {
blog(LOG_INFO, "switched scene");
}
if (switcher->networkConfig.ShouldSendSceneChange()) {
switcher->server.sendMessage(sceneSwitch);
}
}
obs_source_release(currentSource);
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())) {
ResetForNextInterval();
ResetMacros();
stop = false;
th = new SwitcherThread();
th->start((QThread::Priority)threadPriority);
@@ -439,6 +415,14 @@ void SwitcherData::Start()
}
}
void ResetMacros()
{
for (auto &m : switcher->macros) {
m->ResetRunCount();
m->ResetTimers();
}
}
void SwitcherData::Stop()
{
if (th && th->isRunning()) {
@@ -452,6 +436,7 @@ void SwitcherData::Stop()
th = nullptr;
writeToStatusFile("Advanced Scene Switcher stopped");
ResetMacros();
}
server.stop();
@@ -464,13 +449,13 @@ void SwitcherData::Stop()
}
}
void SwitcherData::SetWaitScene()
void SwitcherData::setWaitScene()
{
waitScene = obs_frontend_get_current_scene();
obs_source_release(waitScene);
}
bool SwitcherData::SceneChangedDuringWait()
bool SwitcherData::sceneChangedDuringWait()
{
obs_source_t *currentSource = obs_frontend_get_current_scene();
if (!currentSource) {
@@ -483,7 +468,7 @@ bool SwitcherData::SceneChangedDuringWait()
// Relies on the fact that switcher->currentScene will only be updated on event
// OBS_FRONTEND_EVENT_SCENE_CHANGED but obs_frontend_get_current_scene() will
// already return the scene to be transitioned to.
bool SwitcherData::AnySceneTransitionStarted()
bool SwitcherData::anySceneTransitionStarted()
{
auto currentSceneSrouce = obs_frontend_get_current_scene();
auto currentScene = obs_source_get_weak_source(currentSceneSrouce);
@@ -504,13 +489,13 @@ extern "C" void FreeSceneSwitcher()
switcher = nullptr;
}
static void handleSceneChange()
void handleSceneChange()
{
switcher->lastSceneChangeTime =
std::chrono::high_resolution_clock::now();
// Stop waiting if scene was changed
if (switcher->SceneChangedDuringWait()) {
if (switcher->sceneChangedDuringWait()) {
switcher->cv.notify_one();
}
@@ -538,33 +523,31 @@ static void handleSceneChange()
}
}
static void setLiveTime()
void setLiveTime()
{
switcher->liveTime = QDateTime::currentDateTime();
}
static void resetLiveTime()
void resetLiveTime()
{
switcher->liveTime = QDateTime();
}
static void checkAutoStartRecording()
void checkAutoStartRecording()
{
if (switcher->autoStartEvent == SwitcherData::AutoStart::RECORDING ||
switcher->autoStartEvent ==
SwitcherData::AutoStart::RECORINDG_OR_STREAMING)
if (switcher->autoStartEvent == AutoStartEvent::RECORDING ||
switcher->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
switcher->Start();
}
static void checkAutoStartStreaming()
void checkAutoStartStreaming()
{
if (switcher->autoStartEvent == SwitcherData::AutoStart::STREAMING ||
switcher->autoStartEvent ==
SwitcherData::AutoStart::RECORINDG_OR_STREAMING)
if (switcher->autoStartEvent == AutoStartEvent::STREAMING ||
switcher->autoStartEvent == AutoStartEvent::RECORINDG_OR_STREAMING)
switcher->Start();
}
static void handlePeviewSceneChange()
void handlePeviewSceneChange()
{
if (switcher->networkConfig.ShouldSendPrviewSceneChange()) {
auto source = obs_frontend_get_current_preview_scene();
@@ -575,45 +558,43 @@ static void handlePeviewSceneChange()
}
}
static void setReplayBufferSaved()
void setReplayBufferSaved()
{
switcher->replayBufferSaved = true;
}
static void setTranstionEnd()
void setTranstionEnd()
{
switcher->lastTransitionEndTime =
std::chrono::high_resolution_clock::now();
switcher->macroTransitionCv.notify_all();
}
static void setStreamStarting()
void setStreamStarting()
{
switcher->lastStreamStartingTime =
std::chrono::high_resolution_clock::now();
}
static void setStreamStopping()
void setStreamStopping()
{
switcher->lastStreamStoppingTime =
std::chrono::high_resolution_clock::now();
}
static void handleExit()
void handleExit()
{
if (!switcher) {
return;
}
switcher->obsIsShuttingDown = true;
if (switcher->shutdownConditionCount) {
if (switcher && switcher->obsIsShuttingDown &&
switcher->shutdownConditionCount) {
switcher->Stop();
switcher->CheckMacros();
switcher->RunMacros();
switcher->checkMacros();
switcher->runMacros();
}
FreeSceneSwitcher();
}
static void handleSceneCollectionChanging()
void handleSceneCollectionChanging()
{
if (switcher->settingsWindowOpened) {
AdvSceneSwitcher::window->close();
@@ -679,7 +660,7 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
}
}
static void LoadPlugins()
void LoadPlugins()
{
QFileInfo libPath(
QString(obs_get_module_binary_path(obs_current_module())));
@@ -703,7 +684,6 @@ static void LoadPlugins()
blog(LOG_WARNING, "failed to load \"%s\": %s",
file.toStdString().c_str(),
lib->errorString().toStdString().c_str());
switcher->loadFailureLibs << file;
}
}
}
@@ -723,12 +703,14 @@ void OpenSettingsWindow()
}
}
extern "C" void InitSceneSwitcher(obs_module_t *module, translateFunc translate)
extern "C" void InitSceneSwitcher(obs_module_t *m, translateFunc t)
{
blog(LOG_INFO, "version: %s", g_GIT_TAG);
blog(LOG_INFO, "version: %s", g_GIT_SHA1);
switcher = new SwitcherData(module, translate);
switcher = new SwitcherData;
switcher->modulePtr = m;
switcher->translate = t;
PlatformInit();
LoadPlugins();
@@ -741,5 +723,3 @@ extern "C" void InitSceneSwitcher(obs_module_t *module, translateFunc translate)
obs_module_text("AdvSceneSwitcher.pluginName"));
action->connect(action, &QAction::triggered, OpenSettingsWindow);
}
} // namespace advss

View File

@@ -1,18 +1,19 @@
#pragma once
#include "macro-segment-list.hpp"
#include "log-helper.hpp"
#include "switcher-data-structs.hpp"
#include "platform-funcs.hpp"
#include <macro-segment-list.hpp>
#include <ui_advanced-scene-switcher.h>
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
#define vblog(level, msg, ...) \
if (switcher->verbose) { \
blog(level, msg, ##__VA_ARGS__); \
}
class QCloseEvent;
namespace advss {
class MacroActionEdit;
class MacroConditionEdit;
class Duration;
class SequenceWidget;
struct SceneGroup;
/*******************************************************************************
* Advanced Scene Switcher window
@@ -32,54 +33,23 @@ public:
void reject() override;
void closeEvent(QCloseEvent *event) override;
void LoadUI();
void SetShowFrames();
void SetHideFrames();
void clearFrames(QListWidget *list);
void SetTabOrder();
void SetCurrentTab();
void RestoreWindowGeo();
void CheckFirstTimeSetup();
int IgnoreWindowsFindByData(const QString &window);
int IgnoreIdleWindowsFindByData(const QString &window);
/* --- Begin of general tab section --- */
public:
void SetupGeneralTab();
void UpdateNonMatchingScene(const QString &name);
void SetDeprecationWarnings();
void OpenSequenceExtendEdit(SequenceWidget *sw);
void SetEditSceneGroup(SceneGroup &sg);
public slots:
void on_noMatchDontSwitch_clicked();
void on_noMatchSwitch_clicked();
void on_noMatchRandomSwitch_clicked();
void NoMatchDelayDurationChanged(const Duration &);
void CooldownDurationChanged(const Duration &);
void on_startupBehavior_currentIndexChanged(int index);
void on_autoStartEvent_currentIndexChanged(int index);
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
void on_checkInterval_valueChanged(int value);
void on_tabMoved(int from, int to);
void on_tabWidget_currentChanged(int index);
void on_exportSettings_clicked();
void on_importSettings_clicked();
void on_verboseLogging_stateChanged(int state);
void on_saveWindowGeo_stateChanged(int state);
void on_showTrayNotifications_stateChanged(int state);
void on_uiHintsDisable_stateChanged(int state);
void on_warnPluginLoadFailure_stateChanged(int state);
void on_hideLegacyTabs_stateChanged(int state);
void on_priorityUp_clicked();
void on_priorityDown_clicked();
void on_threadPriority_currentTextChanged(const QString &text);
/* --- End of legacy tab section --- */
/* --- Begin of macro tab section --- */
public:
void SetupMacroTab();
bool AddNewMacro(std::shared_ptr<Macro> &res, std::string &name,
bool addNewMacro(std::shared_ptr<Macro> &res, std::string &name,
std::string format = "");
void RemoveMacro(std::shared_ptr<Macro> &);
void RenameMacro(std::shared_ptr<Macro> &, const QString &name);
std::shared_ptr<Macro> GetSelectedMacro();
std::vector<std::shared_ptr<Macro>> GetSelectedMacros();
std::shared_ptr<Macro> getSelectedMacro();
std::vector<std::shared_ptr<Macro>> getSelectedMacros();
void SetEditMacro(Macro &m);
void SetMacroEditAreaDisabled(bool);
void HighlightAction(int idx, QColor color = QColor(Qt::green));
@@ -91,7 +61,68 @@ public:
void SwapActions(Macro *m, int pos1, int pos2);
void SwapConditions(Macro *m, int pos1, int pos2);
void loadUI();
void setupGeneralTab();
void setupTitleTab();
void setupExecutableTab();
void setupRegionTab();
void setupPauseTab();
void setupSequenceTab();
void setupTransitionsTab();
void setupIdleTab();
void setupRandomTab();
void setupMediaTab();
void setupFileTab();
void setupTimeTab();
void setupAudioTab();
void setupSceneGroupTab();
void setupTriggerTab();
void setupVideoTab();
void setupNetworkTab();
void setupMacroTab();
void setDeprecationWarnings();
void setTabOrder();
void setCurrentTab();
void restoreWindowGeo();
void checkFirstTimeSetup();
signals:
void MacroAdded(const QString &name);
void MacroRemoved(const QString &name);
void MacroRenamed(const QString &oldName, const QString &newName);
void MacroSegmentOrderChanged();
void HighlightMacrosChanged(bool value);
void HighlightActionsChanged(bool value);
void HighlightConditionsChanged(bool value);
void SceneGroupAdded(const QString &name);
void SceneGroupRemoved(const QString &name);
void SceneGroupRenamed(const QString &oldName, const QString newName);
void ConnectionAdded(const QString &);
void ConnectionRenamed(const QString &oldName, const QString &newName);
void ConnectionRemoved(const QString &);
void VariableAdded(const QString &);
void VariableRenamed(const QString &oldName, const QString &newName);
void VariableRemoved(const QString &);
public slots:
void on_windowUp_clicked();
void on_windowDown_clicked();
void on_windowAdd_clicked();
void on_windowRemove_clicked();
void on_noMatchDontSwitch_clicked();
void on_noMatchSwitch_clicked();
void on_noMatchRandomSwitch_clicked();
void NoMatchDelayDurationChanged(double);
void NoMatchDelayUnitChanged(DurationUnit);
void CooldownDurationChanged(double);
void CooldownUnitChanged(DurationUnit);
void on_startupBehavior_currentIndexChanged(int index);
void on_autoStartEvent_currentIndexChanged(int index);
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
void on_checkInterval_valueChanged(int value);
void on_tabMoved(int from, int to);
void on_tabWidget_currentChanged(int index);
void on_macroAdd_clicked();
void on_macroRemove_clicked();
void on_macroUp_clicked();
@@ -144,21 +175,135 @@ public slots:
void HighlightOnChange();
void on_macroProperties_clicked();
signals:
void MacroAdded(const QString &name);
void MacroRemoved(const QString &name);
void MacroRenamed(const QString &oldName, const QString &newName);
void MacroSegmentOrderChanged();
void HighlightMacrosChanged(bool value);
void HighlightActionsChanged(bool value);
void HighlightConditionsChanged(bool value);
void on_screenRegionSwitches_currentRowChanged(int idx);
void on_showFrame_clicked();
void on_screenRegionAdd_clicked();
void on_screenRegionRemove_clicked();
void on_screenRegionUp_clicked();
void on_screenRegionDown_clicked();
void ConnectionAdded(const QString &);
void ConnectionRenamed(const QString &oldName, const QString &newName);
void ConnectionRemoved(const QString &);
void VariableAdded(const QString &);
void VariableRenamed(const QString &oldName, const QString &newName);
void VariableRemoved(const QString &);
void on_pauseUp_clicked();
void on_pauseDown_clicked();
void on_pauseAdd_clicked();
void on_pauseRemove_clicked();
void on_ignoreWindows_currentRowChanged(int idx);
void on_ignoreWindowsAdd_clicked();
void on_ignoreWindowsRemove_clicked();
void on_sceneSequenceAdd_clicked();
void on_sceneSequenceRemove_clicked();
void on_sceneSequenceUp_clicked();
void on_sceneSequenceDown_clicked();
void on_sceneSequenceSave_clicked();
void on_sceneSequenceLoad_clicked();
void on_sequenceEdit_clicked();
void on_sceneSequenceSwitches_itemDoubleClicked(QListWidgetItem *item);
void on_verboseLogging_stateChanged(int state);
void on_saveWindowGeo_stateChanged(int state);
void on_showTrayNotifications_stateChanged(int state);
void on_uiHintsDisable_stateChanged(int state);
void on_hideLegacyTabs_stateChanged(int state);
void on_exportSettings_clicked();
void on_importSettings_clicked();
void on_transitionsAdd_clicked();
void on_transitionsRemove_clicked();
void on_transitionsUp_clicked();
void on_transitionsDown_clicked();
void on_defaultTransitionsAdd_clicked();
void on_defaultTransitionsRemove_clicked();
void on_defaultTransitionsUp_clicked();
void on_defaultTransitionsDown_clicked();
void on_transitionOverridecheckBox_stateChanged(int state);
void on_adjustActiveTransitionType_stateChanged(int state);
void defTransitionDelayValueChanged(int value);
void on_browseButton_clicked();
void on_readFileCheckBox_stateChanged(int state);
void on_readPathLineEdit_textChanged(const QString &text);
void on_writePathLineEdit_textChanged(const QString &text);
void on_browseButton_2_clicked();
void on_executableUp_clicked();
void on_executableDown_clicked();
void on_executableAdd_clicked();
void on_executableRemove_clicked();
void on_idleCheckBox_stateChanged(int state);
void on_ignoreIdleWindows_currentRowChanged(int idx);
void on_ignoreIdleAdd_clicked();
void on_ignoreIdleRemove_clicked();
void on_randomAdd_clicked();
void on_randomRemove_clicked();
void on_fileAdd_clicked();
void on_fileRemove_clicked();
void on_fileSwitches_currentRowChanged(int idx);
void on_fileUp_clicked();
void on_fileDown_clicked();
void on_mediaAdd_clicked();
void on_mediaRemove_clicked();
void on_mediaUp_clicked();
void on_mediaDown_clicked();
void on_timeAdd_clicked();
void on_timeRemove_clicked();
void on_timeUp_clicked();
void on_timeDown_clicked();
void on_audioAdd_clicked();
void on_audioRemove_clicked();
void on_audioUp_clicked();
void on_audioDown_clicked();
void on_audioFallback_toggled(bool on);
void on_videoAdd_clicked();
void on_videoRemove_clicked();
void on_videoUp_clicked();
void on_videoDown_clicked();
void on_getScreenshot_clicked();
void on_serverSettings_toggled(bool on);
void on_serverPort_valueChanged(int value);
void on_lockToIPv4_stateChanged(int state);
void on_serverRestart_clicked();
void updateServerStatus();
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();
void on_sceneGroupAdd_clicked();
void on_sceneGroupRemove_clicked();
void on_sceneGroupUp_clicked();
void on_sceneGroupDown_clicked();
void on_sceneGroupName_editingFinished();
void on_sceneGroups_currentRowChanged(int idx);
void on_sceneGroupSceneAdd_clicked();
void on_sceneGroupSceneRemove_clicked();
void on_sceneGroupSceneUp_clicked();
void on_sceneGroupSceneDown_clicked();
void on_triggerAdd_clicked();
void on_triggerRemove_clicked();
void on_triggerUp_clicked();
void on_triggerDown_clicked();
void on_priorityUp_clicked();
void on_priorityDown_clicked();
void on_threadPriority_currentTextChanged(const QString &text);
void updateScreenRegionCursorPos();
private:
bool MacroTabIsInFocus();
@@ -173,209 +318,29 @@ private:
MacroSection lastInteracted = MacroSection::CONDITIONS;
int currentConditionIdx = -1;
int currentActionIdx = -1;
/* --- End of macro tab section --- */
/* --- Begin of legacy tab section --- */
public:
void ClearFrames(QListWidget *list);
int IgnoreWindowsFindByData(const QString &window);
int IgnoreIdleWindowsFindByData(const QString &window);
void OpenSequenceExtendEdit(SequenceWidget *sw);
// Window tab
public:
void SetupTitleTab();
public slots:
void on_windowUp_clicked();
void on_windowDown_clicked();
void on_windowAdd_clicked();
void on_windowRemove_clicked();
void on_ignoreWindows_currentRowChanged(int idx);
void on_ignoreWindowsAdd_clicked();
void on_ignoreWindowsRemove_clicked();
// Screen region tab
public:
void SetupRegionTab();
public slots:
void SetShowFrames();
void SetHideFrames();
void on_screenRegionSwitches_currentRowChanged(int idx);
void on_showFrame_clicked();
void on_screenRegionAdd_clicked();
void on_screenRegionRemove_clicked();
void on_screenRegionUp_clicked();
void on_screenRegionDown_clicked();
void updateScreenRegionCursorPos();
// Pause tab
public:
void SetupPauseTab();
public slots:
void on_pauseUp_clicked();
void on_pauseDown_clicked();
void on_pauseAdd_clicked();
void on_pauseRemove_clicked();
// Sequence tab
public:
void SetupSequenceTab();
public slots:
void on_sceneSequenceAdd_clicked();
void on_sceneSequenceRemove_clicked();
void on_sceneSequenceUp_clicked();
void on_sceneSequenceDown_clicked();
void on_sceneSequenceSave_clicked();
void on_sceneSequenceLoad_clicked();
void on_sequenceEdit_clicked();
void on_sceneSequenceSwitches_itemDoubleClicked(QListWidgetItem *item);
// Transition tab
public:
void SetupTransitionsTab();
public slots:
void on_transitionsAdd_clicked();
void on_transitionsRemove_clicked();
void on_transitionsUp_clicked();
void on_transitionsDown_clicked();
void on_defaultTransitionsAdd_clicked();
void on_defaultTransitionsRemove_clicked();
void on_defaultTransitionsUp_clicked();
void on_defaultTransitionsDown_clicked();
void on_transitionOverridecheckBox_stateChanged(int state);
void on_adjustActiveTransitionType_stateChanged(int state);
void DefTransitionDelayValueChanged(int value);
// Executable tab
public:
void SetupExecutableTab();
public slots:
void on_executableUp_clicked();
void on_executableDown_clicked();
void on_executableAdd_clicked();
void on_executableRemove_clicked();
// Idle tab
public:
void SetupIdleTab();
public slots:
void on_idleCheckBox_stateChanged(int state);
void on_ignoreIdleWindows_currentRowChanged(int idx);
void on_ignoreIdleAdd_clicked();
void on_ignoreIdleRemove_clicked();
// Random tab
public:
void SetupRandomTab();
public slots:
void on_randomAdd_clicked();
void on_randomRemove_clicked();
// File tab
public:
void SetupFileTab();
public slots:
void on_fileAdd_clicked();
void on_fileRemove_clicked();
void on_fileSwitches_currentRowChanged(int idx);
void on_fileUp_clicked();
void on_fileDown_clicked();
void on_browseButton_clicked();
void on_readFileCheckBox_stateChanged(int state);
void on_readPathLineEdit_textChanged(const QString &text);
void on_writePathLineEdit_textChanged(const QString &text);
void on_browseButton_2_clicked();
// Media tab
public:
void SetupMediaTab();
public slots:
void on_mediaAdd_clicked();
void on_mediaRemove_clicked();
void on_mediaUp_clicked();
void on_mediaDown_clicked();
// Time tab
public:
void SetupTimeTab();
public slots:
void on_timeAdd_clicked();
void on_timeRemove_clicked();
void on_timeUp_clicked();
void on_timeDown_clicked();
// Video tab
public:
void SetupAudioTab();
public slots:
void on_audioAdd_clicked();
void on_audioRemove_clicked();
void on_audioUp_clicked();
void on_audioDown_clicked();
void on_audioFallback_toggled(bool on);
// Video tab
public:
void SetupVideoTab();
public slots:
void on_videoAdd_clicked();
void on_videoRemove_clicked();
void on_videoUp_clicked();
void on_videoDown_clicked();
void on_getScreenshot_clicked();
// Scene group tab
public:
void SetupNetworkTab();
public slots:
void on_serverSettings_toggled(bool on);
void on_serverPort_valueChanged(int value);
void on_lockToIPv4_stateChanged(int state);
void on_serverRestart_clicked();
void UpdateServerStatus();
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();
// Scene group tab
public:
void SetupSceneGroupTab();
void SetEditSceneGroup(SceneGroup &sg);
public slots:
void on_sceneGroupAdd_clicked();
void on_sceneGroupRemove_clicked();
void on_sceneGroupUp_clicked();
void on_sceneGroupDown_clicked();
void on_sceneGroupName_editingFinished();
void on_sceneGroups_currentRowChanged(int idx);
void on_sceneGroupSceneAdd_clicked();
void on_sceneGroupSceneRemove_clicked();
void on_sceneGroupSceneUp_clicked();
void on_sceneGroupSceneDown_clicked();
signals:
void SceneGroupAdded(const QString &name);
void SceneGroupRemoved(const QString &name);
void SceneGroupRenamed(const QString &oldName, const QString newName);
// Trigger tab
public:
void SetupTriggerTab();
public slots:
void on_triggerAdd_clicked();
void on_triggerRemove_clicked();
void on_triggerUp_clicked();
void on_triggerDown_clicked();
/* --- End of legacy tab section --- */
};
void OpenSettingsWindow();
} // namespace advss
/******************************************************************************
* Sceneswitch helper
******************************************************************************/
void setNextTransition(const sceneSwitchInfo &ssi, obs_source_t *currentSource,
transitionData &td);
void overwriteTransitionOverride(const sceneSwitchInfo &ssi,
transitionData &td);
void restoreTransitionOverride(obs_source_t *scene, const transitionData &td);
void switchScene(const sceneSwitchInfo &ssi, bool force = false);
void switchPreviewScene(const OBSWeakSource &ws);
/******************************************************************************
* Settings helper
******************************************************************************/
void AskForBackup(obs_data_t *obj);
/******************************************************************************
* Main SwitcherData
******************************************************************************/
struct SwitcherData;
extern SwitcherData *switcher;
SwitcherData *GetSwitcher();

View File

@@ -1,13 +1,11 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "status-control.hpp"
#include "file-selection.hpp"
#include "utility.hpp"
#include "version.h"
#include <QFileDialog>
namespace advss {
#include <QStandardPaths>
void AdvSceneSwitcher::reject()
{
@@ -32,7 +30,7 @@ void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = SwitcherData::NoMatch::NO_SWITCH;
switcher->switchIfNotMatching = NO_SWITCH;
ui->noMatchSwitchScene->setEnabled(false);
ui->randomDisabledWarning->setVisible(true);
}
@@ -44,7 +42,7 @@ void AdvSceneSwitcher::on_noMatchSwitch_clicked()
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = SwitcherData::NoMatch::SWITCH;
switcher->switchIfNotMatching = SWITCH;
ui->noMatchSwitchScene->setEnabled(true);
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
ui->randomDisabledWarning->setVisible(true);
@@ -57,29 +55,49 @@ void AdvSceneSwitcher::on_noMatchRandomSwitch_clicked()
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = SwitcherData::NoMatch::RANDOM_SWITCH;
switcher->switchIfNotMatching = RANDOM_SWITCH;
ui->noMatchSwitchScene->setEnabled(false);
ui->randomDisabledWarning->setVisible(false);
}
void AdvSceneSwitcher::NoMatchDelayDurationChanged(const Duration &dur)
void AdvSceneSwitcher::NoMatchDelayDurationChanged(double sec)
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->noMatchDelay = dur;
switcher->noMatchDelay.seconds = sec;
}
void AdvSceneSwitcher::CooldownDurationChanged(const Duration &dur)
void AdvSceneSwitcher::NoMatchDelayUnitChanged(DurationUnit unit)
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->cooldown = dur;
switcher->noMatchDelay.displayUnit = unit;
}
void AdvSceneSwitcher::CooldownDurationChanged(double sec)
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->cooldown.seconds = sec;
}
void AdvSceneSwitcher::CooldownUnitChanged(DurationUnit unit)
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->cooldown.displayUnit = unit;
}
void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
@@ -89,8 +107,7 @@ void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->startupBehavior =
static_cast<SwitcherData::StartupBehavior>(index);
switcher->startupBehavior = (StartupBehavior)index;
}
void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
@@ -100,7 +117,7 @@ void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->autoStartEvent = static_cast<SwitcherData::AutoStart>(index);
switcher->autoStartEvent = static_cast<AutoStartEvent>(index);
}
void AdvSceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
@@ -175,16 +192,7 @@ void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
switcher->disableHints = state;
}
void AdvSceneSwitcher::on_warnPluginLoadFailure_stateChanged(int state)
{
if (loading) {
return;
}
switcher->warnPluginLoadFailure = state;
}
static bool isLegacyTab(const QString &name)
bool isLegacyTab(const QString &name)
{
return name == obs_module_text(
"AdvSceneSwitcher.sceneGroupTab.title") ||
@@ -229,7 +237,7 @@ void AdvSceneSwitcher::on_hideLegacyTabs_stateChanged(int state)
}
}
void AdvSceneSwitcher::SetDeprecationWarnings()
void AdvSceneSwitcher::setDeprecationWarnings()
{
QString toolTip =
switcher->disableHints
@@ -243,13 +251,70 @@ void AdvSceneSwitcher::SetDeprecationWarnings()
}
}
QString getDefaultSaveLocation()
{
QString desktopPath = QStandardPaths::writableLocation(
QStandardPaths::DesktopLocation);
auto scName = obs_frontend_get_current_scene_collection();
QString sceneCollectionName(scName);
bfree(scName);
auto timestamp = QDateTime::currentDateTime();
auto path = desktopPath + "/adv-ss-" + sceneCollectionName + "-" +
timestamp.toString("yyyy.MM.dd.hh.mm.ss");
// Check if scene collection name contains invalid path characters
QFile file(path);
if (file.exists()) {
return path;
}
bool validPath = file.open(QIODevice::WriteOnly);
if (validPath) {
file.remove();
return path;
}
return desktopPath + "/adv-ss-" +
timestamp.toString("yyyy.MM.dd.hh.mm.ss");
}
void AskForBackup(obs_data_t *obj)
{
bool backupSettings = DisplayMessage(
obs_module_text("AdvSceneSwitcher.askBackup"), true);
if (!backupSettings) {
return;
}
QString path = QFileDialog::getSaveFileName(
nullptr,
obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle"),
getDefaultSaveLocation(),
obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType"));
if (path.isEmpty()) {
return;
}
QFile file(path);
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(
this,
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle")),
GetDefaultSettingsSaveLocation(),
getDefaultSaveLocation(),
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType")));
if (directory.isEmpty()) {
@@ -262,7 +327,7 @@ void AdvSceneSwitcher::on_exportSettings_clicked()
}
obs_data_t *obj = obs_data_create();
switcher->SaveSettings(obj);
switcher->saveSettings(obj);
obs_data_save_json(obj, file.fileName().toUtf8().constData());
obs_data_release(obj);
}
@@ -302,7 +367,7 @@ void AdvSceneSwitcher::on_importSettings_clicked()
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->LoadSettings(obj);
switcher->loadSettings(obj);
obs_data_release(obj);
switcher->lastImportPath = path.toStdString();
@@ -318,7 +383,7 @@ void AdvSceneSwitcher::on_importSettings_clicked()
}
}
static int findTabIndex(QTabWidget *tabWidget, int pos)
int findTabIndex(QTabWidget *tabWidget, int pos)
{
int at = -1;
@@ -392,10 +457,10 @@ static int findTabIndex(QTabWidget *tabWidget, int pos)
return at;
}
void AdvSceneSwitcher::SetTabOrder()
void AdvSceneSwitcher::setTabOrder()
{
if (!switcher->TabOrderValid()) {
switcher->ResetTabOrder();
if (!switcher->tabOrderValid()) {
switcher->resetTabOrder();
}
QTabBar *bar = ui->tabWidget->tabBar();
@@ -410,22 +475,22 @@ void AdvSceneSwitcher::SetTabOrder()
connect(bar, &QTabBar::tabMoved, this, &AdvSceneSwitcher::on_tabMoved);
}
void AdvSceneSwitcher::SetCurrentTab()
void AdvSceneSwitcher::setCurrentTab()
{
if (switcher->lastOpenedTab >= 0) {
ui->tabWidget->setCurrentIndex(switcher->lastOpenedTab);
}
}
void AdvSceneSwitcher::RestoreWindowGeo()
void AdvSceneSwitcher::restoreWindowGeo()
{
if (switcher->saveWindowGeo && WindowPosValid(switcher->windowPos)) {
if (switcher->saveWindowGeo && windowPosValid(switcher->windowPos)) {
this->resize(switcher->windowSize);
this->move(switcher->windowPos);
}
}
void AdvSceneSwitcher::CheckFirstTimeSetup()
void AdvSceneSwitcher::checkFirstTimeSetup()
{
if (switcher->firstBoot && !switcher->disableHints) {
switcher->firstBoot = false;
@@ -446,7 +511,7 @@ void AdvSceneSwitcher::on_tabMoved(int from, int to)
void AdvSceneSwitcher::on_tabWidget_currentChanged(int)
{
switcher->showFrame = false;
ClearFrames(ui->screenRegionSwitches);
clearFrames(ui->screenRegionSwitches);
SetShowFrames();
}
@@ -483,7 +548,7 @@ void AdvSceneSwitcher::on_adjustActiveTransitionType_stateChanged(int state)
switcher->adjustActiveTransitionType = state;
}
void SwitcherData::LoadSettings(obs_data_t *obj)
void SwitcherData::loadSettings(obs_data_t *obj)
{
if (!obj) {
return;
@@ -492,9 +557,9 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
// Needs to be loaded before any entries which might rely on scene group
// selections to be available.
loadSceneGroups(obj);
LoadVariables(obj);
LoadConnections(obj);
LoadMacros(obj);
loadVariables(obj);
loadMacros(obj);
loadConnections(obj);
loadWindowTitleSwitches(obj);
loadScreenRegionSwitches(obj);
loadPauseSwitches(obj);
@@ -510,24 +575,24 @@ void SwitcherData::LoadSettings(obs_data_t *obj)
loadVideoSwitches(obj);
loadNetworkSettings(obj);
loadSceneTriggers(obj);
LoadGeneralSettings(obj);
LoadHotkeys(obj);
LoadUISettings(obj);
loadGeneralSettings(obj);
loadHotkeys(obj);
loadUISettings(obj);
// Reset on startup and scene collection change
switcher->lastOpenedTab = -1;
}
void SwitcherData::SaveSettings(obs_data_t *obj)
void SwitcherData::saveSettings(obs_data_t *obj)
{
if (!obj) {
return;
}
saveSceneGroups(obj);
SaveMacros(obj);
SaveConnections(obj);
SaveVariables(obj);
saveMacros(obj);
saveConnections(obj);
saveVariables(obj);
saveWindowTitleSwitches(obj);
saveScreenRegionSwitches(obj);
savePauseSwitches(obj);
@@ -543,29 +608,27 @@ void SwitcherData::SaveSettings(obs_data_t *obj)
saveVideoSwitches(obj);
saveNetworkSwitches(obj);
saveSceneTriggers(obj);
SaveGeneralSettings(obj);
SaveHotkeys(obj);
SaveUISettings(obj);
SaveVersion(obj, g_GIT_SHA1);
saveGeneralSettings(obj);
saveHotkeys(obj);
saveUISettings(obj);
saveVersion(obj, g_GIT_SHA1);
}
void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
void SwitcherData::saveGeneralSettings(obs_data_t *obj)
{
obs_data_set_int(obj, "interval", interval);
std::string nonMatchingSceneName = GetWeakSourceName(nonMatchingScene);
obs_data_set_string(obj, "non_matching_scene",
nonMatchingSceneName.c_str());
obs_data_set_int(obj, "switch_if_not_matching",
static_cast<int>(switchIfNotMatching));
noMatchDelay.Save(obj, "noMatchDelay");
obs_data_set_int(obj, "switch_if_not_matching", switchIfNotMatching);
noMatchDelay.Save(obj, "noMatchDelay", "noMatchDelayUnit");
cooldown.Save(obj, "cooldown");
cooldown.Save(obj, "cooldown", "cooldownUnit");
obs_data_set_bool(obj, "active", sceneColletionStop ? true : !stop);
sceneColletionStop = false;
obs_data_set_int(obj, "startup_behavior",
static_cast<int>(startupBehavior));
obs_data_set_int(obj, "startup_behavior", startupBehavior);
obs_data_set_int(obj, "autoStartEvent",
static_cast<int>(autoStartEvent));
@@ -574,10 +637,19 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
obs_data_set_bool(obj, "showSystemTrayNotifications",
showSystemTrayNotifications);
obs_data_set_bool(obj, "disableHints", disableHints);
obs_data_set_bool(obj, "warnPluginLoadFailure", warnPluginLoadFailure);
obs_data_set_bool(obj, "hideLegacyTabs", hideLegacyTabs);
SaveFunctionPriorities(obj, functionNamesByPriority);
obs_data_set_int(obj, "priority0", functionNamesByPriority[0]);
obs_data_set_int(obj, "priority1", functionNamesByPriority[1]);
obs_data_set_int(obj, "priority2", functionNamesByPriority[2]);
obs_data_set_int(obj, "priority3", functionNamesByPriority[3]);
obs_data_set_int(obj, "priority4", functionNamesByPriority[4]);
obs_data_set_int(obj, "priority5", functionNamesByPriority[5]);
obs_data_set_int(obj, "priority6", functionNamesByPriority[6]);
obs_data_set_int(obj, "priority7", functionNamesByPriority[7]);
obs_data_set_int(obj, "priority8", functionNamesByPriority[8]);
obs_data_set_int(obj, "priority9", functionNamesByPriority[9]);
obs_data_set_int(obj, "priority10", functionNamesByPriority[10]);
obs_data_set_int(obj, "threadPriority", threadPriority);
@@ -589,56 +661,88 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
obs_data_set_string(obj, "lastImportPath", lastImportPath.c_str());
}
void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
void SwitcherData::loadGeneralSettings(obs_data_t *obj)
{
obs_data_set_default_int(obj, "interval", default_interval);
interval = obs_data_get_int(obj, "interval");
obs_data_set_default_int(obj, "switch_if_not_matching",
static_cast<int>(NoMatch::NO_SWITCH));
obs_data_set_default_int(obj, "switch_if_not_matching", NO_SWITCH);
switchIfNotMatching =
(NoMatch)obs_data_get_int(obj, "switch_if_not_matching");
std::string nonMatchingSceneName =
obs_data_get_string(obj, "non_matching_scene");
nonMatchingScene = GetWeakSourceByName(nonMatchingSceneName.c_str());
noMatchDelay.Load(obj, "noMatchDelay");
noMatchDelay.Load(obj, "noMatchDelay", "noMatchDelayUnit");
cooldown.Load(obj, "cooldown");
cooldown.Load(obj, "cooldown", "cooldownUnit");
stop = !obs_data_get_bool(obj, "active");
startupBehavior =
(StartupBehavior)obs_data_get_int(obj, "startup_behavior");
if (startupBehavior == StartupBehavior::START) {
if (startupBehavior == START) {
stop = false;
}
if (startupBehavior == StartupBehavior::STOP) {
if (startupBehavior == STOP) {
stop = true;
}
autoStartEvent =
static_cast<AutoStart>(obs_data_get_int(obj, "autoStartEvent"));
autoStartEvent = static_cast<AutoStartEvent>(
obs_data_get_int(obj, "autoStartEvent"));
verbose = obs_data_get_bool(obj, "verbose");
showSystemTrayNotifications =
obs_data_get_bool(obj, "showSystemTrayNotifications");
disableHints = obs_data_get_bool(obj, "disableHints");
obs_data_set_default_bool(obj, "warnPluginLoadFailure", true);
warnPluginLoadFailure = obs_data_get_bool(obj, "warnPluginLoadFailure");
obs_data_set_default_bool(obj, "hideLegacyTabs", true);
hideLegacyTabs = obs_data_get_bool(obj, "hideLegacyTabs");
SetDefaultFunctionPriorities(obj);
LoadFunctionPriorities(obj, functionNamesByPriority);
if (!PrioFuncsValid()) {
functionNamesByPriority = GetDefaultFunctionPriorityList();
obs_data_set_default_int(obj, "priority0", default_priority_0);
obs_data_set_default_int(obj, "priority1", default_priority_1);
obs_data_set_default_int(obj, "priority2", default_priority_2);
obs_data_set_default_int(obj, "priority3", default_priority_3);
obs_data_set_default_int(obj, "priority4", default_priority_4);
obs_data_set_default_int(obj, "priority5", default_priority_5);
obs_data_set_default_int(obj, "priority6", default_priority_6);
obs_data_set_default_int(obj, "priority7", default_priority_7);
obs_data_set_default_int(obj, "priority8", default_priority_8);
functionNamesByPriority[0] = (obs_data_get_int(obj, "priority0"));
functionNamesByPriority[1] = (obs_data_get_int(obj, "priority1"));
functionNamesByPriority[2] = (obs_data_get_int(obj, "priority2"));
functionNamesByPriority[3] = (obs_data_get_int(obj, "priority3"));
functionNamesByPriority[4] = (obs_data_get_int(obj, "priority4"));
functionNamesByPriority[5] = (obs_data_get_int(obj, "priority5"));
functionNamesByPriority[6] = (obs_data_get_int(obj, "priority6"));
functionNamesByPriority[7] = (obs_data_get_int(obj, "priority7"));
functionNamesByPriority[8] = (obs_data_get_int(obj, "priority8"));
functionNamesByPriority[9] = (obs_data_get_int(obj, "priority9"));
functionNamesByPriority[10] = (obs_data_get_int(obj, "priority10"));
if (!prioFuncsValid()) {
functionNamesByPriority[0] = (default_priority_0);
functionNamesByPriority[1] = (default_priority_1);
functionNamesByPriority[2] = (default_priority_2);
functionNamesByPriority[3] = (default_priority_3);
functionNamesByPriority[4] = (default_priority_4);
functionNamesByPriority[5] = (default_priority_5);
functionNamesByPriority[6] = (default_priority_6);
functionNamesByPriority[7] = (default_priority_7);
functionNamesByPriority[8] = (default_priority_8);
functionNamesByPriority[9] = (default_priority_9);
functionNamesByPriority[10] = (default_priority_10);
}
obs_data_set_default_int(obj, "threadPriority",
QThread::NormalPriority);
threadPriority = obs_data_get_int(obj, "threadPriority");
transitionOverrideOverride =
obs_data_get_bool(obj, "transitionOverrideOverride");
// TODO: Remove this fallback in future version
if (obs_data_has_user_value(obj, "tansitionOverrideOverride")) {
transitionOverrideOverride =
obs_data_get_bool(obj, "tansitionOverrideOverride");
} else {
transitionOverrideOverride =
obs_data_get_bool(obj, "transitionOverrideOverride");
}
adjustActiveTransitionType =
obs_data_get_bool(obj, "adjustActiveTransitionType");
@@ -651,8 +755,7 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
lastImportPath = obs_data_get_string(obj, "lastImportPath");
}
static void saveSplitterPos(QList<int> &sizes, obs_data_t *obj,
const std::string name)
void saveSplitterPos(QList<int> &sizes, obs_data_t *obj, const std::string name)
{
auto array = obs_data_array_create();
for (int i = 0; i < sizes.count(); ++i) {
@@ -665,8 +768,7 @@ static void saveSplitterPos(QList<int> &sizes, obs_data_t *obj,
obs_data_array_release(array);
}
static void loadSplitterPos(QList<int> &sizes, obs_data_t *obj,
const std::string name)
void loadSplitterPos(QList<int> &sizes, obs_data_t *obj, const std::string name)
{
sizes.clear();
obs_data_array_t *array = obs_data_get_array(obj, name.c_str());
@@ -679,7 +781,7 @@ static void loadSplitterPos(QList<int> &sizes, obs_data_t *obj,
obs_data_array_release(array);
}
void SwitcherData::SaveUISettings(obs_data_t *obj)
void SwitcherData::saveUISettings(obs_data_t *obj)
{
obs_data_set_int(obj, "generalTabPos", tabOrder[0]);
obs_data_set_int(obj, "macroTabPos", tabOrder[1]);
@@ -712,7 +814,7 @@ void SwitcherData::SaveUISettings(obs_data_t *obj)
"macroListMacroEditSplitterPosition");
}
void SwitcherData::LoadUISettings(obs_data_t *obj)
void SwitcherData::loadUISettings(obs_data_t *obj)
{
obs_data_set_default_int(obj, "generalTabPos", 0);
obs_data_set_default_int(obj, "macroTabPos", 1);
@@ -753,8 +855,8 @@ void SwitcherData::LoadUISettings(obs_data_t *obj)
tabOrder.emplace_back((int)(obs_data_get_int(obj, "sceneGroupTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "triggerTabPos")));
if (!TabOrderValid()) {
ResetTabOrder();
if (!tabOrderValid()) {
resetTabOrder();
}
saveWindowGeo = obs_data_get_bool(obj, "saveWindowGeo");
@@ -768,7 +870,7 @@ void SwitcherData::LoadUISettings(obs_data_t *obj)
"macroListMacroEditSplitterPosition");
}
bool SwitcherData::TabOrderValid()
bool SwitcherData::tabOrderValid()
{
auto tmp = std::vector<int>(tab_count);
std::iota(tmp.begin(), tmp.end(), 0);
@@ -782,13 +884,13 @@ bool SwitcherData::TabOrderValid()
return true;
}
void SwitcherData::ResetTabOrder()
void SwitcherData::resetTabOrder()
{
tabOrder = std::vector<int>(tab_count);
std::iota(tabOrder.begin(), tabOrder.end(), 0);
}
void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
void SwitcherData::checkNoMatchSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition, int &sleep)
{
if (match) {
@@ -800,12 +902,12 @@ void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
return;
}
if (switchIfNotMatching == NoMatch::SWITCH && nonMatchingScene) {
if (switchIfNotMatching == SWITCH && nonMatchingScene) {
match = true;
scene = nonMatchingScene;
transition = nullptr;
}
if (switchIfNotMatching == NoMatch::RANDOM_SWITCH) {
if (switchIfNotMatching == RANDOM_SWITCH) {
match = checkRandom(scene, transition, sleep);
}
}
@@ -824,7 +926,7 @@ void SwitcherData::checkSwitchCooldown(bool &match)
}
}
static void populateStartupBehavior(QComboBox *cb)
void populateStartupBehavior(QComboBox *cb)
{
cb->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.onStartup.asLastRun"));
@@ -834,7 +936,7 @@ static void populateStartupBehavior(QComboBox *cb)
"AdvSceneSwitcher.generalTab.status.onStartup.doNotStart"));
}
static void populateAutoStartEventSelection(QComboBox *cb)
void populateAutoStartEventSelection(QComboBox *cb)
{
cb->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.autoStart.never"));
@@ -846,8 +948,53 @@ static void populateAutoStartEventSelection(QComboBox *cb)
"AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming"));
}
static void populatePriorityFunctionList(QListWidget *list)
void AdvSceneSwitcher::setupGeneralTab()
{
populateSceneSelection(ui->noMatchSwitchScene, false);
if (switcher->switchIfNotMatching == SWITCH) {
ui->noMatchSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(true);
} else if (switcher->switchIfNotMatching == NO_SWITCH) {
ui->noMatchDontSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(false);
} else {
ui->noMatchRandomSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(false);
}
ui->noMatchSwitchScene->setCurrentText(
GetWeakSourceName(switcher->nonMatchingScene).c_str());
DurationSelection *noMatchDelay = new DurationSelection();
noMatchDelay->SetDuration(switcher->noMatchDelay);
noMatchDelay->setToolTip(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip"));
ui->noMatchLayout->addWidget(noMatchDelay);
QWidget::connect(noMatchDelay, SIGNAL(DurationChanged(double)), this,
SLOT(NoMatchDelayDurationChanged(double)));
QWidget::connect(noMatchDelay, SIGNAL(UnitChanged(DurationUnit)), this,
SLOT(NoMatchDelayUnitChanged(DurationUnit)));
ui->checkInterval->setValue(switcher->interval);
DurationSelection *cooldownTime = new DurationSelection();
cooldownTime->SetDuration(switcher->cooldown);
cooldownTime->setToolTip(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint"));
ui->cooldownLayout->addWidget(cooldownTime);
ui->cooldownLayout->addStretch();
QWidget::connect(cooldownTime, SIGNAL(DurationChanged(double)), this,
SLOT(CooldownDurationChanged(double)));
QWidget::connect(cooldownTime, SIGNAL(UnitChanged(DurationUnit)), this,
SLOT(CooldownUnitChanged(DurationUnit)));
ui->verboseLogging->setChecked(switcher->verbose);
ui->saveWindowGeo->setChecked(switcher->saveWindowGeo);
ui->showTrayNotifications->setChecked(
switcher->showSystemTrayNotifications);
ui->uiHintsDisable->setChecked(switcher->disableHints);
ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs);
for (int p : switcher->functionNamesByPriority) {
std::string s = "";
switch (p) {
@@ -897,114 +1044,26 @@ static void populatePriorityFunctionList(QListWidget *list)
break;
}
QString text(s.c_str());
QListWidgetItem *item = new QListWidgetItem(text, list);
QListWidgetItem *item =
new QListWidgetItem(text, ui->priorityList);
item->setData(Qt::UserRole, text);
}
}
static void populateThreadPriorityList(QComboBox *list)
{
for (int i = 0; i < (int)switcher->threadPriorities.size(); ++i) {
list->addItem(switcher->threadPriorities[i].name.c_str());
list->setItemData(
ui->threadPriority->addItem(
switcher->threadPriorities[i].name.c_str());
ui->threadPriority->setItemData(
i, switcher->threadPriorities[i].description.c_str(),
Qt::ToolTipRole);
if (switcher->threadPriority ==
switcher->threadPriorities[i].value) {
list->setCurrentText(
ui->threadPriority->setCurrentText(
switcher->threadPriorities[i].name.c_str());
}
}
}
static bool isGeneralTab(const QString &name)
{
return name == obs_module_text("AdvSceneSwitcher.generalTab.title");
}
static int getGeneralTabIdx(QTabWidget *tabWidget)
{
for (int idx = 0; idx < tabWidget->count(); idx++) {
if (isGeneralTab(tabWidget->tabText(idx))) {
return idx;
}
}
return -1;
}
static void setupGeneralTabInactiveWarning(QTabWidget *tabs)
{
auto callback = [tabs]() {
const bool isRunning = switcher && switcher->th &&
switcher->th->isRunning();
auto idx = getGeneralTabIdx(tabs);
tabs->setTabIcon(
idx,
isRunning ? QIcon()
: QIcon::fromTheme(
"obs",
QIcon(":/res/images/warning.svg")));
};
auto inactiveTimer = new QTimer(tabs);
inactiveTimer->setInterval(1000);
QObject::connect(inactiveTimer, &QTimer::timeout, callback);
inactiveTimer->start();
}
void AdvSceneSwitcher::SetupGeneralTab()
{
PopulateSceneSelection(ui->noMatchSwitchScene, false);
if (switcher->switchIfNotMatching == SwitcherData::NoMatch::SWITCH) {
ui->noMatchSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(true);
} else if (switcher->switchIfNotMatching ==
SwitcherData::NoMatch::NO_SWITCH) {
ui->noMatchDontSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(false);
} else {
ui->noMatchRandomSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(false);
}
ui->noMatchSwitchScene->setCurrentText(
GetWeakSourceName(switcher->nonMatchingScene).c_str());
DurationSelection *noMatchDelay = new DurationSelection();
noMatchDelay->SetDuration(switcher->noMatchDelay);
noMatchDelay->setToolTip(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip"));
ui->noMatchLayout->addWidget(noMatchDelay);
QWidget::connect(noMatchDelay,
SIGNAL(DurationChanged(const Duration &)), this,
SLOT(NoMatchDelayDurationChanged(const Duration &)));
ui->checkInterval->setValue(switcher->interval);
DurationSelection *cooldownTime = new DurationSelection();
cooldownTime->SetDuration(switcher->cooldown);
cooldownTime->setToolTip(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint"));
ui->cooldownLayout->addWidget(cooldownTime);
ui->cooldownLayout->addStretch();
QWidget::connect(cooldownTime,
SIGNAL(DurationChanged(const Duration &)), this,
SLOT(CooldownDurationChanged(const Duration &)));
ui->verboseLogging->setChecked(switcher->verbose);
ui->saveWindowGeo->setChecked(switcher->saveWindowGeo);
ui->showTrayNotifications->setChecked(
switcher->showSystemTrayNotifications);
ui->uiHintsDisable->setChecked(switcher->disableHints);
ui->warnPluginLoadFailure->setChecked(switcher->warnPluginLoadFailure);
ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs);
populatePriorityFunctionList(ui->priorityList);
populateThreadPriorityList(ui->threadPriority);
populateStartupBehavior(ui->startupBehavior);
ui->startupBehavior->setCurrentIndex(
static_cast<int>(switcher->startupBehavior));
ui->startupBehavior->setCurrentIndex(switcher->startupBehavior);
populateAutoStartEventSelection(ui->autoStartEvent);
ui->autoStartEvent->setCurrentIndex(
@@ -1021,10 +1080,6 @@ void AdvSceneSwitcher::SetupGeneralTab()
// Hide the now empty invisible shell of the statusControl widget
// as otherwise it could block user input
statusControl->hide();
setupGeneralTabInactiveWarning(ui->tabWidget);
MinimizeSizeOfColumn(ui->statusLayout, 0);
setWindowTitle(windowTitle() + " - " + g_GIT_TAG);
}
} // namespace advss

View File

@@ -1,12 +1,9 @@
#include "hotkey.hpp"
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include <obs-module.h>
#include <fstream>
#include <regex>
namespace advss {
std::vector<std::weak_ptr<Hotkey>> Hotkey::_registeredHotkeys = {};
uint32_t Hotkey::_hotkeyCounter = 1;
@@ -120,7 +117,7 @@ void Hotkey::ClearAllHotkeys()
_registeredHotkeys.clear();
}
static void startHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
void startHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
{
if (pressed) {
if (!(switcher->th && switcher->th->isRunning())) {
@@ -129,7 +126,7 @@ static void startHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
}
}
static void stopHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
void stopHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
{
if (pressed) {
if (switcher->th && switcher->th->isRunning()) {
@@ -138,8 +135,8 @@ static void stopHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
}
}
static void startStopToggleHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
bool pressed)
void startStopToggleHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
bool pressed)
{
if (pressed) {
if (switcher->th && switcher->th->isRunning()) {
@@ -150,8 +147,8 @@ static void startStopToggleHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
}
}
static void upMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
bool pressed)
void upMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
bool pressed)
{
if (pressed && switcher->settingsWindowOpened &&
AdvSceneSwitcher::window) {
@@ -161,8 +158,8 @@ static void upMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
}
}
static void downMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
bool pressed)
void downMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
bool pressed)
{
if (pressed && switcher->settingsWindowOpened &&
AdvSceneSwitcher::window) {
@@ -172,8 +169,8 @@ static void downMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
}
}
static void removeMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
bool pressed)
void removeMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
bool pressed)
{
if (pressed && switcher->settingsWindowOpened &&
AdvSceneSwitcher::window) {
@@ -183,7 +180,7 @@ static void removeMacroSegmentHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
}
}
static void registerHotkeys()
void registerHotkeys()
{
switcher->startHotkey = obs_hotkey_register_frontend(
"startSwitcherHotkey",
@@ -216,14 +213,14 @@ static void registerHotkeys()
switcher->hotkeysRegistered = true;
}
static void saveHotkey(obs_data_t *obj, obs_hotkey_id id, const char *name)
void saveHotkey(obs_data_t *obj, obs_hotkey_id id, const char *name)
{
obs_data_array_t *a = obs_hotkey_save(id);
obs_data_set_array(obj, name, a);
obs_data_array_release(a);
}
void SwitcherData::SaveHotkeys(obs_data_t *obj)
void SwitcherData::saveHotkeys(obs_data_t *obj)
{
saveHotkey(obj, startHotkey, "startHotkey");
saveHotkey(obj, stopHotkey, "stopHotkey");
@@ -233,14 +230,14 @@ void SwitcherData::SaveHotkeys(obs_data_t *obj)
saveHotkey(obj, removeMacroSegment, "removeMacroSegmentHotkey");
}
static void loadHotkey(obs_data_t *obj, obs_hotkey_id id, const char *name)
void loadHotkey(obs_data_t *obj, obs_hotkey_id id, const char *name)
{
obs_data_array_t *a = obs_data_get_array(obj, name);
obs_hotkey_load(id, a);
obs_data_array_release(a);
}
void SwitcherData::LoadHotkeys(obs_data_t *obj)
void SwitcherData::loadHotkeys(obs_data_t *obj)
{
if (!hotkeysRegistered) {
registerHotkeys();
@@ -252,5 +249,3 @@ void SwitcherData::LoadHotkeys(obs_data_t *obj)
loadHotkey(obj, downMacroSegment, "downMacroSegmentHotkey");
loadHotkey(obj, removeMacroSegment, "removeMacroSegmentHotkey");
}
} // namespace advss

View File

@@ -5,8 +5,6 @@
#include <vector>
#include <chrono>
namespace advss {
extern bool canSimulateKeyPresses;
class Hotkey {
@@ -163,4 +161,4 @@ enum class HotkeyType {
Key_NumpadEnter
};
} // namespace advss
void registerHotkeys();

View File

@@ -1,10 +1,7 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include <thread>
namespace advss {
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
bool SceneTrigger::pause = false;
static QMetaObject::Connection addPulse;
@@ -159,7 +156,7 @@ void SceneTrigger::logMatch()
blog(LOG_INFO,
"scene '%s' in status '%s' triggering action '%s' after %f seconds",
GetWeakSourceName(scene).c_str(), statusName.c_str(),
actionName.c_str(), duration.Seconds());
actionName.c_str(), duration.seconds);
}
void frontEndActionThread(sceneTriggerAction action, double delay)
@@ -269,14 +266,14 @@ void SceneTrigger::performAction()
if (isFrontendAction(triggerAction)) {
t = std::thread(frontEndActionThread, triggerAction,
duration.Seconds());
duration.seconds);
} else if (isAudioAction(triggerAction)) {
bool mute = triggerAction == sceneTriggerAction::MUTE_SOURCE;
t = std::thread(muteThread, audioSource, duration.Seconds(),
t = std::thread(muteThread, audioSource, duration.seconds,
mute);
} else if (isSwitcherStatusAction(triggerAction)) {
bool stop = triggerAction == sceneTriggerAction::STOP_SWITCHER;
t = std::thread(statusThread, duration.Seconds(), stop);
t = std::thread(statusThread, duration.seconds, stop);
} else {
blog(LOG_WARNING, "ignoring unknown action '%d'",
static_cast<int>(triggerAction));
@@ -352,7 +349,7 @@ void SwitcherData::loadSceneTriggers(obs_data_t *obj)
obs_data_array_release(triggerArray);
}
void AdvSceneSwitcher::SetupTriggerTab()
void AdvSceneSwitcher::setupTriggerTab()
{
for (auto &s : switcher->sceneTriggers) {
QListWidgetItem *item;
@@ -401,7 +398,7 @@ void SceneTrigger::load(obs_data_t *obj)
static inline void populateTriggers(QComboBox *list)
{
AddSelectionEntry(
addSelectionEntry(
list,
obs_module_text(
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.none"));
@@ -416,7 +413,7 @@ static inline void populateTriggers(QComboBox *list)
inline void populateActions(QComboBox *list)
{
AddSelectionEntry(
addSelectionEntry(
list,
obs_module_text(
"AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.none"));
@@ -463,15 +460,17 @@ SceneTriggerWidget::SceneTriggerWidget(QWidget *parent, SceneTrigger *s)
SLOT(TriggerTypeChanged(int)));
QWidget::connect(actions, SIGNAL(currentIndexChanged(int)), this,
SLOT(TriggerActionChanged(int)));
QWidget::connect(duration, SIGNAL(DurationChanged(const Duration &)),
this, SLOT(DurationChanged(const Duration &)));
QWidget::connect(duration, SIGNAL(DurationChanged(double)), this,
SLOT(DurationChanged(double)));
QWidget::connect(duration, SIGNAL(UnitChanged(DurationUnit)), this,
SLOT(DurationUnitChanged(DurationUnit)));
QWidget::connect(audioSources,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(AudioSourceChanged(const QString &)));
populateTriggers(triggers);
populateActions(actions);
PopulateAudioSelection(audioSources);
populateAudioSelection(audioSources);
if (s) {
triggers->setCurrentIndex(static_cast<int>(s->triggerType));
@@ -495,7 +494,7 @@ SceneTriggerWidget::SceneTriggerWidget(QWidget *parent, SceneTrigger *s)
{"{{audioSources}}", audioSources},
{"{{duration}}", duration},
{"{{scenes}}", scenes}};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.sceneTriggerTab.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.sceneTriggerTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -553,14 +552,24 @@ void SceneTriggerWidget::TriggerActionChanged(int index)
}
}
void SceneTriggerWidget::DurationChanged(const Duration &duration)
void SceneTriggerWidget::DurationChanged(double seconds)
{
if (loading || !switchData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switchData->duration = duration;
switchData->duration.seconds = seconds;
}
void SceneTriggerWidget::DurationUnitChanged(DurationUnit unit)
{
if (loading || !switchData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switchData->duration.displayUnit = unit;
}
void SceneTriggerWidget::AudioSourceChanged(const QString &text)
@@ -572,5 +581,3 @@ void SceneTriggerWidget::AudioSourceChanged(const QString &text)
std::lock_guard<std::mutex> lock(switcher->m);
switchData->audioSource = GetWeakSourceByQString(text);
}
} // namespace advss

View File

@@ -10,8 +10,6 @@
#include "switch-generic.hpp"
#include "duration-control.hpp"
namespace advss {
enum class sceneTriggerType {
NONE = 0,
SCENE_ACTIVE = 1,
@@ -73,7 +71,8 @@ public:
private slots:
void TriggerTypeChanged(int index);
void TriggerActionChanged(int index);
void DurationChanged(const Duration &);
void DurationChanged(double seconds);
void DurationUnitChanged(DurationUnit unit);
void AudioSourceChanged(const QString &text);
private:
@@ -84,5 +83,3 @@ private:
SceneTrigger *switchData;
};
} // namespace advss

View File

@@ -1,11 +1,8 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "volume-control.hpp"
#include "utility.hpp"
#include <float.h>
namespace advss {
#include "advanced-scene-switcher.hpp"
#include "volume-control.hpp"
#include "utility.hpp"
bool AudioSwitch::pause = false;
static QMetaObject::Connection addPulse;
@@ -215,7 +212,7 @@ void SwitcherData::loadAudioSwitches(obs_data_t *obj)
audioFallback.load(obj);
}
void AdvSceneSwitcher::SetupAudioTab()
void AdvSceneSwitcher::setupAudioTab()
{
for (auto &s : switcher->audioSwitches) {
QListWidgetItem *item;
@@ -441,15 +438,15 @@ AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
SLOT(VolumeThresholdChanged(int)));
QWidget::connect(condition, SIGNAL(currentIndexChanged(int)), this,
SLOT(ConditionChanged(int)));
QWidget::connect(duration, SIGNAL(DurationChanged(const Duration &)),
this, SLOT(DurationChanged(const Duration &)));
QWidget::connect(duration, SIGNAL(DurationChanged(double)), this,
SLOT(DurationChanged(double)));
QWidget::connect(audioSources,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(SourceChanged(const QString &)));
QWidget::connect(ignoreInactiveSource, SIGNAL(stateChanged(int)), this,
SLOT(IgnoreInactiveChanged(int)));
PopulateAudioSelection(audioSources);
populateAudioSelection(audioSources);
populateConditionSelection(condition);
if (s) {
@@ -470,7 +467,7 @@ AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, AudioSwitch *s)
{"{{ignoreInactiveSource}}", ignoreInactiveSource},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.audioTab.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.audioTab.entry"),
switchLayout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
@@ -557,14 +554,14 @@ void AudioSwitchWidget::ConditionChanged(int cond)
switchData->condition = (audioCondition)cond;
}
void AudioSwitchWidget::DurationChanged(const Duration &dur)
void AudioSwitchWidget::DurationChanged(double sec)
{
if (loading || !switchData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switchData->duration = dur;
switchData->duration.seconds = sec;
}
void AudioSwitchWidget::IgnoreInactiveChanged(int state)
@@ -583,8 +580,8 @@ AudioSwitchFallbackWidget::AudioSwitchFallbackWidget(QWidget *parent,
{
duration = new DurationSelection(this, false);
QWidget::connect(duration, SIGNAL(DurationChanged(const Duration &)),
this, SLOT(DurationChanged(const Duration &)));
QWidget::connect(duration, SIGNAL(DurationChanged(double)), this,
SLOT(DurationChanged(double)));
if (s) {
duration->SetDuration(s->duration);
@@ -595,7 +592,7 @@ AudioSwitchFallbackWidget::AudioSwitchFallbackWidget(QWidget *parent,
{"{{scenes}}", scenes},
{"{{duration}}", duration},
{"{{transitions}}", transitions}};
PlaceWidgets(
placeWidgets(
obs_module_text("AdvSceneSwitcher.audioTab.multiMatchfallback"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -605,14 +602,12 @@ AudioSwitchFallbackWidget::AudioSwitchFallbackWidget(QWidget *parent,
loading = false;
}
void AudioSwitchFallbackWidget::DurationChanged(const Duration &dur)
void AudioSwitchFallbackWidget::DurationChanged(double sec)
{
if (loading || !switchData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switchData->duration = dur;
switchData->duration.seconds = sec;
}
} // namespace advss

View File

@@ -13,8 +13,6 @@
#include "duration-control.hpp"
#include "volume-control.hpp"
namespace advss {
constexpr auto audio_func = 8;
typedef enum {
@@ -77,7 +75,7 @@ private slots:
void SourceChanged(const QString &text);
void VolumeThresholdChanged(int vol);
void ConditionChanged(int cond);
void DurationChanged(const Duration &);
void DurationChanged(double dur);
void IgnoreInactiveChanged(int state);
private:
@@ -98,12 +96,10 @@ public:
AudioSwitchFallbackWidget(QWidget *parent, AudioSwitchFallback *s);
private slots:
void DurationChanged(const Duration &dur);
void DurationChanged(double dur);
private:
DurationSelection *duration;
AudioSwitchFallback *switchData;
};
} // namespace advss

View File

@@ -1,10 +1,6 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "platform-funcs.hpp"
#include "utility.hpp"
namespace advss {
bool ExecutableSwitch::pause = false;
static QMetaObject::Connection addPulse;
@@ -103,7 +99,7 @@ bool SwitcherData::checkExeSwitch(OBSWeakSource &scene,
bool equals = runningProcesses.contains(s.exe);
bool matches = (runningProcesses.indexOf(
QRegularExpression(s.exe)) != -1);
bool focus = (!s.inFocus || IsInFocus(s.exe));
bool focus = (!s.inFocus || isInFocus(s.exe));
// True if current window is ignored AND switch equals OR matches last window
bool ignore =
@@ -160,7 +156,7 @@ void SwitcherData::loadExecutableSwitches(obs_data_t *obj)
obs_data_array_release(executableArray);
}
void AdvSceneSwitcher::SetupExecutableTab()
void AdvSceneSwitcher::setupExecutableTab()
{
for (auto &s : switcher->executableSwitches) {
QListWidgetItem *item;
@@ -212,7 +208,7 @@ ExecutableSwitchWidget::ExecutableSwitchWidget(QWidget *parent,
QWidget::connect(requiresFocus, SIGNAL(stateChanged(int)), this,
SLOT(FocusChanged(int)));
PopulateProcessSelection(processes);
populateProcessSelection(processes);
processes->setEditable(true);
processes->setMaxVisibleItems(20);
@@ -228,7 +224,7 @@ ExecutableSwitchWidget::ExecutableSwitchWidget(QWidget *parent,
{"{{requiresFocus}}", requiresFocus},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.executableTab.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.executableTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -276,5 +272,3 @@ void ExecutableSwitchWidget::FocusChanged(int state)
std::lock_guard<std::mutex> lock(switcher->m);
switchData->inFocus = state;
}
} // namespace advss

View File

@@ -9,8 +9,6 @@
#include <QCheckBox>
#include "switch-generic.hpp"
namespace advss {
constexpr auto exe_func = 3;
struct ExecutableSwitch : SceneSwitcherEntry {
@@ -44,5 +42,3 @@ private:
ExecutableSwitch *switchData;
};
} // namespace advss

View File

@@ -1,8 +1,3 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "curl-helper.hpp"
#include "utility.hpp"
#include <QtGlobal>
#include <QFileDialog>
#include <QTextStream>
@@ -11,7 +6,9 @@
#include <regex>
#include <curl/curl.h>
namespace advss {
#include "advanced-scene-switcher.hpp"
#include "curl-helper.hpp"
#include "utility.hpp"
bool FileSwitch::pause = false;
static QMetaObject::Connection addPulse;
@@ -212,7 +209,7 @@ bool matchFileContent(QString &filedata, FileSwitch &s)
}
QString text = QString::fromStdString(s.text);
return CompareIgnoringLineEnding(text, filedata);
return compareIgnoringLineEnding(text, filedata);
}
bool checkRemoteFileContent(FileSwitch &s)
@@ -414,7 +411,7 @@ void SwitcherData::loadFileSwitches(obs_data_t *obj)
fileIO.writePath = obs_data_get_string(obj, "writePath");
}
void AdvSceneSwitcher::SetupFileTab()
void AdvSceneSwitcher::setupFileTab()
{
ui->remoteFileWarningLabel->setText(
obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning1") +
@@ -545,11 +542,11 @@ FileSwitchWidget::FileSwitchWidget(QWidget *parent, FileSwitch *s)
QHBoxLayout *line1Layout = new QHBoxLayout;
QHBoxLayout *line2Layout = new QHBoxLayout;
QHBoxLayout *line3Layout = new QHBoxLayout;
PlaceWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry"),
line1Layout, widgetPlaceholders);
PlaceWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry2"),
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry2"),
line2Layout, widgetPlaceholders, false);
PlaceWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry3"),
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry3"),
line3Layout, widgetPlaceholders);
mainLayout->addLayout(line1Layout);
mainLayout->addLayout(line2Layout);
@@ -668,5 +665,3 @@ void FileSwitchWidget::CheckFileContentChanged(int state)
std::lock_guard<std::mutex> lock(switcher->m);
switchData->onlyMatchIfChanged = state;
}
} // namespace advss

View File

@@ -8,11 +8,8 @@
#pragma once
#include "switch-generic.hpp"
#include <QPlainTextEdit>
#include <QDateTime>
#include <obs-module.h>
namespace advss {
constexpr auto read_file_func = 0;
typedef enum {
@@ -80,5 +77,3 @@ static inline QString MakeFileSwitchName(const QString &scene,
const QString &fileName,
const QString &text, bool useRegex,
bool useTime, bool onlyMatchIfChanged);
} // namespace advss

View File

@@ -1,12 +1,6 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
constexpr auto previous_scene_name = "Previous Scene";
constexpr auto current_transition_name = "Current Transition";
namespace advss {
static inline bool SceneGroupValid(SceneGroup *group)
{
if (group) {
@@ -214,9 +208,9 @@ SwitchWidget::SwitchWidget(QWidget *parent, SceneSwitcherEntry *s,
SIGNAL(SceneGroupRenamed(const QString &, const QString &)),
this, SLOT(SceneGroupRename(const QString &, const QString &)));
PopulateSceneSelection(scenes, usePreviousScene, false, false,
populateSceneSelection(scenes, usePreviousScene, false, false,
addSceneGroup, &switcher->sceneGroups);
PopulateTransitionSelection(transitions, addCurrentTransition);
populateTransitionSelection(transitions, addCurrentTransition);
switchData = s;
showSwitchData();
@@ -306,5 +300,3 @@ void SwitchWidget::TransitionChanged(const QString &text)
switchData->transition = GetWeakTransitionByQString(text);
switchData->useCurrentTransition = switchData->transition == nullptr;
}
} // namespace advss

View File

@@ -4,8 +4,6 @@
#include "scene-group.hpp"
namespace advss {
enum class SwitchTargetType {
Scene,
SceneGroup,
@@ -97,5 +95,3 @@ protected:
SceneSwitcherEntry *switchData;
};
} // namespace advss

View File

@@ -1,11 +1,7 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "platform-funcs.hpp"
#include "utility.hpp"
#include <regex>
namespace advss {
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
bool IdleData::pause = false;
IdleWidget *idleWidget = nullptr;
@@ -42,7 +38,7 @@ bool SwitcherData::checkIdleSwitch(OBSWeakSource &scene,
}
}
if (!ignoreIdle && SecondsSinceLastInput() > idleData.time) {
if (!ignoreIdle && secondsSinceLastInput() > idleData.time) {
if (idleData.alreadySwitched) {
return false;
}
@@ -209,9 +205,9 @@ void SwitcherData::loadIdleSwitches(obs_data_t *obj)
idleData.load(obj);
}
void AdvSceneSwitcher::SetupIdleTab()
void AdvSceneSwitcher::setupIdleTab()
{
PopulateWindowSelection(ui->ignoreIdleWindowsWindows);
populateWindowSelection(ui->ignoreIdleWindowsWindows);
for (auto &window : switcher->ignoreIdleWindows) {
QString text = QString::fromStdString(window);
@@ -271,7 +267,7 @@ IdleWidget::IdleWidget(QWidget *parent, IdleData *s)
{"{{duration}}", duration},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.idleTab.idleswitch"),
placeWidgets(obs_module_text("AdvSceneSwitcher.idleTab.idleswitch"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -289,5 +285,3 @@ void IdleWidget::DurationChanged(int dur)
std::lock_guard<std::mutex> lock(switcher->m);
switcher->idleData.time = dur;
}
} // namespace advss

View File

@@ -8,8 +8,6 @@
#pragma once
#include "switch-generic.hpp"
namespace advss {
constexpr auto default_idle_time = 60;
constexpr auto idle_func = 2;
@@ -38,5 +36,3 @@ private:
IdleData *switchData;
};
} // namespace advss

View File

@@ -1,9 +1,6 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
namespace advss {
bool MediaSwitch::pause = false;
static QMetaObject::Connection addPulse;
@@ -235,7 +232,7 @@ void SwitcherData::loadMediaSwitches(obs_data_t *obj)
obs_data_array_release(mediaArray);
}
void AdvSceneSwitcher::SetupMediaTab()
void AdvSceneSwitcher::setupMediaTab()
{
for (auto &s : switcher->mediaSwitches) {
QListWidgetItem *item;
@@ -463,7 +460,7 @@ MediaSwitchWidget::MediaSwitchWidget(QWidget *parent, MediaSwitch *s)
QWidget::connect(time, SIGNAL(valueChanged(int)), this,
SLOT(TimeChanged(int)));
PopulateMediaSelection(mediaSources);
populateMediaSelection(mediaSources);
populateMediaStates(states);
populateTimeRestrictions(timeRestrictions);
@@ -486,7 +483,7 @@ MediaSwitchWidget::MediaSwitchWidget(QWidget *parent, MediaSwitch *s)
{"{{time}}", time},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.mediaTab.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.mediaTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -563,5 +560,3 @@ void MediaSwitchWidget::TimeChanged(int time)
std::lock_guard<std::mutex> lock(switcher->m);
switchData->time = time;
}
} // namespace advss

View File

@@ -8,8 +8,6 @@
#pragma once
#include "switch-generic.hpp"
namespace advss {
constexpr auto media_func = 6;
typedef enum {
@@ -85,5 +83,3 @@ private:
MediaSwitch *switchData;
};
} // namespace advss

View File

@@ -7,12 +7,8 @@ Most of this code is based on https://github.com/Palakis/obs-websocket
#include <QMessageBox>
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "scene-switch-helpers.hpp"
#include "utility.hpp"
namespace advss {
#define PARAM_SERVER_ENABLE "ServerEnabled"
#define PARAM_SERVER_PORT "ServerPort"
#define PARAM_LOCKTOIPV4 "LockToIPv4"
@@ -128,9 +124,10 @@ WSServer::WSServer() : QObject(nullptr), _connections(), _clMutex()
_server.set_reuse_addr(true);
#endif
_server.set_open_handler(bind(&WSServer::onOpen, this, _1));
_server.set_close_handler(bind(&WSServer::onClose, this, _1));
_server.set_message_handler(bind(&WSServer::onMessage, this, _1, _2));
_server.set_open_handler(bind(&WSServer::onOpen, this, ::_1));
_server.set_close_handler(bind(&WSServer::onClose, this, ::_1));
_server.set_message_handler(
bind(&WSServer::onMessage, this, ::_1, ::_2));
}
WSServer::~WSServer()
@@ -224,7 +221,7 @@ void WSServer::stop()
blog(LOG_INFO, "server stopped successfully");
}
void WSServer::sendMessage(SceneSwitchInfo sceneSwitch, bool preview)
void WSServer::sendMessage(sceneSwitchInfo sceneSwitch, bool preview)
{
if (!sceneSwitch.scene) {
return;
@@ -308,9 +305,9 @@ std::string processMessage(std::string payload)
"'";
}
if (preview) {
SwitchPreviewScene(scene);
switchPreviewScene(scene);
} else {
SwitchScene({scene, transition, duration});
switchScene({scene, transition, duration});
}
return ret;
}
@@ -364,10 +361,11 @@ WSClient::WSClient() : QObject(nullptr)
_client.set_reuse_addr(true);
#endif
_client.set_open_handler(bind(&WSClient::onOpen, this, _1));
_client.set_fail_handler(bind(&WSClient::onFail, this, _1));
_client.set_message_handler(bind(&WSClient::onMessage, this, _1, _2));
_client.set_close_handler(bind(&WSClient::onClose, this, _1));
_client.set_open_handler(bind(&WSClient::onOpen, this, ::_1));
_client.set_fail_handler(bind(&WSClient::onFail, this, ::_1));
_client.set_message_handler(
bind(&WSClient::onMessage, this, ::_1, ::_2));
_client.set_close_handler(bind(&WSClient::onClose, this, ::_1));
}
WSClient::~WSClient()
@@ -503,7 +501,7 @@ void SwitcherData::saveNetworkSwitches(obs_data_t *obj)
}
}
void AdvSceneSwitcher::SetupNetworkTab()
void AdvSceneSwitcher::setupNetworkTab()
{
ui->serverSettings->setChecked(switcher->networkConfig.ServerEnabled);
ui->serverPort->setValue(switcher->networkConfig.ServerPort);
@@ -521,9 +519,9 @@ void AdvSceneSwitcher::SetupNetworkTab()
QTimer *statusTimer = new QTimer(this);
connect(statusTimer, SIGNAL(timeout()), this,
SLOT(UpdateClientStatus()));
SLOT(updateClientStatus()));
connect(statusTimer, SIGNAL(timeout()), this,
SLOT(UpdateServerStatus()));
SLOT(updateServerStatus()));
statusTimer->start(500);
}
@@ -574,7 +572,7 @@ void AdvSceneSwitcher::on_serverRestart_clicked()
switcher->networkConfig.LockToIPv4);
}
void AdvSceneSwitcher::UpdateServerStatus()
void AdvSceneSwitcher::updateServerStatus()
{
switch (switcher->serverStatus) {
case ServerStatus::NOT_RUNNING:
@@ -672,7 +670,7 @@ void AdvSceneSwitcher::on_clientReconnect_clicked()
switcher->client.connect(switcher->networkConfig.GetClientUri());
}
void AdvSceneSwitcher::UpdateClientStatus()
void AdvSceneSwitcher::updateClientStatus()
{
switch (switcher->clientStatus) {
case ClientStatus::DISCONNECTED:
@@ -711,5 +709,3 @@ Compatability::StdFunctionRunnable::StdFunctionRunnable(
: cb(std::move(func))
{
}
} // namespace advss

View File

@@ -19,13 +19,11 @@ Most of this code is based on https://github.com/Palakis/obs-websocket
#include <websocketpp/server.hpp>
#include <websocketpp/client.hpp>
namespace advss {
using websocketpp::connection_hdl;
typedef websocketpp::server<websocketpp::config::asio> server;
typedef websocketpp::client<websocketpp::config::asio_client> client;
struct SceneSwitchInfo;
struct sceneSwitchInfo;
class NetworkConfig {
public:
@@ -62,7 +60,7 @@ public:
virtual ~WSServer();
void start(quint16 port, bool lockToIPv4);
void stop();
void sendMessage(SceneSwitchInfo sceneSwitch, bool preview = false);
void sendMessage(sceneSwitchInfo sceneSwitch, bool preview = false);
QThreadPool *threadPool() { return &_threadPool; }
private:
@@ -133,5 +131,3 @@ public:
QRunnable *CreateFunctionRunnable(std::function<void()> func);
}
} // namespace advss

View File

@@ -1,10 +1,7 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include <regex>
namespace advss {
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
static QMetaObject::Connection addPulse;
@@ -247,7 +244,7 @@ void SwitcherData::loadPauseSwitches(obs_data_t *obj)
obs_data_array_release(pauseArray);
}
void AdvSceneSwitcher::SetupPauseTab()
void AdvSceneSwitcher::setupPauseTab()
{
for (auto &s : switcher->pauseEntries) {
QListWidgetItem *item;
@@ -312,7 +309,7 @@ PauseEntryWidget::PauseEntryWidget(QWidget *parent, PauseEntry *s)
populatePauseTypes(pauseTypes);
populatePauseTargets(pauseTargets);
PopulateWindowSelection(windows);
populateWindowSelection(windows);
windows->setEditable(true);
windows->setMaxVisibleItems(20);
@@ -338,7 +335,7 @@ PauseEntryWidget::PauseEntryWidget(QWidget *parent, PauseEntry *s)
{"{{pauseTargets}}", pauseTargets},
{"{{windows}}", windows}};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.pauseTab.pauseEntry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.pauseTab.pauseEntry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -413,5 +410,3 @@ bool PauseEntry::valid()
{
return true;
}
} // namespace advss

View File

@@ -8,8 +8,6 @@
#pragma once
#include "switch-generic.hpp"
namespace advss {
enum class PauseType {
Scene,
Window,
@@ -72,5 +70,3 @@ private:
PauseEntry *switchData;
};
} // namespace advss

View File

@@ -0,0 +1,78 @@
#include <algorithm>
#include "advanced-scene-switcher.hpp"
void AdvSceneSwitcher::on_threadPriority_currentTextChanged(const QString &text)
{
if (loading || ui->threadPriority->count() !=
(int)switcher->threadPriorities.size())
return;
std::lock_guard<std::mutex> lock(switcher->m);
for (auto p : switcher->threadPriorities) {
if (p.name == text.toUtf8().constData()) {
switcher->threadPriority = p.value;
break;
}
}
}
void AdvSceneSwitcher::on_priorityUp_clicked()
{
int currentIndex = ui->priorityList->currentRow();
if (currentIndex != -1 && currentIndex != 0) {
ui->priorityList->insertItem(
currentIndex - 1,
ui->priorityList->takeItem(currentIndex));
ui->priorityList->setCurrentRow(currentIndex - 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->functionNamesByPriority.begin() +
currentIndex,
switcher->functionNamesByPriority.begin() +
currentIndex - 1);
}
ui->macroPriorityWarning->setVisible(
switcher->functionNamesByPriority[0] != macro_func);
}
void AdvSceneSwitcher::on_priorityDown_clicked()
{
int currentIndex = ui->priorityList->currentRow();
if (currentIndex != -1 &&
currentIndex != ui->priorityList->count() - 1) {
ui->priorityList->insertItem(
currentIndex + 1,
ui->priorityList->takeItem(currentIndex));
ui->priorityList->setCurrentRow(currentIndex + 1);
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(switcher->functionNamesByPriority.begin() +
currentIndex,
switcher->functionNamesByPriority.begin() +
currentIndex + 1);
}
ui->macroPriorityWarning->setVisible(
switcher->functionNamesByPriority[0] != macro_func);
}
bool SwitcherData::prioFuncsValid()
{
auto fNBPCopy = functionNamesByPriority;
std::sort(fNBPCopy.begin(), fNBPCopy.end());
auto it = std::unique(fNBPCopy.begin(), fNBPCopy.end());
bool wasUnique = (it == fNBPCopy.end());
if (!wasUnique) {
return false;
}
for (int p : functionNamesByPriority) {
if (p < 0 || p > 10) {
return false;
}
}
return true;
}

View File

@@ -1,10 +1,7 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include <random>
namespace advss {
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
bool RandomSwitch::pause = false;
static QMetaObject::Connection addPulse;
@@ -116,7 +113,7 @@ void SwitcherData::loadRandomSwitches(obs_data_t *obj)
obs_data_array_release(randomArray);
}
void AdvSceneSwitcher::SetupRandomTab()
void AdvSceneSwitcher::setupRandomTab()
{
for (auto &s : switcher->randomSwitches) {
QListWidgetItem *item;
@@ -143,8 +140,7 @@ void AdvSceneSwitcher::SetupRandomTab()
border-radius: 7px; \
border-color: rgb(0,0,0,0) \
}");
if (switcher->switchIfNotMatching !=
SwitcherData::NoMatch::RANDOM_SWITCH) {
if (switcher->switchIfNotMatching != RANDOM_SWITCH) {
if (!switcher->disableHints) {
PulseWidget(ui->randomDisabledWarning, QColor(Qt::red),
QColor(0, 0, 0, 0));
@@ -186,7 +182,7 @@ RandomSwitchWidget::RandomSwitchWidget(QWidget *parent, RandomSwitch *s)
{"{{scenes}}", scenes},
{"{{transitions}}", transitions},
{"{{delay}}", delay}};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.randomTab.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.randomTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -224,5 +220,3 @@ void RandomSwitchWidget::DelayChanged(double d)
std::lock_guard<std::mutex> lock(switcher->m);
switchData->delay = d;
}
} // namespace advss

View File

@@ -8,8 +8,6 @@
#pragma once
#include "switch-generic.hpp"
namespace advss {
struct RandomSwitch : SceneSwitcherEntry {
static bool pause;
double delay = 0.0;
@@ -38,5 +36,3 @@ private:
RandomSwitch *switchData;
};
} // namespace advss

View File

@@ -1,15 +1,12 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include <QTimer>
namespace advss {
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
bool ScreenRegionSwitch::pause = false;
static QMetaObject::Connection addPulse;
void AdvSceneSwitcher::ClearFrames(QListWidget *list)
void AdvSceneSwitcher::clearFrames(QListWidget *list)
{
for (int i = 0; i < list->count(); ++i) {
ScreenRegionWidget *sw =
@@ -51,7 +48,7 @@ void AdvSceneSwitcher::on_showFrame_clicked()
showCurrentFrame(ui->screenRegionSwitches);
} else {
SetShowFrames();
ClearFrames(ui->screenRegionSwitches);
clearFrames(ui->screenRegionSwitches);
}
}
@@ -62,7 +59,7 @@ void AdvSceneSwitcher::on_screenRegionSwitches_currentRowChanged(int idx)
}
if (switcher->showFrame) {
ClearFrames(ui->screenRegionSwitches);
clearFrames(ui->screenRegionSwitches);
showCurrentFrame(ui->screenRegionSwitches);
}
}
@@ -156,7 +153,7 @@ bool SwitcherData::checkScreenRegionSwitch(OBSWeakSource &scene,
return false;
}
std::pair<int, int> cursorPos = GetCursorPos();
std::pair<int, int> cursorPos = getCursorPos();
int minRegionSize = 99999;
bool match = false;
@@ -191,7 +188,7 @@ bool SwitcherData::checkScreenRegionSwitch(OBSWeakSource &scene,
void AdvSceneSwitcher::updateScreenRegionCursorPos()
{
std::pair<int, int> position = GetCursorPos();
std::pair<int, int> position = getCursorPos();
ui->cursorXPosition->setText(QString::number(position.first));
ui->cursorYPosition->setText(QString::number(position.second));
}
@@ -231,7 +228,7 @@ void SwitcherData::loadScreenRegionSwitches(obs_data_t *obj)
obs_data_array_release(screenRegionArray);
}
void AdvSceneSwitcher::SetupRegionTab()
void AdvSceneSwitcher::setupRegionTab()
{
for (auto &s : switcher->screenRegionSwitches) {
QListWidgetItem *item;
@@ -321,7 +318,7 @@ ScreenRegionWidget::ScreenRegionWidget(QWidget *parent, ScreenRegionSwitch *s)
QWidget::connect(maxY, SIGNAL(valueChanged(int)), this,
SLOT(MaxYChanged(int)));
PopulateSceneSelection(
populateSceneSelection(
excludeScenes, false, false, false, false, nullptr, true,
obs_module_text(
"AdvSceneSwitcher.screenRegionTab.excludeScenes.None"),
@@ -345,7 +342,7 @@ ScreenRegionWidget::ScreenRegionWidget(QWidget *parent, ScreenRegionSwitch *s)
{"{{scenes}}", scenes},
{"{{transitions}}", transitions},
{"{{excludeScenes}}", excludeScenes}};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.screenRegionTab.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.screenRegionTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -458,5 +455,3 @@ void ScreenRegionWidget::drawFrame()
switchData->maxY - switchData->minY);
}
}
} // namespace advss

View File

@@ -9,8 +9,6 @@
#include <QSpinBox>
#include "switch-generic.hpp"
namespace advss {
constexpr auto screen_region_func = 4;
struct ScreenRegionSwitch : SceneSwitcherEntry {
@@ -57,5 +55,3 @@ private:
void drawFrame();
};
} // namespace advss

View File

@@ -1,12 +1,9 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include <QFileDialog>
#include <QTextStream>
#include <QScrollArea>
namespace advss {
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
constexpr auto max_extend_text_size = 150;
@@ -281,7 +278,7 @@ void SwitcherData::loadSceneSequenceSwitches(obs_data_t *obj)
obs_data_array_release(sceneSequenceArray);
}
void AdvSceneSwitcher::SetupSequenceTab()
void AdvSceneSwitcher::setupSequenceTab()
{
for (auto &s : switcher->sceneSequenceSwitches) {
QListWidgetItem *item;
@@ -458,7 +455,7 @@ bool SceneSequenceSwitch::checkDurationMatchInterruptible()
void SceneSequenceSwitch::prepareUninterruptibleMatch(int &linger)
{
int dur = delay.Milliseconds();
int dur = delay.seconds * 1000;
if (dur > 0) {
linger = dur;
}
@@ -591,8 +588,10 @@ SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s,
QWidget::connect(scenes, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(SceneChanged(const QString &)));
QWidget::connect(delay, SIGNAL(DurationChanged(const Duration &)), this,
SLOT(DelayChanged(const Duration &)));
QWidget::connect(delay, SIGNAL(DurationChanged(double)), this,
SLOT(DelayChanged(double)));
QWidget::connect(delay, SIGNAL(UnitChanged(DurationUnit)), this,
SLOT(DelayUnitsChanged(DurationUnit)));
QWidget::connect(startScenes,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(StartSceneChanged(const QString &)));
@@ -604,7 +603,7 @@ SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s,
QWidget::connect(reduce, SIGNAL(clicked()), this,
SLOT(ReduceClicked()));
PopulateSceneSelection(startScenes);
populateSceneSelection(startScenes);
interruptible->setToolTip(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.interruptibleHint"));
@@ -616,7 +615,7 @@ SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s,
{"{{scenes}}", scenes},
{"{{delay}}", delay},
{"{{transitions}}", transitions}};
PlaceWidgets(
placeWidgets(
obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.extendEntry"),
mainLayout, widgetPlaceholders);
@@ -629,7 +628,7 @@ SequenceWidget::SequenceWidget(QWidget *parent, SceneSequenceSwitch *s,
{"{{delay}}", delay},
{"{{transitions}}", transitions},
{"{{interruptible}}", interruptible}};
PlaceWidgets(obs_module_text(
placeWidgets(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.entry"),
startSequence, widgetPlaceholders);
@@ -690,14 +689,24 @@ void SequenceWidget::swapSwitchData(SequenceWidget *s1, SequenceWidget *s2)
s2->setSwitchData(t);
}
void SequenceWidget::DelayChanged(const Duration &delay)
void SequenceWidget::DelayChanged(double sec)
{
if (loading || !switchData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switchData->delay = delay;
switchData->delay.seconds = sec;
}
void SequenceWidget::DelayUnitsChanged(DurationUnit unit)
{
if (loading || !switchData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switchData->delay.displayUnit = unit;
}
void SequenceWidget::setExtendedSequenceStartScene()
@@ -796,5 +805,3 @@ void SequenceWidget::ReduceClicked()
delete item;
}
}
} // namespace advss

View File

@@ -11,8 +11,6 @@
#include "switch-generic.hpp"
#include "duration-control.hpp"
namespace advss {
constexpr auto round_trip_func = 1;
struct SceneSequenceSwitch : SceneSwitcherEntry {
@@ -61,7 +59,8 @@ public:
private slots:
void SceneChanged(const QString &text);
void DelayChanged(const Duration &delay);
void DelayChanged(double delay);
void DelayUnitsChanged(DurationUnit);
void StartSceneChanged(const QString &text);
void InterruptibleChanged(int state);
void ExtendClicked();
@@ -84,5 +83,3 @@ protected:
SceneSequenceSwitch *switchData;
};
} // namespace advss

View File

@@ -1,9 +1,6 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
namespace advss {
bool TimeSwitch::pause = false;
static QMetaObject::Connection addPulse;
@@ -182,7 +179,7 @@ void SwitcherData::loadTimeSwitches(obs_data_t *obj)
obs_data_array_release(timeArray);
}
void AdvSceneSwitcher::SetupTimeTab()
void AdvSceneSwitcher::setupTimeTab()
{
for (auto &s : switcher->timeSwitches) {
QListWidgetItem *item;
@@ -261,7 +258,7 @@ TimeSwitchWidget::TimeSwitchWidget(QWidget *parent, TimeSwitch *s)
{"{{time}}", time},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.timeTab.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.timeTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -309,5 +306,3 @@ void TimeSwitchWidget::TimeChanged(const QTime &time)
std::lock_guard<std::mutex> lock(switcher->m);
switchData->time = time;
}
} // namespace advss

View File

@@ -10,8 +10,6 @@
#include "switch-generic.hpp"
namespace advss {
constexpr auto time_func = 7;
typedef enum {
@@ -56,5 +54,3 @@ private:
TimeSwitch *switchData;
};
} // namespace advss

View File

@@ -1,10 +1,7 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include <thread>
namespace advss {
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
constexpr auto default_def_transition_dealy = 300;
bool DefaultSceneTransition::pause = false;
@@ -172,7 +169,7 @@ void SwitcherData::checkDefaultSceneTransitions()
}
}
void AdvSceneSwitcher::DefTransitionDelayValueChanged(int value)
void AdvSceneSwitcher::defTransitionDelayValueChanged(int value)
{
if (loading) {
return;
@@ -182,6 +179,104 @@ void AdvSceneSwitcher::DefTransitionDelayValueChanged(int value)
DefaultSceneTransition::delay = value;
}
std::pair<obs_weak_source_t *, int> getNextTransition(obs_weak_source_t *scene1,
obs_weak_source_t *scene2)
{
obs_weak_source_t *ws = nullptr;
int duration = 0;
if (scene1 && scene2) {
for (SceneTransition &t : switcher->sceneTransitions) {
if (!t.initialized()) {
continue;
}
if (t.scene == scene1 && t.scene2 == scene2) {
ws = t.transition;
duration = t.duration * 1000;
break;
}
}
}
return std::make_pair(ws, duration);
}
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);
td.name = obs_data_get_string(data, "transition");
td.duration = obs_data_get_int(data, "transition_duration");
std::string name = GetWeakSourceName(ssi.transition);
obs_data_set_string(data, "transition", name.c_str());
obs_data_set_int(data, "transition_duration", ssi.duration);
obs_data_release(data);
obs_source_release(scene);
}
void restoreTransitionOverride(obs_source_t *scene, const transitionData &td)
{
obs_data_t *data = obs_source_get_private_settings(scene);
obs_data_set_string(data, "transition", td.name.c_str());
obs_data_set_int(data, "transition_duration", td.duration);
obs_data_release(data);
}
void setNextTransition(const sceneSwitchInfo &sceneSwitch,
obs_source_t *currentSource, transitionData &td)
{
// Priority:
// 1. Transition tab
// 2. Individual switcher entry
// 3. Current transition settings
// Transition Tab
obs_weak_source_t *currentScene =
obs_source_get_weak_source(currentSource);
auto tinfo = getNextTransition(currentScene, sceneSwitch.scene);
obs_weak_source_release(currentScene);
OBSWeakSource nextTransition = tinfo.first;
int nextTransitionDuration = tinfo.second;
// Individual switcher entry
if (!nextTransition) {
nextTransition = sceneSwitch.transition;
}
if (!nextTransitionDuration) {
nextTransitionDuration = sceneSwitch.duration;
}
// Current transition settings
if (!nextTransition) {
auto ct = obs_frontend_get_current_transition();
nextTransition = obs_source_get_weak_source(ct);
obs_weak_source_release(nextTransition);
obs_source_release(ct);
}
if (!nextTransitionDuration) {
nextTransitionDuration = obs_frontend_get_transition_duration();
}
if (switcher->adjustActiveTransitionType) {
obs_frontend_set_transition_duration(nextTransitionDuration);
auto t = obs_weak_source_get_source(nextTransition);
obs_frontend_set_current_transition(t);
obs_source_release(t);
}
if (switcher->transitionOverrideOverride) {
overwriteTransitionOverride({sceneSwitch.scene, nextTransition,
nextTransitionDuration},
td);
}
}
void SwitcherData::saveSceneTransitions(obs_data_t *obj)
{
obs_data_array_t *sceneTransitionsArray = obs_data_array_create();
@@ -254,7 +349,7 @@ void SwitcherData::loadSceneTransitions(obs_data_t *obj)
obs_data_get_int(obj, "defTransitionDelay");
}
void AdvSceneSwitcher::SetupTransitionsTab()
void AdvSceneSwitcher::setupTransitionsTab()
{
for (auto &s : switcher->sceneTransitions) {
QListWidgetItem *item;
@@ -302,11 +397,11 @@ void AdvSceneSwitcher::SetupTransitionsTab()
"AdvSceneSwitcher.transitionTab.defaultTransition.delay.help"));
QWidget::connect(defTransitionDelay, SIGNAL(valueChanged(int)), this,
SLOT(DefTransitionDelayValueChanged(int)));
SLOT(defTransitionDelayValueChanged(int)));
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{defTransitionDelay}}", defTransitionDelay}};
PlaceWidgets(
placeWidgets(
obs_module_text(
"AdvSceneSwitcher.transitionTab.defaultTransition.delay"),
ui->defTransitionDelayLayout, widgetPlaceholders);
@@ -354,7 +449,7 @@ TransitionSwitchWidget::TransitionSwitchWidget(QWidget *parent,
QWidget::connect(duration, SIGNAL(valueChanged(double)), this,
SLOT(DurationChanged(double)));
PopulateSceneSelection(scenes2);
populateSceneSelection(scenes2);
if (s) {
scenes2->setCurrentText(GetWeakSourceName(s->scene2).c_str());
@@ -367,7 +462,7 @@ TransitionSwitchWidget::TransitionSwitchWidget(QWidget *parent,
{"{{scenes2}}", scenes2},
{"{{duration}}", duration},
{"{{transitions}}", transitions}};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.transitionTab.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.transitionTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -423,7 +518,7 @@ DefTransitionSwitchWidget::DefTransitionSwitchWidget(QWidget *parent,
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{scenes}}", scenes}, {"{{transitions}}", transitions}};
PlaceWidgets(
placeWidgets(
obs_module_text(
"AdvSceneSwitcher.transitionTab.defaultTransitionEntry"),
mainLayout, widgetPlaceholders);
@@ -497,5 +592,3 @@ void DefaultSceneTransition::setTransition()
t = std::thread(setTransitionDelayed, transition, delay);
t.detach();
}
} // namespace advss

View File

@@ -3,8 +3,6 @@
#include "switch-generic.hpp"
namespace advss {
struct SceneTransition : SceneSwitcherEntry {
OBSWeakSource scene2 = nullptr;
double duration = 0.3;
@@ -79,5 +77,3 @@ public:
private:
DefaultSceneTransition *switchData;
};
} // namespace advss

View File

@@ -1,13 +1,10 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include <QFileDialog>
#include <QBuffer>
#include <QToolTip>
#include <thread>
namespace advss {
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
bool VideoSwitch::pause = false;
static QMetaObject::Connection addPulse;
@@ -185,7 +182,7 @@ void SwitcherData::loadVideoSwitches(obs_data_t *obj)
obs_data_array_release(videoArray);
}
void AdvSceneSwitcher::SetupVideoTab()
void AdvSceneSwitcher::setupVideoTab()
{
for (auto &s : switcher->videoSwitches) {
QListWidgetItem *item;
@@ -431,7 +428,7 @@ VideoSwitchWidget::VideoSwitchWidget(QWidget *parent, VideoSwitch *s)
{"{{ignoreInactiveSource}}", ignoreInactiveSource},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.videoTab.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.videoTab.entry"),
switchLayout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
@@ -580,5 +577,3 @@ void VideoSwitchWidget::IgnoreInactiveChanged(int state)
std::lock_guard<std::mutex> lock(switcher->m);
switchData->ignoreInactiveSource = state;
}
} // namespace advss

View File

@@ -11,8 +11,6 @@
#include "switch-generic.hpp"
#include "screenshot-helper.hpp"
namespace advss {
constexpr auto video_func = 9;
enum class videoSwitchType {
@@ -82,5 +80,3 @@ private:
VideoSwitch *switchData;
};
} // namespace advss

View File

@@ -1,11 +1,7 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "platform-funcs.hpp"
#include "utility.hpp"
#include <regex>
namespace advss {
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
bool WindowSwitch::pause = false;
static QMetaObject::Connection addPulse;
@@ -181,8 +177,8 @@ void checkWindowTitleSwitchDirect(WindowSwitch &s,
OBSWeakSource &transition)
{
bool focus = (!s.focus || s.window == currentWindowTitle);
bool fullscreen = (!s.fullscreen || IsFullscreen(s.window));
bool max = (!s.maximized || IsMaximized(s.window));
bool fullscreen = (!s.fullscreen || isFullscreen(s.window));
bool max = (!s.maximized || isMaximized(s.window));
if (focus && fullscreen && max) {
match = true;
@@ -207,8 +203,8 @@ void checkWindowTitleSwitchRegex(WindowSwitch &s,
}
bool focus = (!s.focus || window == currentWindowTitle);
bool fullscreen = (!s.fullscreen || IsFullscreen(window));
bool max = (!s.maximized || IsMaximized(window));
bool fullscreen = (!s.fullscreen || isFullscreen(window));
bool max = (!s.maximized || isMaximized(window));
if (focus && fullscreen && max) {
match = true;
@@ -319,7 +315,7 @@ void SwitcherData::loadWindowTitleSwitches(obs_data_t *obj)
obs_data_array_release(ignoreWindowsArray);
}
void AdvSceneSwitcher::SetupTitleTab()
void AdvSceneSwitcher::setupTitleTab()
{
for (auto &s : switcher->windowSwitches) {
QListWidgetItem *item;
@@ -340,7 +336,7 @@ void AdvSceneSwitcher::SetupTitleTab()
ui->windowHelp->setVisible(false);
}
PopulateWindowSelection(ui->ignoreWindowsWindows);
populateWindowSelection(ui->ignoreWindowsWindows);
for (auto &window : switcher->ignoreWindowsSwitches) {
QString text = QString::fromStdString(window);
@@ -398,7 +394,7 @@ WindowSwitchWidget::WindowSwitchWidget(QWidget *parent, WindowSwitch *s)
QWidget::connect(focused, SIGNAL(stateChanged(int)), this,
SLOT(FocusChanged(int)));
PopulateWindowSelection(windows);
populateWindowSelection(windows);
windows->setEditable(true);
windows->setMaxVisibleItems(20);
@@ -418,7 +414,7 @@ WindowSwitchWidget::WindowSwitchWidget(QWidget *parent, WindowSwitch *s)
{"{{fullscreen}}", fullscreen},
{"{{maximized}}", maximized},
{"{{focused}}", focused}};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.windowTitleTab.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.windowTitleTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -486,5 +482,3 @@ void WindowSwitchWidget::FocusChanged(int state)
std::lock_guard<std::mutex> lock(switcher->m);
switchData->focus = state;
}
} // namespace advss

View File

@@ -8,8 +8,6 @@
#pragma once
#include "switch-generic.hpp"
namespace advss {
constexpr auto window_title_func = 5;
struct WindowSwitch : SceneSwitcherEntry {
@@ -49,5 +47,3 @@ private:
WindowSwitch *switchData;
};
} // namespace advss

View File

@@ -33,8 +33,6 @@
#include <fstream>
#include <sstream>
namespace advss {
static Display *xdisplay = 0;
static QLibrary *libXtstHandle = nullptr;
@@ -317,7 +315,7 @@ bool windowStatesAreSet(const std::string &windowTitle,
return false;
}
bool IsMaximized(const std::string &title)
bool isMaximized(const std::string &title)
{
std::vector<QString> states;
states.emplace_back("_NET_WM_STATE_MAXIMIZED_VERT");
@@ -325,19 +323,13 @@ bool IsMaximized(const std::string &title)
return windowStatesAreSet(title, states);
}
bool IsFullscreen(const std::string &title)
bool isFullscreen(const std::string &title)
{
std::vector<QString> states;
states.emplace_back("_NET_WM_STATE_FULLSCREEN");
return windowStatesAreSet(title, states);
}
std::optional<std::string> GetTextInWindow(const std::string &window)
{
// Not implemented
return {};
}
#ifdef USE_PROCPS
void GetProcessList(QStringList &processes)
{
@@ -436,7 +428,7 @@ void GetForegroundProcessName(std::string &proc)
proc = getProcNameFromPid(pid);
}
bool IsInFocus(const QString &executable)
bool isInFocus(const QString &executable)
{
std::string current;
GetForegroundProcessName(current);
@@ -450,7 +442,7 @@ bool IsInFocus(const QString &executable)
return (equals || matches);
}
int SecondsSinceLastInput()
int secondsSinceLastInput()
{
if (!canGetIdleTime) {
return 0;
@@ -667,5 +659,3 @@ void PlatformCleanup()
}
cleanupDisplay();
}
} // namespace advss

View File

@@ -1,9 +1,7 @@
#include "macro-action-audio.hpp"
#include "switcher-data.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
namespace advss {
constexpr int64_t nsPerMs = 1000000;
const std::string MacroActionAudio::id = "audio";
@@ -116,7 +114,7 @@ void MacroActionAudio::FadeVolume()
int nrSteps = 0;
float volStep = 0.;
if (_fadeType == FadeType::DURATION) {
nrSteps = _duration.Milliseconds() / fadeInterval.count();
nrSteps = _duration.seconds * 1000 / fadeInterval.count();
volStep = volDiff / nrSteps;
} else {
volStep = _rate / 1000.0f;
@@ -214,7 +212,7 @@ void MacroActionAudio::LogAction() const
vblog(LOG_INFO,
"performed action \"%s\" for source \"%s\" with volume %d with fade %d %f",
it->second.c_str(), _audioSource.ToString(true).c_str(),
_volume.GetValue(), _fade, _duration.Seconds());
_volume, _fade, _duration.seconds);
} else {
blog(LOG_WARNING, "ignored unknown audio action %d",
static_cast<int>(_action));
@@ -227,16 +225,15 @@ bool MacroActionAudio::Save(obs_data_t *obj) const
_duration.Save(obj);
_audioSource.Save(obj, "audioSource");
obs_data_set_int(obj, "action", static_cast<int>(_action));
obs_data_set_int(obj, "syncOffset", _syncOffset);
obs_data_set_int(obj, "monitor", _monitorType);
_syncOffset.Save(obj, "syncOffset");
_balance.Save(obj, "balance");
_volume.Save(obj, "volume");
_rate.Save(obj, "rate");
obs_data_set_double(obj, "balance", _balance);
obs_data_set_int(obj, "volume", _volume);
obs_data_set_double(obj, "rate", _rate);
obs_data_set_bool(obj, "fade", _fade);
obs_data_set_int(obj, "fadeType", static_cast<int>(_fadeType));
obs_data_set_bool(obj, "wait", _wait);
obs_data_set_bool(obj, "abortActiveFade", _abortActiveFade);
obs_data_set_int(obj, "version", 1);
return true;
}
@@ -246,19 +243,12 @@ bool MacroActionAudio::Load(obs_data_t *obj)
_duration.Load(obj);
_audioSource.Load(obj, "audioSource");
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
_syncOffset = obs_data_get_int(obj, "syncOffset");
_monitorType = static_cast<obs_monitoring_type>(
obs_data_get_int(obj, "monitor"));
if (!obs_data_has_user_value(obj, "version")) {
_syncOffset = obs_data_get_int(obj, "syncOffset");
_balance = obs_data_get_double(obj, "balance");
_volume = obs_data_get_int(obj, "volume");
_rate = obs_data_get_double(obj, "rate");
} else {
_syncOffset.Load(obj, "syncOffset");
_balance.Load(obj, "balance");
_volume.Load(obj, "volume");
_rate.Load(obj, "rate");
}
_balance = obs_data_get_double(obj, "balance");
_volume = obs_data_get_int(obj, "volume");
_rate = obs_data_get_double(obj, "rate");
_fade = obs_data_get_bool(obj, "fade");
if (obs_data_has_user_value(obj, "wait")) {
_wait = obs_data_get_bool(obj, "wait");
@@ -312,16 +302,16 @@ MacroActionAudioEdit::MacroActionAudioEdit(
_sources(new SourceSelectionWidget(this, QStringList(), true)),
_actions(new QComboBox),
_fadeTypes(new QComboBox),
_syncOffset(new VariableSpinBox),
_syncOffset(new QSpinBox),
_monitorTypes(new QComboBox),
_balance(new SliderSpinBox(
0., 1., "",
obs_module_text(
"AdvSceneSwitcher.action.audio.balance.description"))),
_volumePercent(new VariableSpinBox),
_volumePercent(new QSpinBox),
_fade(new QCheckBox),
_duration(new DurationSelection(parent, false)),
_rate(new VariableDoubleSpinBox),
_rate(new QDoubleSpinBox),
_wait(new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.audio.fade.wait"))),
_abortActiveFade(new QCheckBox(
@@ -346,35 +336,27 @@ MacroActionAudioEdit::MacroActionAudioEdit(
sources.sort();
_sources->SetSourceNameList(sources);
populateFadeTypeSelection(_fadeTypes);
PopulateMonitorTypeSelection(_monitorTypes);
populateMonitorTypeSelection(_monitorTypes);
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionChanged(int)));
QWidget::connect(_sources,
SIGNAL(SourceChanged(const SourceSelection &)), this,
SLOT(SourceChanged(const SourceSelection &)));
QWidget::connect(
_syncOffset,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this, SLOT(SyncOffsetChanged(const NumberVariable<int> &)));
QWidget::connect(
_balance,
SIGNAL(DoubleValueChanged(const NumberVariable<double> &)),
this, SLOT(BalanceChanged(const NumberVariable<double> &)));
QWidget::connect(_syncOffset, SIGNAL(valueChanged(int)), this,
SLOT(SyncOffsetChanged(int)));
QWidget::connect(_balance, SIGNAL(DoubleValueChanged(double)), this,
SLOT(BalanceChanged(double)));
QWidget::connect(_monitorTypes, SIGNAL(currentIndexChanged(int)), this,
SLOT(MonitorTypeChanged(int)));
QWidget::connect(
_volumePercent,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this, SLOT(VolumeChanged(const NumberVariable<int> &)));
QWidget::connect(_volumePercent, SIGNAL(valueChanged(int)), this,
SLOT(VolumeChanged(int)));
QWidget::connect(_fade, SIGNAL(stateChanged(int)), this,
SLOT(FadeChanged(int)));
QWidget::connect(_duration, SIGNAL(DurationChanged(const Duration &)),
this, SLOT(DurationChanged(const Duration &)));
QWidget::connect(
_rate,
SIGNAL(NumberVariableChanged(const NumberVariable<double> &)),
this, SLOT(RateChanged(const NumberVariable<double> &)));
QWidget::connect(_duration, SIGNAL(DurationChanged(double)), this,
SLOT(DurationChanged(double)));
QWidget::connect(_rate, SIGNAL(valueChanged(double)), this,
SLOT(RateChanged(double)));
QWidget::connect(_wait, SIGNAL(stateChanged(int)), this,
SLOT(WaitChanged(int)));
QWidget::connect(_abortActiveFade, SIGNAL(stateChanged(int)), this,
@@ -397,10 +379,10 @@ MacroActionAudioEdit::MacroActionAudioEdit(
{"{{fadeTypes}}", _fadeTypes},
};
QHBoxLayout *entryLayout = new QHBoxLayout;
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.audio.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.action.audio.entry"),
entryLayout, widgetPlaceholders);
_fadeTypeLayout = new QHBoxLayout;
PlaceWidgets(
placeWidgets(
obs_module_text("AdvSceneSwitcher.action.audio.fade.duration"),
_fadeTypeLayout, widgetPlaceholders);
@@ -419,7 +401,7 @@ MacroActionAudioEdit::MacroActionAudioEdit(
_loading = false;
}
static bool hasVolumeControl(MacroActionAudio::Action action)
bool hasVolumeControl(MacroActionAudio::Action action)
{
return action == MacroActionAudio::Action::SOURCE_VOLUME ||
action == MacroActionAudio::Action::MASTER_VOLUME;
@@ -447,7 +429,7 @@ void MacroActionAudioEdit::SetWidgetVisibility()
_fadeTypeLayout->removeWidget(_fadeTypes);
_fadeTypeLayout->removeWidget(_duration);
_fadeTypeLayout->removeWidget(_rate);
ClearLayout(_fadeTypeLayout);
clearLayout(_fadeTypeLayout);
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{fade}}", _fade},
{"{{duration}}", _duration},
@@ -455,12 +437,12 @@ void MacroActionAudioEdit::SetWidgetVisibility()
{"{{fadeTypes}}", _fadeTypes},
};
if (_entryData->_fadeType == MacroActionAudio::FadeType::DURATION) {
PlaceWidgets(
placeWidgets(
obs_module_text(
"AdvSceneSwitcher.action.audio.fade.duration"),
_fadeTypeLayout, widgetPlaceholders);
} else {
PlaceWidgets(obs_module_text(
placeWidgets(obs_module_text(
"AdvSceneSwitcher.action.audio.fade.rate"),
_fadeTypeLayout, widgetPlaceholders);
}
@@ -470,9 +452,9 @@ void MacroActionAudioEdit::SetWidgetVisibility()
_rate->setVisible(_entryData->_fadeType ==
MacroActionAudio::FadeType::RATE);
SetLayoutVisible(_fadeTypeLayout,
setLayoutVisible(_fadeTypeLayout,
hasVolumeControl(_entryData->_action));
SetLayoutVisible(_fadeOptionsLayout,
setLayoutVisible(_fadeOptionsLayout,
hasVolumeControl(_entryData->_action));
adjustSize();
}
@@ -486,13 +468,13 @@ void MacroActionAudioEdit::UpdateEntryData()
_sources->SetSource(_entryData->_audioSource);
_actions->setCurrentIndex(
_actions->findData(static_cast<int>(_entryData->_action)));
_syncOffset->SetValue(_entryData->_syncOffset);
_syncOffset->setValue(_entryData->_syncOffset);
_monitorTypes->setCurrentIndex(_entryData->_monitorType);
_balance->SetDoubleValue(_entryData->_balance);
_volumePercent->SetValue(_entryData->_volume);
_volumePercent->setValue(_entryData->_volume);
_fade->setChecked(_entryData->_fade);
_duration->SetDuration(_entryData->_duration);
_rate->SetValue(_entryData->_rate);
_rate->setValue(_entryData->_rate);
_wait->setChecked(_entryData->_wait);
_abortActiveFade->setChecked(_entryData->_abortActiveFade);
_fadeTypes->setCurrentIndex(static_cast<int>(_entryData->_fadeType));
@@ -505,7 +487,7 @@ void MacroActionAudioEdit::SourceChanged(const SourceSelection &source)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_audioSource = source;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
@@ -517,19 +499,19 @@ void MacroActionAudioEdit::ActionChanged(int idx)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_action = static_cast<MacroActionAudio::Action>(
_actions->itemData(idx).toInt());
SetWidgetVisibility();
}
void MacroActionAudioEdit::SyncOffsetChanged(const NumberVariable<int> &value)
void MacroActionAudioEdit::SyncOffsetChanged(int value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_syncOffset = value;
}
@@ -539,27 +521,27 @@ void MacroActionAudioEdit::MonitorTypeChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_monitorType = static_cast<obs_monitoring_type>(value);
}
void MacroActionAudioEdit::BalanceChanged(const NumberVariable<double> &value)
void MacroActionAudioEdit::BalanceChanged(double value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_balance = value;
}
void MacroActionAudioEdit::VolumeChanged(const NumberVariable<int> &value)
void MacroActionAudioEdit::VolumeChanged(int value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_volume = value;
}
@@ -569,28 +551,28 @@ void MacroActionAudioEdit::FadeChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_fade = value;
SetWidgetVisibility();
}
void MacroActionAudioEdit::DurationChanged(const Duration &dur)
void MacroActionAudioEdit::DurationChanged(double seconds)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_duration = dur;
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_duration.seconds = seconds;
}
void MacroActionAudioEdit::RateChanged(const NumberVariable<double> &value)
void MacroActionAudioEdit::RateChanged(double value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_rate = value;
}
@@ -600,7 +582,7 @@ void MacroActionAudioEdit::WaitChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_wait = value;
}
@@ -610,7 +592,7 @@ void MacroActionAudioEdit::AbortActiveFadeChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_abortActiveFade = value;
}
@@ -620,9 +602,7 @@ void MacroActionAudioEdit::FadeTypeChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_fadeType = static_cast<MacroActionAudio::FadeType>(value);
SetWidgetVisibility();
}
} // namespace advss

View File

@@ -9,8 +9,6 @@
#include <QCheckBox>
#include <QHBoxLayout>
namespace advss {
class MacroActionAudio : public MacroAction {
public:
MacroActionAudio(Macro *m) : MacroAction(m) {}
@@ -44,13 +42,13 @@ public:
Action _action = Action::MUTE;
FadeType _fadeType = FadeType::DURATION;
NumberVariable<int> _syncOffset = 0;
int64_t _syncOffset = 0;
obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE;
NumberVariable<double> _balance = 0.5;
NumberVariable<int> _volume = 0;
double _balance = 0.5;
int _volume = 0;
bool _fade = false;
Duration _duration;
NumberVariable<double> _rate = 100.;
double _rate = 100.;
bool _wait = false;
bool _abortActiveFade = false;
@@ -86,13 +84,13 @@ public:
private slots:
void SourceChanged(const SourceSelection &);
void ActionChanged(int value);
void SyncOffsetChanged(const NumberVariable<int> &value);
void SyncOffsetChanged(int value);
void MonitorTypeChanged(int value);
void BalanceChanged(const NumberVariable<double> &value);
void VolumeChanged(const NumberVariable<int> &value);
void BalanceChanged(double value);
void VolumeChanged(int value);
void FadeChanged(int value);
void DurationChanged(const Duration &seconds);
void RateChanged(const NumberVariable<double> &value);
void DurationChanged(double seconds);
void RateChanged(double value);
void WaitChanged(int value);
void AbortActiveFadeChanged(int value);
void FadeTypeChanged(int value);
@@ -103,13 +101,13 @@ protected:
SourceSelectionWidget *_sources;
QComboBox *_actions;
QComboBox *_fadeTypes;
VariableSpinBox *_syncOffset;
QSpinBox *_syncOffset;
QComboBox *_monitorTypes;
SliderSpinBox *_balance;
VariableSpinBox *_volumePercent;
QSpinBox *_volumePercent;
QCheckBox *_fade;
DurationSelection *_duration;
VariableDoubleSpinBox *_rate;
QDoubleSpinBox *_rate;
QCheckBox *_wait;
QCheckBox *_abortActiveFade;
QHBoxLayout *_fadeTypeLayout;
@@ -121,5 +119,3 @@ private:
bool _loading = true;
};
} // namespace advss

View File

@@ -1,12 +1,9 @@
#include "advanced-scene-switcher.hpp"
#include "switcher-data.hpp"
#include "macro-action-edit.hpp"
#include "macro-action-scene-switch.hpp"
#include "section.hpp"
#include "utility.hpp"
namespace advss {
std::map<std::string, MacroActionInfo> &MacroActionFactory::GetMap()
{
static std::map<std::string, MacroActionInfo> _methods;
@@ -157,7 +154,7 @@ std::shared_ptr<MacroSegment> MacroActionEdit::Data()
void AdvSceneSwitcher::AddMacroAction(int idx)
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -196,7 +193,7 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
void AdvSceneSwitcher::on_actionAdd_clicked()
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -214,7 +211,7 @@ void AdvSceneSwitcher::on_actionAdd_clicked()
void AdvSceneSwitcher::RemoveMacroAction(int idx)
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -240,7 +237,7 @@ void AdvSceneSwitcher::RemoveMacroAction(int idx)
void AdvSceneSwitcher::on_actionRemove_clicked()
{
if (currentActionIdx == -1) {
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -292,7 +289,7 @@ void AdvSceneSwitcher::SwapActions(Macro *m, int pos1, int pos2)
void AdvSceneSwitcher::MoveMacroActionUp(int idx)
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -307,7 +304,7 @@ void AdvSceneSwitcher::MoveMacroActionUp(int idx)
void AdvSceneSwitcher::MoveMacroActionDown(int idx)
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -322,7 +319,7 @@ void AdvSceneSwitcher::MoveMacroActionDown(int idx)
void AdvSceneSwitcher::MacroActionSelectionChanged(int idx)
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -342,7 +339,7 @@ void AdvSceneSwitcher::MacroActionSelectionChanged(int idx)
void AdvSceneSwitcher::MacroActionReorder(int to, int from)
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -364,5 +361,3 @@ void AdvSceneSwitcher::MacroActionReorder(int to, int from)
HighlightAction(to);
emit(MacroSegmentOrderChanged());
}
} // namespace advss

View File

@@ -4,8 +4,6 @@
#include <QComboBox>
#include <memory>
namespace advss {
struct MacroActionInfo {
using TCreateMethod = std::shared_ptr<MacroAction> (*)(Macro *m);
using TCreateWidgetMethod = QWidget *(*)(QWidget *parent,
@@ -53,5 +51,3 @@ private:
std::shared_ptr<MacroAction> *_entryData;
bool _loading = true;
};
} // namespace advss

View File

@@ -1,12 +1,11 @@
#include "macro-action-file.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
#include <QFile>
#include <QTextStream>
#include <QFileDialog>
namespace advss {
const std::string MacroActionFile::id = "file";
bool MacroActionFile::_registered = MacroActionFactory::Register(
@@ -56,7 +55,7 @@ void MacroActionFile::LogAction() const
bool MacroActionFile::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
_file.Save(obj, "file");
obs_data_set_string(obj, "file", _file.c_str());
_text.Save(obj, "text");
obs_data_set_int(obj, "action", static_cast<int>(_action));
return true;
@@ -65,7 +64,7 @@ bool MacroActionFile::Save(obs_data_t *obj) const
bool MacroActionFile::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_file.Load(obj, "file");
_file = obs_data_get_string(obj, "file");
_text.Load(obj, "text");
_action = static_cast<FileAction>(obs_data_get_int(obj, "action"));
return true;
@@ -73,7 +72,7 @@ bool MacroActionFile::Load(obs_data_t *obj)
std::string MacroActionFile::GetShortDesc() const
{
return _file.UnresolvedValue();
return _file;
}
static inline void populateActionSelection(QComboBox *list)
@@ -107,7 +106,7 @@ MacroActionFileEdit::MacroActionFileEdit(
{"{{matchText}}", _text},
{"{{actions}}", _actions},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.file.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.action.file.entry"),
entryLayout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
@@ -140,7 +139,7 @@ void MacroActionFileEdit::PathChanged(const QString &text)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_file = text.toUtf8().constData();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
@@ -152,7 +151,7 @@ void MacroActionFileEdit::TextChanged()
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_text = _text->toPlainText().toStdString();
adjustSize();
@@ -165,8 +164,6 @@ void MacroActionFileEdit::ActionChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_action = static_cast<FileAction>(value);
}
} // namespace advss

View File

@@ -5,8 +5,6 @@
#include <QSpinBox>
namespace advss {
enum class FileAction {
WRITE,
APPEND,
@@ -26,8 +24,9 @@ public:
return std::make_shared<MacroActionFile>(m);
}
StringVariable _file = obs_module_text("AdvSceneSwitcher.enterPath");
StringVariable _text = obs_module_text("AdvSceneSwitcher.enterText");
std::string _file = obs_module_text("AdvSceneSwitcher.enterPath");
VariableResolvingString _text =
obs_module_text("AdvSceneSwitcher.enterText");
FileAction _action = FileAction::WRITE;
private:
@@ -67,5 +66,3 @@ protected:
private:
bool _loading = true;
};
} // namespace advss

View File

@@ -1,8 +1,7 @@
#include "macro-action-filter.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
namespace advss {
const std::string MacroActionFilter::id = "filter";
bool MacroActionFilter::_registered = MacroActionFactory::Register(
@@ -19,9 +18,24 @@ const static std::map<MacroActionFilter::Action, std::string> actionTypes = {
"AdvSceneSwitcher.action.filter.type.settings"},
};
void MacroActionFilter::ResolveVariables()
{
if (_source.GetType() == SourceSelection::Type::SOURCE) {
return;
}
std::string name = GetWeakSourceName(_filter);
if (!name.empty()) {
_filterName = name;
}
_filter = GetWeakFilterByName(_source.GetSource(), _filterName.c_str());
}
bool MacroActionFilter::PerformAction()
{
auto s = obs_weak_source_get_source(_filter.GetFilter(_source));
ResolveVariables();
auto s = obs_weak_source_get_source(_filter);
switch (_action) {
case Action::ENABLE:
obs_source_set_enabled(s, true);
@@ -30,7 +44,7 @@ bool MacroActionFilter::PerformAction()
obs_source_set_enabled(s, false);
break;
case Action::SETTINGS:
SetSourceSettings(s, _settings);
setSourceSettings(s, _settings);
break;
default:
break;
@@ -45,7 +59,7 @@ void MacroActionFilter::LogAction() const
if (it != actionTypes.end()) {
vblog(LOG_INFO,
"performed action \"%s\" for filter \"%s\" on source \"%s\"",
it->second.c_str(), _filter.ToString().c_str(),
it->second.c_str(), GetWeakSourceName(_filter).c_str(),
_source.ToString(true).c_str());
} else {
blog(LOG_WARNING, "ignored unknown filter action %d",
@@ -57,7 +71,7 @@ bool MacroActionFilter::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
_source.Save(obj);
_filter.Save(obj, "filter");
obs_data_set_string(obj, "filter", _filterName.c_str());
obs_data_set_int(obj, "action", static_cast<int>(_action));
_settings.Save(obj, "settings");
return true;
@@ -67,7 +81,9 @@ bool MacroActionFilter::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_source.Load(obj);
_filter.Load(obj, _source, "filter");
_filterName = obs_data_get_string(obj, "filter");
_filter = GetWeakFilterByQString(_source.GetSource(),
_filterName.c_str());
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
_settings.Load(obj, "settings");
return true;
@@ -75,8 +91,8 @@ bool MacroActionFilter::Load(obs_data_t *obj)
std::string MacroActionFilter::GetShortDesc() const
{
if (!_filter.ToString().empty() && !_source.ToString().empty()) {
return _source.ToString() + " - " + _filter.ToString();
if (_filter && !_source.ToString().empty()) {
return _source.ToString() + " - " + GetWeakSourceName(_filter);
}
return "";
}
@@ -92,7 +108,7 @@ MacroActionFilterEdit::MacroActionFilterEdit(
QWidget *parent, std::shared_ptr<MacroActionFilter> entryData)
: QWidget(parent),
_sources(new SourceSelectionWidget(this, QStringList(), true)),
_filters(new FilterSelectionWidget(this, _sources, true)),
_filters(new QComboBox()),
_actions(new QComboBox()),
_getSettings(new QPushButton(obs_module_text(
"AdvSceneSwitcher.action.filter.getSettings"))),
@@ -110,9 +126,8 @@ MacroActionFilterEdit::MacroActionFilterEdit(
QWidget::connect(_sources,
SIGNAL(SourceChanged(const SourceSelection &)), this,
SLOT(SourceChanged(const SourceSelection &)));
QWidget::connect(_filters,
SIGNAL(FilterChanged(const FilterSelection &)), this,
SLOT(FilterChanged(const FilterSelection &)));
QWidget::connect(_filters, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(FilterChanged(const QString &)));
QWidget::connect(_getSettings, SIGNAL(clicked()), this,
SLOT(GetSettingsClicked()));
QWidget::connect(_settings, SIGNAL(textChanged()), this,
@@ -125,13 +140,12 @@ MacroActionFilterEdit::MacroActionFilterEdit(
{"{{actions}}", _actions}, {"{{settings}}", _settings},
{"{{getSettings}}", _getSettings},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.filter.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.action.filter.entry"),
entryLayout, widgetPlaceholders);
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addWidget(_getSettings);
buttonLayout->addStretch();
buttonLayout->setContentsMargins(0, 0, 0, 0);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(entryLayout);
@@ -152,7 +166,9 @@ void MacroActionFilterEdit::UpdateEntryData()
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
_sources->SetSource(_entryData->_source);
_filters->SetFilter(_entryData->_source, _entryData->_filter);
populateFilterSelection(_filters, _entryData->_source.GetSource());
_filters->setCurrentText(
GetWeakSourceName(_entryData->_filter).c_str());
_settings->setPlainText(_entryData->_settings);
SetWidgetVisibility(_entryData->_action ==
MacroActionFilter::Action::SETTINGS);
@@ -166,19 +182,25 @@ void MacroActionFilterEdit::SourceChanged(const SourceSelection &source)
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_source = source;
{
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_source = source;
}
_filters->clear();
populateFilterSelection(_filters, _entryData->_source.GetSource());
_filters->adjustSize();
}
void MacroActionFilterEdit::FilterChanged(const FilterSelection &filter)
void MacroActionFilterEdit::FilterChanged(const QString &text)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_filter = filter;
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_filterName = text.toStdString();
_entryData->_filter =
GetWeakFilterByQString(_entryData->_source.GetSource(), text);
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
@@ -189,7 +211,7 @@ void MacroActionFilterEdit::ActionChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_action = static_cast<MacroActionFilter::Action>(value);
SetWidgetVisibility(_entryData->_action ==
MacroActionFilter::Action::SETTINGS);
@@ -197,13 +219,13 @@ void MacroActionFilterEdit::ActionChanged(int value)
void MacroActionFilterEdit::GetSettingsClicked()
{
if (_loading || !_entryData ||
!_entryData->_filter.GetFilter(_entryData->_source)) {
if (_loading || !_entryData || !_entryData->_source.GetSource() ||
!_entryData->_filter) {
return;
}
_settings->setPlainText(FormatJsonString(GetSourceSettings(
_entryData->_filter.GetFilter(_entryData->_source))));
_settings->setPlainText(
formatJsonString(getSourceSettings(_entryData->_filter)));
}
void MacroActionFilterEdit::SettingsChanged()
@@ -212,7 +234,7 @@ void MacroActionFilterEdit::SettingsChanged()
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_settings = _settings->toPlainText().toStdString();
adjustSize();
@@ -224,7 +246,4 @@ void MacroActionFilterEdit::SetWidgetVisibility(bool showSettings)
_settings->setVisible(showSettings);
_getSettings->setVisible(showSettings);
adjustSize();
updateGeometry();
}
} // namespace advss

View File

@@ -2,14 +2,11 @@
#include "macro-action-edit.hpp"
#include "variable-text-edit.hpp"
#include "source-selection.hpp"
#include "filter-selection.hpp"
#include <QComboBox>
#include <QSpinBox>
#include <QPushButton>
namespace advss {
class MacroActionFilter : public MacroAction {
public:
MacroActionFilter(Macro *m) : MacroAction(m) {}
@@ -31,13 +28,18 @@ public:
};
SourceSelection _source;
FilterSelection _filter;
OBSWeakSource _filter;
Action _action = Action::ENABLE;
StringVariable _settings = "";
VariableResolvingString _settings = "";
private:
void ResolveVariables();
std::string _filterName = "";
static bool _registered;
static const std::string id;
friend class MacroActionFilterEdit;
};
class MacroActionFilterEdit : public QWidget {
@@ -58,7 +60,7 @@ public:
private slots:
void SourceChanged(const SourceSelection &);
void FilterChanged(const FilterSelection &);
void FilterChanged(const QString &);
void ActionChanged(int value);
void GetSettingsClicked();
void SettingsChanged();
@@ -67,7 +69,7 @@ signals:
protected:
SourceSelectionWidget *_sources;
FilterSelectionWidget *_filters;
QComboBox *_filters;
QComboBox *_actions;
QPushButton *_getSettings;
VariableTextEdit *_settings;
@@ -77,5 +79,3 @@ private:
void SetWidgetVisibility(bool);
bool _loading = true;
};
} // namespace advss

View File

@@ -1,11 +1,8 @@
#include "macro-action-hotkey.hpp"
#include "platform-funcs.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
#include <obs-interaction.h>
namespace advss {
const std::string MacroActionHotkey::id = "hotkey";
bool MacroActionHotkey::_registered = MacroActionFactory::Register(
@@ -133,8 +130,7 @@ static std::unordered_map<HotkeyType, long> keyTable = {
//{HotkeyType::Key_NumpadEnter, ???},
};
static obs_key_combination
keysToOBSKeycombo(const std::vector<HotkeyType> &keys)
obs_key_combination keysToOBSKeycombo(const std::vector<HotkeyType> &keys)
{
obs_key_combination combo{};
auto it = keyTable.find(keys.back());
@@ -182,7 +178,7 @@ keysToOBSKeycombo(const std::vector<HotkeyType> &keys)
return combo;
}
static void InjectKeys(const std::vector<HotkeyType> &keys, int duration)
void InjectKeys(const std::vector<HotkeyType> &keys, int duration)
{
auto combo = keysToOBSKeycombo(keys);
if (obs_key_combination_is_empty(combo)) {
@@ -228,7 +224,7 @@ bool MacroActionHotkey::PerformAction()
}
if (!keys.empty()) {
int dur = _duration.Milliseconds();
int dur = _duration;
if (_onlySendToObs || !canSimulateKeyPresses) {
std::thread t([keys, dur]() { InjectKeys(keys, dur); });
t.detach();
@@ -258,9 +254,8 @@ bool MacroActionHotkey::Save(obs_data_t *obj) const
obs_data_set_bool(obj, "right_alt", _rightAlt);
obs_data_set_bool(obj, "left_meta", _leftMeta);
obs_data_set_bool(obj, "right_meta", _rightMeta);
_duration.Save(obj);
obs_data_set_int(obj, "duration", _duration);
obs_data_set_bool(obj, "onlyOBS", _onlySendToObs);
obs_data_set_int(obj, "version", 1);
return true;
}
@@ -276,11 +271,7 @@ bool MacroActionHotkey::Load(obs_data_t *obj)
_rightAlt = obs_data_get_bool(obj, "right_alt");
_leftMeta = obs_data_get_bool(obj, "left_meta");
_rightMeta = obs_data_get_bool(obj, "right_meta");
if (!obs_data_has_user_value(obj, "version")) {
_duration = obs_data_get_int(obj, "duration") / 1000.0;
} else {
_duration.Load(obj);
}
_duration = obs_data_get_int(obj, "duration");
_onlySendToObs = obs_data_get_bool(obj, "onlyOBS");
return true;
}
@@ -397,30 +388,32 @@ static inline void populateKeySelection(QComboBox *list)
MacroActionHotkeyEdit::MacroActionHotkeyEdit(
QWidget *parent, std::shared_ptr<MacroActionHotkey> entryData)
: QWidget(parent),
_keys(new QComboBox()),
_leftShift(new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.leftShift"))),
_rightShift(new QCheckBox(obs_module_text(
"AdvSceneSwitcher.action.hotkey.rightShift"))),
_leftCtrl(new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.leftCtrl"))),
_rightCtrl(new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.rightCtrl"))),
_leftAlt(new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.leftAlt"))),
_rightAlt(new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.rightAlt"))),
_leftMeta(new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.leftMeta"))),
_rightMeta(new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.rightMeta"))),
_duration(new DurationSelection(this, false)),
_onlySendToOBS(new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.onlyOBS"))),
_noKeyPressSimulationWarning(new QLabel(
obs_module_text("AdvSceneSwitcher.action.hotkey.disabled")))
: QWidget(parent)
{
_keys = new QComboBox();
_leftShift = new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.leftShift"));
_rightShift = new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.rightShift"));
_leftCtrl = new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.leftCtrl"));
_rightCtrl = new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.rightCtrl"));
_leftAlt = new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.leftAlt"));
_rightAlt = new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.rightAlt"));
_leftMeta = new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.leftMeta"));
_rightMeta = new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.rightMeta"));
_duration = new QSpinBox();
_duration->setMaximum(5000);
_onlySendToOBS = new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.hotkey.onlyOBS"));
_noKeyPressSimulationWarning = new QLabel(
obs_module_text("AdvSceneSwitcher.action.hotkey.disabled"));
populateKeySelection(_keys);
QWidget::connect(_keys, SIGNAL(currentIndexChanged(int)), this,
@@ -441,8 +434,8 @@ MacroActionHotkeyEdit::MacroActionHotkeyEdit(
SLOT(LMetaChanged(int)));
QWidget::connect(_rightMeta, SIGNAL(stateChanged(int)), this,
SLOT(RMetaChanged(int)));
QWidget::connect(_duration, SIGNAL(DurationChanged(const Duration &)),
this, SLOT(DurationChanged(const Duration &)));
QWidget::connect(_duration, SIGNAL(valueChanged(int)), this,
SLOT(DurationChanged(int)));
QWidget::connect(_onlySendToOBS, SIGNAL(stateChanged(int)), this,
SLOT(OnlySendToOBSChanged(int)));
@@ -451,7 +444,7 @@ MacroActionHotkeyEdit::MacroActionHotkeyEdit(
{"{{keys}}", _keys},
{"{{duration}}", _duration},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.hotkey.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.action.hotkey.entry"),
line1Layout, widgetPlaceholders);
QHBoxLayout *line2Layout = new QHBoxLayout;
@@ -500,7 +493,7 @@ void MacroActionHotkeyEdit::UpdateEntryData()
_rightAlt->setChecked(_entryData->_rightAlt);
_leftMeta->setChecked(_entryData->_leftMeta);
_rightMeta->setChecked(_entryData->_rightMeta);
_duration->SetDuration(_entryData->_duration);
_duration->setValue(_entryData->_duration);
_onlySendToOBS->setChecked(_entryData->_onlySendToObs ||
!canSimulateKeyPresses);
SetWarningVisibility();
@@ -512,7 +505,7 @@ void MacroActionHotkeyEdit::LShiftChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_leftShift = state;
}
@@ -522,7 +515,7 @@ void MacroActionHotkeyEdit::RShiftChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_rightShift = state;
}
@@ -532,7 +525,7 @@ void MacroActionHotkeyEdit::LCtrlChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_leftCtrl = state;
}
@@ -542,7 +535,7 @@ void MacroActionHotkeyEdit::RCtrlChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_rightCtrl = state;
}
@@ -552,7 +545,7 @@ void MacroActionHotkeyEdit::LAltChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_leftAlt = state;
}
@@ -562,7 +555,7 @@ void MacroActionHotkeyEdit::RAltChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_rightAlt = state;
}
@@ -572,7 +565,7 @@ void MacroActionHotkeyEdit::LMetaChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_leftMeta = state;
}
@@ -582,18 +575,18 @@ void MacroActionHotkeyEdit::RMetaChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_rightMeta = state;
}
void MacroActionHotkeyEdit::DurationChanged(const Duration &dur)
void MacroActionHotkeyEdit::DurationChanged(int ms)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_duration = dur;
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_duration = ms;
}
void MacroActionHotkeyEdit::OnlySendToOBSChanged(int state)
@@ -602,7 +595,7 @@ void MacroActionHotkeyEdit::OnlySendToOBSChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_onlySendToObs = state;
SetWarningVisibility();
}
@@ -613,8 +606,6 @@ void MacroActionHotkeyEdit::KeyChanged(int key)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_key = static_cast<HotkeyType>(key);
}
} // namespace advss

View File

@@ -1,15 +1,12 @@
#pragma once
#include "macro-action-edit.hpp"
#include "hotkey.hpp"
#include "duration-control.hpp"
#include <QComboBox>
#include <QCheckBox>
#include <QSpinBox>
#include <QHBoxLayout>
namespace advss {
class MacroActionHotkey : public MacroAction {
public:
MacroActionHotkey(Macro *m) : MacroAction(m) {}
@@ -33,7 +30,7 @@ public:
bool _rightAlt = false;
bool _leftMeta = false;
bool _rightMeta = false;
Duration _duration = 0.3;
int _duration = 300; // in ms
#ifdef __APPLE__
bool _onlySendToObs = true;
#else
@@ -71,7 +68,7 @@ private slots:
void RAltChanged(int state);
void LMetaChanged(int state);
void RMetaChanged(int state);
void DurationChanged(const Duration &);
void DurationChanged(int ms);
void OnlySendToOBSChanged(int state);
protected:
@@ -84,7 +81,7 @@ protected:
QCheckBox *_rightAlt;
QCheckBox *_leftMeta;
QCheckBox *_rightMeta;
DurationSelection *_duration;
QSpinBox *_duration;
QCheckBox *_onlySendToOBS;
QLabel *_noKeyPressSimulationWarning;
@@ -95,5 +92,3 @@ private:
QHBoxLayout *_mainLayout;
bool _loading = true;
};
} // namespace advss

View File

@@ -1,10 +1,8 @@
#include "macro-action-http.hpp"
#include "switcher-data.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
#include "curl-helper.hpp"
namespace advss {
const std::string MacroActionHttp::id = "http";
bool MacroActionHttp::_registered = MacroActionFactory::Register(
@@ -18,37 +16,22 @@ const static std::map<MacroActionHttp::Method, std::string> methods = {
"AdvSceneSwitcher.action.http.type.post"},
};
static size_t DropCB(void *, size_t size, size_t nmemb, std::string *)
size_t DropCB(void *, size_t size, size_t nmemb, std::string *)
{
return size * nmemb;
}
static size_t WriteCB(void *ptr, size_t size, size_t nmemb, std::string *buffer)
size_t WriteCB(void *ptr, size_t size, size_t nmemb, std::string *buffer)
{
buffer->append((char *)ptr, nmemb);
return size * nmemb;
}
void MacroActionHttp::SetupHeaders()
{
if (!_setHeaders) {
return;
}
struct curl_slist *headers = nullptr;
for (auto &header : _headers) {
headers = switcher->curl.SlistAppend(headers, header.c_str());
}
if (!_headers.empty()) {
switcher->curl.SetOpt(CURLOPT_HTTPHEADER, headers);
}
}
void MacroActionHttp::Get()
{
switcher->curl.SetOpt(CURLOPT_URL, _url.c_str());
switcher->curl.SetOpt(CURLOPT_HTTPGET, 1L);
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
SetupHeaders();
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, _timeout.seconds * 1000);
std::string response;
if (IsReferencedInVars()) {
@@ -66,8 +49,7 @@ void MacroActionHttp::Post()
{
switcher->curl.SetOpt(CURLOPT_URL, _url.c_str());
switcher->curl.SetOpt(CURLOPT_POSTFIELDS, _data.c_str());
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, _timeout.Milliseconds());
SetupHeaders();
switcher->curl.SetOpt(CURLOPT_TIMEOUT_MS, _timeout.seconds * 1000);
switcher->curl.Perform();
}
@@ -108,10 +90,8 @@ void MacroActionHttp::LogAction() const
bool MacroActionHttp::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
_url.Save(obj, "url");
obs_data_set_string(obj, "url", _url.c_str());
_data.Save(obj, "data");
obs_data_set_bool(obj, "setHeaders", _setHeaders);
_headers.Save(obj, "headers", "header");
obs_data_set_int(obj, "method", static_cast<int>(_method));
_timeout.Save(obj);
return true;
@@ -120,10 +100,8 @@ bool MacroActionHttp::Save(obs_data_t *obj) const
bool MacroActionHttp::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_url.Load(obj, "url");
_url = obs_data_get_string(obj, "url");
_data.Load(obj, "data");
_setHeaders = obs_data_get_bool(obj, "setHeaders");
_headers.Load(obj, "headers", "header");
_method = static_cast<Method>(obs_data_get_int(obj, "method"));
_timeout.Load(obj);
return true;
@@ -131,7 +109,7 @@ bool MacroActionHttp::Load(obs_data_t *obj)
std::string MacroActionHttp::GetShortDesc() const
{
return _url.UnresolvedValue();
return _url;
}
static inline void populateMethodSelection(QComboBox *list)
@@ -144,15 +122,9 @@ static inline void populateMethodSelection(QComboBox *list)
MacroActionHttpEdit::MacroActionHttpEdit(
QWidget *parent, std::shared_ptr<MacroActionHttp> entryData)
: QWidget(parent),
_url(new VariableLineEdit(this)),
_url(new QLineEdit()),
_methods(new QComboBox()),
_data(new VariableTextEdit(this)),
_setHeaders(new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.http.setHeaders"))),
_headerListLayout(new QVBoxLayout()),
_headerList(new StringListEdit(
this, obs_module_text("AdvSceneSwitcher.action.http.headers"),
obs_module_text("AdvSceneSwitcher.action.http.addHeader"))),
_timeout(new DurationSelection(this, false))
{
populateMethodSelection(_methods);
@@ -163,13 +135,8 @@ MacroActionHttpEdit::MacroActionHttpEdit(
SLOT(DataChanged()));
QWidget::connect(_methods, SIGNAL(currentIndexChanged(int)), this,
SLOT(MethodChanged(int)));
QWidget::connect(_setHeaders, SIGNAL(stateChanged(int)), this,
SLOT(SetHeadersChanged(int)));
QWidget::connect(_headerList,
SIGNAL(StringListChanged(const StringList &)), this,
SLOT(HeadersChanged(const StringList &)));
QWidget::connect(_timeout, SIGNAL(DurationChanged(const Duration &)),
this, SLOT(TimeoutChanged(const Duration &)));
QWidget::connect(_timeout, SIGNAL(DurationChanged(double)), this,
SLOT(TimeoutChanged(double)));
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{url}}", _url},
@@ -178,22 +145,16 @@ MacroActionHttpEdit::MacroActionHttpEdit(
{"{{timeout}}", _timeout},
};
auto *actionLayout = new QHBoxLayout;
PlaceWidgets(
placeWidgets(
obs_module_text("AdvSceneSwitcher.action.http.entry.line1"),
actionLayout, widgetPlaceholders);
auto *timeoutLayout = new QHBoxLayout;
PlaceWidgets(
placeWidgets(
obs_module_text("AdvSceneSwitcher.action.http.entry.line2"),
timeoutLayout, widgetPlaceholders);
_headerListLayout->addWidget(new QLabel(
obs_module_text("AdvSceneSwitcher.action.http.headers")));
_headerListLayout->addWidget(_headerList);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(actionLayout);
mainLayout->addWidget(_setHeaders);
mainLayout->addLayout(_headerListLayout);
mainLayout->addWidget(_data);
mainLayout->addLayout(timeoutLayout);
setLayout(mainLayout);
@@ -209,10 +170,8 @@ void MacroActionHttpEdit::UpdateEntryData()
return;
}
_url->setText(_entryData->_url);
_url->setText(QString::fromStdString(_entryData->_url));
_data->setPlainText(_entryData->_data);
_setHeaders->setChecked(_entryData->_setHeaders);
_headerList->SetStringList(_entryData->_headers);
_methods->setCurrentIndex(static_cast<int>(_entryData->_method));
_timeout->SetDuration(_entryData->_timeout);
SetWidgetVisibility();
@@ -224,7 +183,7 @@ void MacroActionHttpEdit::URLChanged()
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_url = _url->text().toStdString();
emit(HeaderInfoChanged(_url->text()));
}
@@ -235,48 +194,33 @@ void MacroActionHttpEdit::MethodChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_method = static_cast<MacroActionHttp::Method>(value);
SetWidgetVisibility();
}
void MacroActionHttpEdit::TimeoutChanged(const Duration &dur)
void MacroActionHttpEdit::TimeoutChanged(double seconds)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_timeout = dur;
}
void MacroActionHttpEdit::SetHeadersChanged(int value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_setHeaders = value;
SetWidgetVisibility();
}
void MacroActionHttpEdit::HeadersChanged(const StringList &headers)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_headers = headers;
adjustSize();
updateGeometry();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_timeout.seconds = seconds;
}
void MacroActionHttpEdit::SetWidgetVisibility()
{
_data->setVisible(_entryData->_method == MacroActionHttp::Method::POST);
SetLayoutVisible(_headerListLayout, _entryData->_setHeaders);
switch (_entryData->_method) {
case MacroActionHttp::Method::GET:
_data->hide();
break;
case MacroActionHttp::Method::POST:
_data->show();
break;
default:
break;
}
adjustSize();
updateGeometry();
@@ -288,11 +232,9 @@ void MacroActionHttpEdit::DataChanged()
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_data = _data->toPlainText().toUtf8().constData();
adjustSize();
updateGeometry();
}
} // namespace advss

View File

@@ -1,15 +1,10 @@
#pragma once
#include "macro-action-edit.hpp"
#include "variable-text-edit.hpp"
#include "variable-line-edit.hpp"
#include "duration-control.hpp"
#include "string-list.hpp"
#include <QLineEdit>
#include <QComboBox>
#include <QCheckBox>
namespace advss {
class MacroActionHttp : public MacroAction {
public:
@@ -30,15 +25,13 @@ public:
POST,
};
StringVariable _url = obs_module_text("AdvSceneSwitcher.enterURL");
StringVariable _data = obs_module_text("AdvSceneSwitcher.enterText");
bool _setHeaders = false;
StringList _headers;
std::string _url = obs_module_text("AdvSceneSwitcher.enterURL");
VariableResolvingString _data =
obs_module_text("AdvSceneSwitcher.enterText");
Method _method = Method::GET;
Duration _timeout = Duration(1.0);
Duration _timeout;
private:
void SetupHeaders();
void Get();
void Post();
@@ -66,9 +59,7 @@ private slots:
void DataChanged();
void URLChanged();
void MethodChanged(int);
void TimeoutChanged(const Duration &seconds);
void SetHeadersChanged(int);
void HeadersChanged(const StringList &);
void TimeoutChanged(double seconds);
signals:
void HeaderInfoChanged(const QString &);
@@ -78,14 +69,9 @@ protected:
private:
void SetWidgetVisibility();
VariableLineEdit *_url;
QLineEdit *_url;
QComboBox *_methods;
VariableTextEdit *_data;
QCheckBox *_setHeaders;
QVBoxLayout *_headerListLayout;
StringListEdit *_headerList;
DurationSelection *_timeout;
bool _loading = true;
};
} // namespace advss

View File

@@ -1,9 +1,7 @@
#include "macro-action-macro.hpp"
#include "macro.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
namespace advss {
const std::string MacroActionMacro::id = "macro";
bool MacroActionMacro::_registered = MacroActionFactory::Register(
@@ -23,28 +21,27 @@ const static std::map<PerformMacroAction, std::string> actionTypes = {
bool MacroActionMacro::PerformAction()
{
auto macro = _macro.GetMacro();
if (!macro) {
if (!_macro.get()) {
return true;
}
switch (_action) {
case PerformMacroAction::PAUSE:
macro->SetPaused();
_macro->SetPaused();
break;
case PerformMacroAction::UNPAUSE:
macro->SetPaused(false);
_macro->SetPaused(false);
break;
case PerformMacroAction::RESET_COUNTER:
macro->ResetRunCount();
_macro->ResetRunCount();
break;
case PerformMacroAction::RUN:
if (!macro->Paused()) {
macro->PerformActions();
if (!_macro->Paused()) {
_macro->PerformActions();
}
break;
case PerformMacroAction::STOP:
macro->Stop();
_macro->Stop();
break;
default:
break;
@@ -54,27 +51,26 @@ bool MacroActionMacro::PerformAction()
void MacroActionMacro::LogAction() const
{
auto macro = _macro.GetMacro();
if (!macro) {
if (!_macro.get()) {
return;
}
switch (_action) {
case PerformMacroAction::PAUSE:
vblog(LOG_INFO, "paused \"%s\"", macro->Name().c_str());
vblog(LOG_INFO, "paused \"%s\"", _macro->Name().c_str());
break;
case PerformMacroAction::UNPAUSE:
vblog(LOG_INFO, "unpaused \"%s\"", macro->Name().c_str());
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());
_macro->Name().c_str());
break;
case PerformMacroAction::RUN:
vblog(LOG_INFO, "run nested macro \"%s\"",
macro->Name().c_str());
_macro->Name().c_str());
break;
case PerformMacroAction::STOP:
vblog(LOG_INFO, "stopped macro \"%s\"", macro->Name().c_str());
vblog(LOG_INFO, "stopped macro \"%s\"", _macro->Name().c_str());
break;
default:
break;
@@ -100,7 +96,10 @@ bool MacroActionMacro::Load(obs_data_t *obj)
std::string MacroActionMacro::GetShortDesc() const
{
return _macro.Name();
if (_macro.get()) {
return _macro->Name();
}
return "";
}
static inline void populateActionSelection(QComboBox *list)
@@ -121,6 +120,8 @@ MacroActionMacroEdit::MacroActionMacroEdit(
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)));
@@ -129,7 +130,7 @@ MacroActionMacroEdit::MacroActionMacroEdit(
{"{{actions}}", _actions},
{"{{macros}}", _macros},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.macro.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.action.macro.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -144,7 +145,7 @@ void MacroActionMacroEdit::UpdateEntryData()
return;
}
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
_macros->SetCurrentMacro(_entryData->_macro);
_macros->SetCurrentMacro(_entryData->_macro.get());
if (_entryData->_action == PerformMacroAction::RUN ||
_entryData->_action == PerformMacroAction::STOP) {
_macros->HideSelectedMacro();
@@ -157,8 +158,8 @@ void MacroActionMacroEdit::MacroChanged(const QString &text)
return;
}
auto lock = LockContext();
_entryData->_macro = text;
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_macro.UpdateRef(text);
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
@@ -169,7 +170,7 @@ void MacroActionMacroEdit::ActionChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_action = static_cast<PerformMacroAction>(value);
if (_entryData->_action == PerformMacroAction::RUN ||
@@ -180,4 +181,9 @@ void MacroActionMacroEdit::ActionChanged(int value)
}
}
} // namespace advss
void MacroActionMacroEdit::MacroRemove(const QString &)
{
if (_entryData) {
_entryData->_macro.UpdateRef();
}
}

View File

@@ -4,8 +4,6 @@
#include <QHBoxLayout>
namespace advss {
enum class PerformMacroAction {
PAUSE,
UNPAUSE,
@@ -53,6 +51,7 @@ public:
private slots:
void MacroChanged(const QString &text);
void MacroRemove(const QString &name);
void ActionChanged(int value);
signals:
void HeaderInfoChanged(const QString &);
@@ -66,5 +65,3 @@ private:
QHBoxLayout *_mainLayout;
bool _loading = true;
};
} // namespace advss

View File

@@ -1,8 +1,7 @@
#include "macro-action-media.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
namespace advss {
const std::string MacroActionMedia::id = "media";
bool MacroActionMedia::_registered = MacroActionFactory::Register(
@@ -49,7 +48,7 @@ bool MacroActionMedia::PerformAction()
obs_source_media_previous(source);
break;
case MediaAction::SEEK:
obs_source_media_set_time(source, _seek.Milliseconds());
obs_source_media_set_time(source, _seek.seconds * 1000);
break;
default:
break;
@@ -117,8 +116,10 @@ MacroActionMediaEdit::MacroActionMediaEdit(
QWidget::connect(_sources,
SIGNAL(SourceChanged(const SourceSelection &)), this,
SLOT(SourceChanged(const SourceSelection &)));
QWidget::connect(_seek, SIGNAL(DurationChanged(const Duration &)), this,
SLOT(DurationChanged(const Duration &)));
QWidget::connect(_seek, SIGNAL(DurationChanged(double)), this,
SLOT(DurationChanged(double)));
QWidget::connect(_seek, SIGNAL(UnitChanged(DurationUnit)), this,
SLOT(DurationUnitChanged(DurationUnit)));
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
@@ -126,7 +127,7 @@ MacroActionMediaEdit::MacroActionMediaEdit(
{"{{actions}}", _actions},
{"{{duration}}", _seek},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.media.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.action.media.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -153,7 +154,7 @@ void MacroActionMediaEdit::SourceChanged(const SourceSelection &source)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_mediaSource = source;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
@@ -165,19 +166,29 @@ void MacroActionMediaEdit::ActionChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_action = static_cast<MediaAction>(value);
SetWidgetVisibility();
}
void MacroActionMediaEdit::DurationChanged(const Duration &dur)
void MacroActionMediaEdit::DurationChanged(double seconds)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_seek = dur;
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_seek.seconds = seconds;
}
void MacroActionMediaEdit::DurationUnitChanged(DurationUnit unit)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_seek.displayUnit = unit;
}
void MacroActionMediaEdit::SetWidgetVisibility()
@@ -188,5 +199,3 @@ void MacroActionMediaEdit::SetWidgetVisibility()
_seek->setVisible(_entryData->_action == MediaAction::SEEK);
adjustSize();
}
} // namespace advss

View File

@@ -6,8 +6,6 @@
#include <QSpinBox>
#include <QHBoxLayout>
namespace advss {
enum class MediaAction {
PLAY,
PAUSE,
@@ -60,7 +58,8 @@ public:
private slots:
void SourceChanged(const SourceSelection &);
void ActionChanged(int value);
void DurationChanged(const Duration &value);
void DurationChanged(double value);
void DurationUnitChanged(DurationUnit unit);
signals:
void HeaderInfoChanged(const QString &);
@@ -76,5 +75,3 @@ private:
QHBoxLayout *_mainLayout;
bool _loading = true;
};
} // namespace advss

View File

@@ -1,318 +0,0 @@
#include "macro-action-osc.hpp"
#include "utility.hpp"
#include <system_error>
#include <QGroupBox>
namespace advss {
const std::string MacroActionOSC::id = "osc";
bool MacroActionOSC::_registered = MacroActionFactory::Register(
MacroActionOSC::id, {MacroActionOSC::Create, MacroActionOSCEdit::Create,
"AdvSceneSwitcher.action.osc"});
MacroActionOSC::MacroActionOSC(Macro *m)
: MacroAction(m),
_ctx(asio::io_context()),
_tcpSocket(asio::ip::tcp::socket(_ctx)),
_udpSocket(asio::ip::udp::socket(_ctx))
{
}
void MacroActionOSC::SendOSCTCPMessage(const asio::mutable_buffer &buffer)
{
try {
asio::write(_tcpSocket, asio::buffer(buffer));
} catch (const std::exception &e) {
blog(LOG_WARNING,
"failed to send OSC message \"%s\" via TCP %s %d: %s",
_message.ToString().c_str(), _ip.c_str(), _port.GetValue(),
e.what());
}
}
void MacroActionOSC::SendOSCUDPMessage(const asio::mutable_buffer &buffer)
{
try {
_udpSocket.send_to(buffer, _updEndpoint);
} catch (const std::exception &e) {
blog(LOG_WARNING,
"failed to send OSC message \"%s\" via UDP %s %d: %s",
_message.ToString().c_str(), _ip.c_str(), _port.GetValue(),
e.what());
}
}
void MacroActionOSC::UDPReconnect()
{
asio::error_code ec;
asio::ip::udp::resolver resolver(_ctx);
auto endpoints = resolver.resolve(asio::ip::udp::v4(), _ip.c_str(),
std::to_string(_port.GetValue()), ec);
if (ec) {
endpoints = resolver.resolve(asio::ip::udp::v6(), _ip.c_str(),
std::to_string(_port.GetValue()),
ec);
}
if (ec) {
blog(LOG_WARNING, "failed to get IP for \"%s\": %s",
_ip.c_str(), ec.message().c_str());
return;
}
try {
_updEndpoint = endpoints.begin()->endpoint();
_udpSocket = asio::ip::udp::socket(_ctx);
_udpSocket.open(endpoints.begin()->endpoint().protocol());
} catch (const std::exception &e) {
blog(LOG_WARNING, "failed to connect to UDP %s %d: %s",
_ip.c_str(), _port.GetValue(), e.what());
}
}
void MacroActionOSC::TCPReconnect()
{
asio::error_code ec;
asio::ip::tcp::resolver resolver(_ctx);
auto endpoints = resolver.resolve(asio::ip::tcp::v4(), _ip.c_str(),
std::to_string(_port.GetValue()), ec);
if (ec) {
endpoints = resolver.resolve(asio::ip::tcp::v6(), _ip.c_str(),
std::to_string(_port.GetValue()),
ec);
}
if (ec) {
blog(LOG_WARNING, "failed to get IP for \"%s\": %s",
_ip.c_str(), ec.message().c_str());
return;
}
try {
_tcpSocket = asio::ip::tcp::socket(_ctx);
_tcpSocket.connect(endpoints.begin()->endpoint());
} catch (const std::exception &e) {
blog(LOG_WARNING, "failed to connect to TCP %s %d: %s",
_ip.c_str(), _port.GetValue(), e.what());
}
}
void MacroActionOSC::CheckReconnect()
{
if (_protocol == Protocol::TCP &&
(_reconnect || !_tcpSocket.is_open())) {
TCPReconnect();
}
if (_protocol == Protocol::UDP &&
(_reconnect || !_udpSocket.is_open())) {
UDPReconnect();
}
}
bool MacroActionOSC::PerformAction()
{
auto buffer = _message.GetBuffer();
if (!buffer.has_value()) {
blog(LOG_WARNING, "failed to create or fill OSC buffer!");
return true;
}
CheckReconnect();
if (_protocol == Protocol::TCP &&
(_reconnect || !_tcpSocket.is_open())) {
TCPReconnect();
}
if (_protocol == Protocol::UDP &&
(_reconnect || !_udpSocket.is_open())) {
UDPReconnect();
}
auto rawMessage = asio::buffer(*buffer);
switch (_protocol) {
case MacroActionOSC::Protocol::TCP:
SendOSCTCPMessage(rawMessage);
break;
case MacroActionOSC::Protocol::UDP:
SendOSCUDPMessage(rawMessage);
break;
default:
break;
}
return true;
}
void MacroActionOSC::LogAction() const
{
vblog(LOG_INFO, "sending OSC message '%s' to %s %s %d",
_message.ToString().c_str(),
_protocol == Protocol::UDP ? "UDP" : "TCP", _ip.c_str(),
_port.GetValue());
}
bool MacroActionOSC::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
obs_data_set_int(obj, "protocol", static_cast<int>(_protocol));
_ip.Save(obj, "ip");
_port.Save(obj, "port");
_message.Save(obj);
return true;
}
bool MacroActionOSC::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_protocol = static_cast<Protocol>(obs_data_get_int(obj, "protocol"));
_ip.Load(obj, "ip");
_port.Load(obj, "port");
_message.Load(obj);
return true;
}
void MacroActionOSC::SetProtocol(Protocol p)
{
_protocol = p;
_reconnect = true;
}
void MacroActionOSC::SetIP(const std::string &ip)
{
_ip = ip;
_reconnect = true;
}
void MacroActionOSC::SetPortNr(IntVariable port)
{
_port = port;
_reconnect = true;
}
static void populateProtocolSelection(QComboBox *list)
{
list->addItem("TCP");
list->addItem("UDP");
}
MacroActionOSCEdit::MacroActionOSCEdit(
QWidget *parent, std::shared_ptr<MacroActionOSC> entryData)
: QWidget(parent),
_protocol(new QComboBox(this)),
_ip(new VariableLineEdit(this)),
_port(new VariableSpinBox(this)),
_message(new OSCMessageEdit(this))
{
populateProtocolSelection(_protocol);
_port->setMaximum(65535);
auto networkGroup =
new QGroupBox(obs_module_text("AdvSceneSwitcher.osc.network"));
auto networkLayout = new QGridLayout;
int row = 0;
networkLayout->addWidget(
new QLabel(obs_module_text(
"AdvSceneSwitcher.osc.network.protocol")),
row, 0);
networkLayout->addWidget(_protocol, row, 1);
++row;
networkLayout->addWidget(
new QLabel(obs_module_text(
"AdvSceneSwitcher.osc.network.address")),
row, 0);
networkLayout->addWidget(_ip, row, 1);
++row;
networkLayout->addWidget(new QLabel(obs_module_text(
"AdvSceneSwitcher.osc.network.port")),
row, 0);
networkLayout->addWidget(_port, row, 1);
networkGroup->setLayout(networkLayout);
auto messageGroup =
new QGroupBox(obs_module_text("AdvSceneSwitcher.osc.message"));
auto messageLayout = new QHBoxLayout();
messageLayout->addWidget(_message);
messageGroup->setLayout(messageLayout);
auto mainLayout = new QVBoxLayout;
mainLayout->addWidget(networkGroup);
mainLayout->addWidget(messageGroup);
setLayout(mainLayout);
QWidget::connect(_ip, SIGNAL(editingFinished()), this,
SLOT(IpChanged()));
QWidget::connect(_protocol, SIGNAL(currentIndexChanged(int)), this,
SLOT(ProtocolChanged(int)));
QWidget::connect(
_port,
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
this, SLOT(PortChanged(const NumberVariable<int> &)));
QWidget::connect(_message, SIGNAL(MessageChanged(const OSCMessage &)),
this, SLOT(MessageChanged(const OSCMessage &)));
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
void MacroActionOSCEdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
_protocol->setCurrentIndex(static_cast<int>(_entryData->GetProtocol()));
_ip->setText(_entryData->GetIP());
_port->SetValue(_entryData->GetPortNr());
_message->SetMessage(_entryData->_message);
adjustSize();
updateGeometry();
}
void MacroActionOSCEdit::IpChanged()
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->SetIP(_ip->text().toStdString());
}
void MacroActionOSCEdit::ProtocolChanged(int value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->SetProtocol(static_cast<MacroActionOSC::Protocol>(value));
}
void MacroActionOSCEdit::PortChanged(const NumberVariable<int> &value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->SetPortNr(value);
}
void MacroActionOSCEdit::MessageChanged(const OSCMessage &m)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_message = m;
adjustSize();
updateGeometry();
}
} // namespace advss

View File

@@ -1,94 +0,0 @@
#pragma once
#include "macro-action-edit.hpp"
#include "osc-helpers.hpp"
#include <memory>
#include <asio.hpp>
namespace advss {
class MacroActionOSC : public MacroAction {
public:
MacroActionOSC(Macro *m);
bool PerformAction();
void LogAction() const;
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionOSC>(m);
}
enum class Protocol {
TCP,
UDP,
};
void SetProtocol(Protocol);
Protocol GetProtocol() const { return _protocol; }
void SetIP(const std::string &);
StringVariable GetIP() const { return _ip; }
void SetPortNr(IntVariable);
IntVariable GetPortNr() { return _port; }
OSCMessage _message;
private:
void SendOSCTCPMessage(const asio::mutable_buffer &);
void SendOSCUDPMessage(const asio::mutable_buffer &);
void CheckReconnect();
void TCPReconnect();
void UDPReconnect();
Protocol _protocol = Protocol::UDP;
StringVariable _ip = "localhost";
IntVariable _port = 12345;
bool _reconnect = true;
asio::io_context _ctx;
asio::ip::tcp::socket _tcpSocket;
asio::ip::udp::socket _udpSocket;
asio::ip::udp::endpoint _updEndpoint;
static bool _registered;
static const std::string id;
};
class MacroActionOSCEdit : public QWidget {
Q_OBJECT
public:
MacroActionOSCEdit(QWidget *parent,
std::shared_ptr<MacroActionOSC> entryData = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionOSCEdit(
parent,
std::dynamic_pointer_cast<MacroActionOSC>(action));
}
private slots:
void IpChanged();
void MessageChanged(const OSCMessage &);
void ProtocolChanged(int);
void PortChanged(const NumberVariable<int> &value);
signals:
void HeaderInfoChanged(const QString &);
protected:
std::shared_ptr<MacroActionOSC> _entryData;
private:
QComboBox *_protocol;
VariableLineEdit *_ip;
VariableSpinBox *_port;
OSCMessageEdit *_message;
bool _loading = true;
};
} // namespace advss

View File

@@ -1,20 +1,15 @@
#include "macro-action-plugin-state.hpp"
#include "switcher-data.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
#include <thread>
#include <QMainWindow>
using namespace std::chrono_literals;
namespace advss {
const std::string MacroActionPluginState::id = "plugin_state";
bool MacroActionPluginState::_registered = MacroActionFactory::Register(
MacroActionPluginState::id,
{MacroActionPluginState::Create, MacroActionPluginStateEdit::Create,
"AdvSceneSwitcher.action.pluginState"});
"AdvSceneSwitcher.action.PluginState"});
const static std::map<PluginStateAction, std::string> actionTypes = {
{PluginStateAction::STOP,
@@ -23,26 +18,24 @@ const static std::map<PluginStateAction, std::string> actionTypes = {
"AdvSceneSwitcher.action.pluginState.type.noMatch"},
{PluginStateAction::IMPORT_SETTINGS,
"AdvSceneSwitcher.action.pluginState.type.import"},
{PluginStateAction::TERMINATE,
"AdvSceneSwitcher.action.pluginState.type.terminate"},
};
const static std::map<SwitcherData::NoMatch, std::string> noMatchValues = {
{SwitcherData::NoMatch::NO_SWITCH,
const static std::map<NoMatch, std::string> noMatchValues = {
{NO_SWITCH,
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch"},
{SwitcherData::NoMatch::SWITCH,
{SWITCH,
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo"},
{SwitcherData::NoMatch::RANDOM_SWITCH,
{RANDOM_SWITCH,
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom"},
};
static void stopPlugin()
void stopPlugin()
{
std::thread t([]() { switcher->Stop(); });
t.detach();
}
static void importSettings(const std::string &path)
void importSettings(const std::string &path)
{
if (switcher->settingsWindowOpened) {
return;
@@ -51,91 +44,18 @@ static void importSettings(const std::string &path)
if (!obj) {
return;
}
switcher->LoadSettings(obj);
switcher->loadSettings(obj);
obs_data_release(obj);
}
static void setNoMatchBehaviour(int value, OBSWeakSource &scene)
void setNoMatchBehaviour(int value, OBSWeakSource &scene)
{
switcher->switchIfNotMatching =
static_cast<SwitcherData::NoMatch>(value);
if (switcher->switchIfNotMatching == SwitcherData::NoMatch::SWITCH) {
switcher->switchIfNotMatching = static_cast<NoMatch>(value);
if (switcher->switchIfNotMatching == SWITCH) {
switcher->nonMatchingScene = scene;
}
}
static void closeOBSWindow()
{
blog(LOG_WARNING, "closing OBS window now!");
auto obsWindow =
static_cast<QMainWindow *>(obs_frontend_get_main_window());
if (obsWindow) {
obsWindow->close();
} else {
blog(LOG_WARNING,
"OBS shutdown was aborted - failed to get QMainWindow");
}
}
static void terminateOBS(void *)
{
static std::mutex mtx;
static std::mutex waitMutex;
static std::condition_variable cv;
static bool abortTerminate;
static bool stopWaiting;
static std::chrono::high_resolution_clock::time_point
lastShutdownAttempt{};
// Don't allow multiple simultaneous instances of the shutdown dialog
std::unique_lock<std::mutex> lock(mtx, std::try_to_lock);
if (!lock.owns_lock()) {
blog(LOG_INFO,
"OBS shutdown dialog already triggered - ignoring additional request");
return;
}
// Prevent the user from locking himself out of controlling OBS by
// continuously opening the shutdown dialog
auto now = std::chrono::high_resolution_clock::now();
if (lastShutdownAttempt + 5s > now) {
blog(LOG_INFO,
"OBS shutdown dialog already triggered recently - ignoring request");
return;
}
lastShutdownAttempt = now;
abortTerminate = false;
stopWaiting = false;
// Give the user a 10s grace period during which the shutdown can be aborted
std::thread thread([]() {
std::unique_lock<std::mutex> lock(waitMutex);
if (cv.wait_for(lock, 10s, [] { return stopWaiting; })) {
if (abortTerminate) {
blog(LOG_INFO, "OBS shutdown was aborted");
} else {
closeOBSWindow();
}
} else {
closeOBSWindow();
}
});
thread.detach();
// Ask the user how to proceed
abortTerminate = !DisplayMessage(
obs_module_text(
"AdvSceneSwitcher.action.pluginState.terminateConfirm"),
true, false);
stopWaiting = true;
// This closes OBS immediately if shutdown was confirmed
cv.notify_all();
lock.unlock();
}
bool MacroActionPluginState::PerformAction()
{
switch (_action) {
@@ -150,14 +70,6 @@ bool MacroActionPluginState::PerformAction()
// There is no point in continuing
// The settings will be invalid
return false;
case PluginStateAction::TERMINATE: {
std::thread thread([]() {
obs_queue_task(OBS_TASK_UI, terminateOBS, nullptr,
false);
});
thread.detach();
break;
}
default:
break;
}
@@ -177,9 +89,6 @@ void MacroActionPluginState::LogAction() const
vblog(LOG_INFO, "importing settings from %s",
_settingsPath.c_str());
break;
case PluginStateAction::TERMINATE:
vblog(LOG_INFO, "sending terminate signal to OBS in 10s");
break;
default:
blog(LOG_WARNING, "ignored unknown pluginState action %d",
static_cast<int>(_action));
@@ -193,7 +102,7 @@ bool MacroActionPluginState::Save(obs_data_t *obj) const
obs_data_set_int(obj, "action", static_cast<int>(_action));
obs_data_set_int(obj, "value", _value);
obs_data_set_string(obj, "scene", GetWeakSourceName(_scene).c_str());
_settingsPath.Save(obj, "settingsPath");
obs_data_set_string(obj, "settingsPath", _settingsPath.c_str());
return true;
}
@@ -205,7 +114,7 @@ bool MacroActionPluginState::Load(obs_data_t *obj)
_value = obs_data_get_int(obj, "value");
const char *sceneName = obs_data_get_string(obj, "scene");
_scene = GetWeakSourceByName(sceneName);
_settingsPath.Load(obj, "settingsPath");
_settingsPath = obs_data_get_string(obj, "settingsPath");
return true;
}
@@ -238,7 +147,7 @@ MacroActionPluginStateEdit::MacroActionPluginStateEdit(
"AdvSceneSwitcher.action.pluginState.importWarning"));
populateActionSelection(_actions);
PopulateSceneSelection(_scenes);
populateSceneSelection(_scenes);
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionChanged(int)));
@@ -257,7 +166,7 @@ MacroActionPluginStateEdit::MacroActionPluginStateEdit(
{"{{settings}}", _settings},
{"{{settingsWarning}}", _settingsWarning},
};
PlaceWidgets(
placeWidgets(
obs_module_text("AdvSceneSwitcher.action.pluginState.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -276,7 +185,7 @@ void MacroActionPluginStateEdit::UpdateEntryData()
populateValueSelection(_values, _entryData->_action);
_values->setCurrentIndex(_entryData->_value);
_scenes->setCurrentText(GetWeakSourceName(_entryData->_scene).c_str());
_settings->SetPath(_entryData->_settingsPath);
_settings->SetPath(QString::fromStdString(_entryData->_settingsPath));
SetWidgetVisibility();
}
@@ -287,7 +196,7 @@ void MacroActionPluginStateEdit::ActionChanged(int value)
}
{
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_action = static_cast<PluginStateAction>(value);
SetWidgetVisibility();
}
@@ -302,7 +211,7 @@ void MacroActionPluginStateEdit::ValueChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_value = value;
SetWidgetVisibility();
}
@@ -313,7 +222,7 @@ void MacroActionPluginStateEdit::SceneChanged(const QString &text)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = GetWeakSourceByQString(text);
}
@@ -323,7 +232,7 @@ void MacroActionPluginStateEdit::PathChanged(const QString &text)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_settingsPath = text.toStdString();
}
@@ -342,8 +251,7 @@ void MacroActionPluginStateEdit::SetWidgetVisibility()
break;
case PluginStateAction::NO_MATCH_BEHAVIOUR:
_values->show();
if (static_cast<SwitcherData::NoMatch>(_entryData->_value) ==
SwitcherData::NoMatch::SWITCH) {
if ((NoMatch)_entryData->_value == SWITCH) {
_scenes->show();
}
break;
@@ -355,5 +263,3 @@ void MacroActionPluginStateEdit::SetWidgetVisibility()
break;
}
}
} // namespace advss

View File

@@ -5,13 +5,10 @@
#include <QDoubleSpinBox>
#include <QLabel>
namespace advss {
enum class PluginStateAction {
STOP,
NO_MATCH_BEHAVIOUR,
IMPORT_SETTINGS,
TERMINATE,
};
class MacroActionPluginState : public MacroAction {
@@ -29,7 +26,7 @@ public:
PluginStateAction _action = PluginStateAction::STOP;
int _value = 0;
StringVariable _settingsPath;
std::string _settingsPath;
OBSWeakSource _scene;
private:
@@ -72,5 +69,3 @@ private:
void SetWidgetVisibility();
bool _loading = true;
};
} // namespace advss

View File

@@ -1,8 +1,7 @@
#include "macro-action-profile.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
namespace advss {
const std::string MacroActionProfile::id = "profile";
bool MacroActionProfile::_registered = MacroActionFactory::Register(
@@ -45,7 +44,7 @@ MacroActionProfileEdit::MacroActionProfileEdit(
: QWidget(parent)
{
_profiles = new QComboBox();
PopulateProfileSelection(_profiles);
populateProfileSelection(_profiles);
QWidget::connect(_profiles, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(ProfileChanged(const QString &)));
@@ -53,7 +52,7 @@ MacroActionProfileEdit::MacroActionProfileEdit(
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{profiles}}", _profiles},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.profile.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.action.profile.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
@@ -77,10 +76,8 @@ void MacroActionProfileEdit::ProfileChanged(const QString &text)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_profile = text.toStdString();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
} // namespace advss

View File

@@ -3,8 +3,6 @@
#include <QComboBox>
namespace advss {
class MacroActionProfile : public MacroAction {
public:
MacroActionProfile(Macro *m) : MacroAction(m) {}
@@ -54,5 +52,3 @@ protected:
private:
bool _loading = true;
};
} // namespace advss

View File

@@ -1,11 +1,9 @@
#include "macro-action-projector.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
#include <QGuiApplication>
#include <QScreen>
namespace advss {
const std::string MacroActionProjector::id = "projector";
bool MacroActionProjector::_registered = MacroActionFactory::Register(
@@ -117,6 +115,46 @@ static inline void populateWindowTypes(QComboBox *list)
"AdvSceneSwitcher.action.projector.fullscreen"));
}
static QStringList getMonitorNames()
{
QStringList monitorNames;
QList<QScreen *> screens = QGuiApplication::screens();
for (int i = 0; i < screens.size(); i++) {
QScreen *screen = screens[i];
QRect screenGeometry = screen->geometry();
qreal ratio = screen->devicePixelRatio();
QString name = "";
#if defined(__APPLE__) || defined(_WIN32)
name = screen->name();
#else
name = screen->model().simplified();
if (name.length() > 1 && name.endsWith("-")) {
name.chop(1);
}
#endif
name = name.simplified();
if (name.length() == 0) {
name = QString("%1 %2")
.arg(obs_module_text(
"AdvSceneSwitcher.action.projector.display"))
.arg(QString::number(i + 1));
}
QString str =
QString("%1: %2x%3 @ %4,%5")
.arg(name,
QString::number(screenGeometry.width() *
ratio),
QString::number(screenGeometry.height() *
ratio),
QString::number(screenGeometry.x()),
QString::number(screenGeometry.y()));
monitorNames << str;
}
return monitorNames;
}
MacroActionProjectorEdit::MacroActionProjectorEdit(
QWidget *parent, std::shared_ptr<MacroActionProjector> entryData)
: QWidget(parent),
@@ -133,7 +171,7 @@ MacroActionProjectorEdit::MacroActionProjectorEdit(
auto sources = GetSourceNames();
sources.sort();
_sources->SetSourceNameList(sources);
_monitors->addItems(GetMonitorNames());
_monitors->addItems(getMonitorNames());
QWidget::connect(_windowTypes, SIGNAL(currentIndexChanged(int)), this,
SLOT(WindowTypeChanged(int)));
@@ -153,12 +191,12 @@ MacroActionProjectorEdit::MacroActionProjectorEdit(
{"{{monitors}}", _monitors},
};
PlaceWidgets(obs_module_text(
placeWidgets(obs_module_text(
"AdvSceneSwitcher.action.projector.entry.monitor"),
_monitorSelection, widgetPlaceholders);
QHBoxLayout *mainLayout = new QHBoxLayout;
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.projector.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.action.projector.entry"),
mainLayout, widgetPlaceholders);
mainLayout->insertLayout(mainLayout->count() - 1, _monitorSelection);
setLayout(mainLayout);
@@ -187,7 +225,7 @@ void MacroActionProjectorEdit::SceneChanged(const SceneSelection &s)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
}
@@ -197,7 +235,7 @@ void MacroActionProjectorEdit::SourceChanged(const SourceSelection &source)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_source = source;
}
@@ -207,17 +245,17 @@ void MacroActionProjectorEdit::MonitorChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_monitor = value;
}
void MacroActionProjectorEdit::WindowTypeChanged(int)
void MacroActionProjectorEdit::WindowTypeChanged(int value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_fullscreen =
_windowTypes->currentText() ==
obs_module_text("AdvSceneSwitcher.action.projector.fullscreen");
@@ -230,7 +268,7 @@ void MacroActionProjectorEdit::TypeChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_type = static_cast<MacroActionProjector::Type>(value);
SetWidgetVisibility();
}
@@ -245,10 +283,8 @@ void MacroActionProjectorEdit::SetWidgetVisibility()
MacroActionProjector::Type::SCENE);
_sources->setVisible(_entryData->_type ==
MacroActionProjector::Type::SOURCE);
SetLayoutVisible(_monitorSelection, _entryData->_fullscreen);
setLayoutVisible(_monitorSelection, _entryData->_fullscreen);
adjustSize();
updateGeometry();
}
} // namespace advss

View File

@@ -3,8 +3,6 @@
#include "scene-selection.hpp"
#include "source-selection.hpp"
namespace advss {
class MacroActionProjector : public MacroAction {
public:
MacroActionProjector(Macro *m) : MacroAction(m) {}
@@ -73,5 +71,3 @@ private:
void SetWidgetVisibility();
bool _loading = true;
};
} // namespace advss

View File

@@ -1,11 +1,9 @@
#include "macro-action-random.hpp"
#include "macro.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
#include <cstdlib>
namespace advss {
const std::string MacroActionRandom::id = "random";
bool MacroActionRandom::_registered = MacroActionFactory::Register(
@@ -13,30 +11,22 @@ bool MacroActionRandom::_registered = MacroActionFactory::Register(
{MacroActionRandom::Create, MacroActionRandomEdit::Create,
"AdvSceneSwitcher.action.random"});
static bool validNextMacro(const std::shared_ptr<Macro> &macro)
std::vector<MacroRef> getNextMacros(std::vector<MacroRef> &macros,
MacroRef &lastRandomMacro, bool allowRepeat)
{
return macro && !macro->Paused();
}
static std::vector<std::shared_ptr<Macro>>
getNextMacros(std::vector<MacroRef> &macros, MacroRef &lastRandomMacroRef,
bool allowRepeat)
{
std::vector<std::shared_ptr<Macro>> res;
std::vector<MacroRef> res;
if (macros.size() == 1) {
auto macro = macros[0].GetMacro();
if (validNextMacro(macro)) {
res.push_back(macro);
if (!macros[0].get() || macros[0]->Paused()) {
return res;
} else {
return macros;
}
return res;
}
auto lastRandomMacro = lastRandomMacroRef.GetMacro();
for (auto &m : macros) {
auto macro = m.GetMacro();
if (validNextMacro(macro) &&
(allowRepeat || (lastRandomMacro != macro))) {
res.push_back(macro);
if (m.get() && !m->Paused() &&
(allowRepeat || (lastRandomMacro.get() != m.get()))) {
res.push_back(m);
}
}
return res;
@@ -52,7 +42,7 @@ bool MacroActionRandom::PerformAction()
if (macros.size() == 0) {
return true;
}
if (macros.size() == 1) {
if (macros.size() == 1 && macros[0].get()) {
lastRandomMacro = macros[0];
return macros[0]->PerformActions();
}
@@ -102,7 +92,7 @@ MacroActionRandomEdit::MacroActionRandomEdit(
auto *entryLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.random.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.action.random.entry"),
entryLayout, widgetPlaceholders);
auto *mainLayout = new QVBoxLayout;
@@ -136,7 +126,8 @@ void MacroActionRandomEdit::MacroRemove(const QString &)
auto it = _entryData->_macros.begin();
while (it != _entryData->_macros.end()) {
if (!it->GetMacro()) {
it->UpdateRef();
if (it->get() == nullptr) {
it = _entryData->_macros.erase(it);
} else {
++it;
@@ -151,7 +142,7 @@ void MacroActionRandomEdit::Add(const std::string &name)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
MacroRef macro(name);
_entryData->_macros.push_back(macro);
_allowRepeat->setVisible(ShouldShowAllowRepeat());
@@ -164,7 +155,7 @@ void MacroActionRandomEdit::Remove(int idx)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_macros.erase(std::next(_entryData->_macros.begin(), idx));
_allowRepeat->setVisible(ShouldShowAllowRepeat());
adjustSize();
@@ -177,7 +168,7 @@ void MacroActionRandomEdit::Replace(int idx, const std::string &name)
}
MacroRef macro(name);
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_macros[idx] = macro;
adjustSize();
}
@@ -188,7 +179,7 @@ void MacroActionRandomEdit::AllowRepeatChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_allowRepeat = value;
}
@@ -197,13 +188,11 @@ bool MacroActionRandomEdit::ShouldShowAllowRepeat()
if (_entryData->_macros.size() <= 1) {
return false;
}
const auto macro = _entryData->_macros[0].GetMacro();
const auto macro = _entryData->_macros[0];
for (const auto &m : _entryData->_macros) {
if (macro != m.GetMacro()) {
if (macro.get() != m.get()) {
return true;
}
}
return false;
}
} // namespace advss

View File

@@ -6,8 +6,6 @@
#include <QListWidget>
#include <QCheckBox>
namespace advss {
class MacroActionRandom : public MultiMacroRefAction {
public:
MacroActionRandom(Macro *m) : MacroAction(m), MultiMacroRefAction(m) {}
@@ -62,5 +60,3 @@ private:
QCheckBox *_allowRepeat;
bool _loading = true;
};
} // namespace advss

View File

@@ -1,10 +1,7 @@
#include "macro-action-recording.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
#include <util/config-file.h>
namespace advss {
const std::string MacroActionRecord::id = "recording";
bool MacroActionRecord::_registered = MacroActionFactory::Register(
@@ -12,80 +9,45 @@ bool MacroActionRecord::_registered = MacroActionFactory::Register(
{MacroActionRecord::Create, MacroActionRecordEdit::Create,
"AdvSceneSwitcher.action.recording"});
const static std::map<MacroActionRecord::Action, std::string> actionTypes = {
{MacroActionRecord::Action::STOP,
"AdvSceneSwitcher.action.recording.type.stop"},
{MacroActionRecord::Action::START,
"AdvSceneSwitcher.action.recording.type.start"},
{MacroActionRecord::Action::PAUSE,
"AdvSceneSwitcher.action.recording.type.pause"},
{MacroActionRecord::Action::UNPAUSE,
const static std::map<RecordAction, std::string> actionTypes = {
{RecordAction::STOP, "AdvSceneSwitcher.action.recording.type.stop"},
{RecordAction::START, "AdvSceneSwitcher.action.recording.type.start"},
{RecordAction::PAUSE, "AdvSceneSwitcher.action.recording.type.pause"},
{RecordAction::UNPAUSE,
"AdvSceneSwitcher.action.recording.type.unpause"},
{MacroActionRecord::Action::SPLIT,
"AdvSceneSwitcher.action.recording.type.split"},
{MacroActionRecord::Action::FOLDER,
"AdvSceneSwitcher.action.recording.type.changeOutputFolder"},
{MacroActionRecord::Action::FILE_FORMAT,
"AdvSceneSwitcher.action.recording.type.changeOutputFileFormat"},
{RecordAction::SPLIT, "AdvSceneSwitcher.action.recording.type.split"},
};
bool MacroActionRecord::PerformAction()
{
switch (_action) {
case Action::STOP:
case RecordAction::STOP:
if (obs_frontend_recording_active()) {
obs_frontend_recording_stop();
}
break;
case Action::START:
case RecordAction::START:
if (!obs_frontend_recording_active()) {
obs_frontend_recording_start();
}
break;
case Action::PAUSE:
case RecordAction::PAUSE:
if (obs_frontend_recording_active() &&
!obs_frontend_recording_paused()) {
obs_frontend_recording_pause(true);
}
break;
case Action::UNPAUSE:
case RecordAction::UNPAUSE:
if (obs_frontend_recording_active() &&
obs_frontend_recording_paused()) {
obs_frontend_recording_pause(false);
}
break;
#if LIBOBS_API_VER >= MAKE_SEMANTIC_VERSION(28, 0, 0)
case Action::SPLIT:
case RecordAction::SPLIT:
obs_frontend_recording_split_file();
break;
#endif
case Action::FOLDER: {
std::string folder = _folder; // Trigger variable resolve
auto conf = obs_frontend_get_profile_config();
config_set_string(conf, "SimpleOutput", "FilePath",
folder.c_str());
config_set_string(conf, "AdvOut", "FFFilePath", folder.c_str());
config_set_string(conf, "AdvOut", "RecFilePath",
folder.c_str());
if (config_save(conf) != CONFIG_SUCCESS) {
blog(LOG_WARNING,
"failed to set recoding output folder");
}
break;
}
case Action::FILE_FORMAT: {
std::string format = _fileFormat; // Trigger variable resolve
auto conf = obs_frontend_get_profile_config();
config_set_string(conf, "Output", "FilenameFormatting",
format.c_str());
if (config_save(conf) != CONFIG_SUCCESS) {
blog(LOG_WARNING,
"failed to set recoding file format string");
}
break;
}
default:
break;
}
@@ -107,17 +69,13 @@ bool MacroActionRecord::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
obs_data_set_int(obj, "action", static_cast<int>(_action));
_folder.Save(obj, "folder");
_fileFormat.Save(obj, "format");
return true;
}
bool MacroActionRecord::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
_folder.Load(obj, "folder");
_fileFormat.Load(obj, "format");
_action = static_cast<RecordAction>(obs_data_get_int(obj, "action"));
return true;
}
@@ -135,27 +93,21 @@ MacroActionRecordEdit::MacroActionRecordEdit(
_pauseHint(new QLabel(obs_module_text(
"AdvSceneSwitcher.action.recording.pause.hint"))),
_splitHint(new QLabel(obs_module_text(
"AdvSceneSwitcher.action.recording.split.hint"))),
_recordFolder(new FileSelection(FileSelection::Type::FOLDER, this)),
_recordFileFormat(new VariableLineEdit(this))
"AdvSceneSwitcher.action.recording.split.hint")))
{
populateActionSelection(_actions);
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionChanged(int)));
QWidget::connect(_recordFolder, SIGNAL(PathChanged(const QString &)),
this, SLOT(FolderChanged(const QString &)));
QWidget::connect(_recordFileFormat, SIGNAL(editingFinished()), this,
SLOT(FormatStringChanged()));
auto mainLayout = new QHBoxLayout;
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.recording.entry"),
mainLayout,
{{"{{actions}}", _actions},
{"{{pauseHint}}", _pauseHint},
{"{{splitHint}}", _splitHint},
{"{{recordFolder}}", _recordFolder},
{"{{recordFileFormat}}", _recordFileFormat}});
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{actions}}", _actions},
{"{{pauseHint}}", _pauseHint},
{"{{splitHint}}", _splitHint},
};
placeWidgets(obs_module_text("AdvSceneSwitcher.action.recording.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
_entryData = entryData;
@@ -169,46 +121,18 @@ void MacroActionRecordEdit::UpdateEntryData()
return;
}
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
_recordFolder->SetPath(_entryData->_folder);
_recordFileFormat->setText(_entryData->_fileFormat);
SetWidgetVisibility();
SetLabelVisibility();
}
static bool isPauseAction(MacroActionRecord::Action a)
bool isPauseAction(RecordAction a)
{
return a == MacroActionRecord::Action::PAUSE ||
a == MacroActionRecord::Action::UNPAUSE;
return a == RecordAction::PAUSE || a == RecordAction::UNPAUSE;
}
void MacroActionRecordEdit::FolderChanged(const QString &folder)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_folder = folder.toStdString();
}
void MacroActionRecordEdit::FormatStringChanged()
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_fileFormat = _recordFileFormat->text().toStdString();
}
void MacroActionRecordEdit::SetWidgetVisibility()
void MacroActionRecordEdit::SetLabelVisibility()
{
_pauseHint->setVisible(isPauseAction(_entryData->_action));
_splitHint->setVisible(_entryData->_action ==
MacroActionRecord::Action::SPLIT);
_recordFolder->setVisible(_entryData->_action ==
MacroActionRecord::Action::FOLDER);
_recordFileFormat->setVisible(_entryData->_action ==
MacroActionRecord::Action::FILE_FORMAT);
_splitHint->setVisible(_entryData->_action == RecordAction::SPLIT);
}
void MacroActionRecordEdit::ActionChanged(int value)
@@ -217,9 +141,7 @@ void MacroActionRecordEdit::ActionChanged(int value)
return;
}
auto lock = LockContext();
_entryData->_action = static_cast<MacroActionRecord::Action>(value);
SetWidgetVisibility();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_action = static_cast<RecordAction>(value);
SetLabelVisibility();
}
} // namespace advss

View File

@@ -1,13 +1,16 @@
#pragma once
#include "macro-action-edit.hpp"
#include "file-selection.hpp"
#include "variable-line-edit.hpp"
#include <QDir>
#include <QComboBox>
#include <QHBoxLayout>
namespace advss {
enum class RecordAction {
STOP,
START,
PAUSE,
UNPAUSE,
SPLIT,
};
class MacroActionRecord : public MacroAction {
public:
@@ -22,19 +25,7 @@ public:
return std::make_shared<MacroActionRecord>(m);
}
enum class Action {
STOP,
START,
PAUSE,
UNPAUSE,
SPLIT,
FOLDER,
FILE_FORMAT,
};
Action _action = Action::STOP;
StringVariable _folder = QDir::homePath().toStdString() + "/Videos";
StringVariable _fileFormat = "%CCYY-%MM-%DD %hh-%mm-%ss";
RecordAction _action = RecordAction::STOP;
private:
static bool _registered;
@@ -59,22 +50,16 @@ public:
private slots:
void ActionChanged(int value);
void FolderChanged(const QString &);
void FormatStringChanged();
protected:
QComboBox *_actions;
QLabel *_pauseHint;
QLabel *_splitHint;
FileSelection *_recordFolder;
VariableLineEdit *_recordFileFormat;
std::shared_ptr<MacroActionRecord> _entryData;
private:
void SetWidgetVisibility();
void SetLabelVisibility();
QHBoxLayout *_mainLayout;
bool _loading = true;
};
} // namespace advss

View File

@@ -1,8 +1,7 @@
#include "macro-action-replay-buffer.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
namespace advss {
const std::string MacroActionReplayBuffer::id = "replay_buffer";
bool MacroActionReplayBuffer::_registered = MacroActionFactory::Register(
@@ -90,7 +89,7 @@ MacroActionReplayBufferEdit::MacroActionReplayBufferEdit(
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{actions}}", _actions},
};
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.replay.entry"),
placeWidgets(obs_module_text("AdvSceneSwitcher.action.replay.entry"),
layout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(layout);
@@ -118,11 +117,9 @@ void MacroActionReplayBufferEdit::ActionChanged(int value)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_action = static_cast<ReplayBufferAction>(value);
_saveWarning->setVisible(_entryData->_action ==
ReplayBufferAction::SAVE);
adjustSize();
}
} // namespace advss

View File

@@ -4,8 +4,6 @@
#include <QHBoxLayout>
namespace advss {
enum class ReplayBufferAction {
STOP,
START,
@@ -60,5 +58,3 @@ protected:
private:
bool _loading = true;
};
} // namespace advss

View File

@@ -1,11 +1,12 @@
#include "macro-action-run.hpp"
#include "advanced-scene-switcher.hpp"
#include "name-dialog.hpp"
#include "utility.hpp"
#include <QProcess>
#include <QFileDialog>
#include <QDesktopServices>
namespace advss {
const std::string MacroActionRun::id = "run";
bool MacroActionRun::_registered = MacroActionFactory::Register(
@@ -14,53 +15,137 @@ bool MacroActionRun::_registered = MacroActionFactory::Register(
bool MacroActionRun::PerformAction()
{
bool procStarted = QProcess::startDetached(
QString::fromStdString(_procConfig.Path()), _procConfig.Args(),
QString::fromStdString(_procConfig.WorkingDir()));
if (!procStarted && _procConfig.Args().empty()) {
if (!QProcess::startDetached(
QString::fromStdString(_path), _args,
QString::fromStdString(_workingDirectory)) &&
_args.empty()) {
vblog(LOG_INFO, "run \"%s\" using QDesktopServices",
_procConfig.Path().c_str());
QDesktopServices::openUrl(QUrl::fromLocalFile(
QString::fromStdString(_procConfig.Path())));
_path.c_str());
QDesktopServices::openUrl(
QUrl::fromLocalFile(QString::fromStdString(_path)));
}
return true;
}
void MacroActionRun::LogAction() const
{
vblog(LOG_INFO, "run \"%s\"", _procConfig.UnresolvedPath().c_str());
vblog(LOG_INFO, "run \"%s\"", _path.c_str());
}
bool MacroActionRun::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
_procConfig.Save(obj);
obs_data_set_string(obj, "path", _path.c_str());
obs_data_set_string(obj, "workingDirectory", _workingDirectory.c_str());
obs_data_array_t *args = obs_data_array_create();
for (auto &arg : _args) {
obs_data_t *array_obj = obs_data_create();
obs_data_set_string(array_obj, "arg",
arg.toStdString().c_str());
obs_data_array_push_back(args, array_obj);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "args", args);
obs_data_array_release(args);
return true;
}
bool MacroActionRun::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_procConfig.Load(obj);
_path = obs_data_get_string(obj, "path");
_workingDirectory = obs_data_get_string(obj, "workingDirectory");
obs_data_array_t *args = obs_data_get_array(obj, "args");
size_t count = obs_data_array_count(args);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(args, i);
_args << QString::fromStdString(
obs_data_get_string(array_obj, "arg"));
obs_data_release(array_obj);
}
obs_data_array_release(args);
return true;
}
std::string MacroActionRun::GetShortDesc() const
{
return _procConfig.UnresolvedPath();
return _path;
}
MacroActionRunEdit::MacroActionRunEdit(
QWidget *parent, std::shared_ptr<MacroActionRun> entryData)
: QWidget(parent), _procConfig(new ProcessConfigEdit(this))
: QWidget(parent),
_filePath(new FileSelection()),
_argList(new QListWidget()),
_addArg(new QPushButton()),
_removeArg(new QPushButton()),
_argUp(new QPushButton()),
_argDown(new QPushButton()),
_workingDirectory(new FileSelection(FileSelection::Type::FOLDER))
{
QWidget::connect(_procConfig,
SIGNAL(ConfigChanged(const ProcessConfig &)), this,
SLOT(ProcessConfigChanged(const ProcessConfig &)));
_addArg->setMaximumWidth(22);
_addArg->setProperty("themeID",
QVariant(QString::fromUtf8("addIconSmall")));
_addArg->setFlat(true);
_removeArg->setMaximumWidth(22);
_removeArg->setProperty("themeID",
QVariant(QString::fromUtf8("removeIconSmall")));
_removeArg->setFlat(true);
_argUp->setMaximumWidth(22);
_argUp->setProperty("themeID",
QVariant(QString::fromUtf8("upArrowIconSmall")));
_argUp->setFlat(true);
_argDown->setMaximumWidth(22);
_argDown->setProperty(
"themeID", QVariant(QString::fromUtf8("downArrowIconSmall")));
_argDown->setFlat(true);
auto *layout = new QVBoxLayout;
layout->addWidget(_procConfig);
setLayout(layout);
QWidget::connect(_filePath, SIGNAL(PathChanged(const QString &)), this,
SLOT(PathChanged(const QString &)));
QWidget::connect(_addArg, SIGNAL(clicked()), this, SLOT(AddArg()));
QWidget::connect(_removeArg, SIGNAL(clicked()), this,
SLOT(RemoveArg()));
QWidget::connect(_argUp, SIGNAL(clicked()), this, SLOT(ArgUp()));
QWidget::connect(_argDown, SIGNAL(clicked()), this, SLOT(ArgDown()));
QWidget::connect(_argList, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
this, SLOT(ArgItemClicked(QListWidgetItem *)));
QWidget::connect(_workingDirectory,
SIGNAL(PathChanged(const QString &)), this,
SLOT(WorkingDirectoryChanged(const QString &)));
auto *entryLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{filePath}}", _filePath},
{"{{workingDirectory}}", _workingDirectory},
};
placeWidgets(obs_module_text("AdvSceneSwitcher.action.run.entry"),
entryLayout, widgetPlaceholders, false);
auto argButtonLayout = new QHBoxLayout;
argButtonLayout->addWidget(_addArg);
argButtonLayout->addWidget(_removeArg);
QFrame *line = new QFrame();
line->setFrameShape(QFrame::VLine);
line->setFrameShadow(QFrame::Sunken);
argButtonLayout->addWidget(line);
argButtonLayout->addWidget(_argUp);
argButtonLayout->addWidget(_argDown);
argButtonLayout->addStretch();
auto workingDirectoryLayout = new QHBoxLayout;
placeWidgets(
obs_module_text(
"AdvSceneSwitcher.action.run.entry.workingDirectory"),
workingDirectoryLayout, widgetPlaceholders, false);
auto *mainLayout = new QVBoxLayout;
mainLayout->addLayout(entryLayout);
mainLayout->addWidget(new QLabel(
obs_module_text("AdvSceneSwitcher.action.run.arguments")));
mainLayout->addWidget(_argList);
mainLayout->addLayout(argButtonLayout);
mainLayout->addLayout(workingDirectoryLayout);
setLayout(mainLayout);
_entryData = entryData;
UpdateEntryData();
@@ -72,21 +157,142 @@ void MacroActionRunEdit::UpdateEntryData()
if (!_entryData) {
return;
}
_procConfig->SetProcessConfig(_entryData->_procConfig);
_filePath->SetPath(QString::fromStdString(_entryData->_path));
for (auto &arg : _entryData->_args) {
QListWidgetItem *item = new QListWidgetItem(arg, _argList);
item->setData(Qt::UserRole, arg);
}
_workingDirectory->SetPath(
QString::fromStdString(_entryData->_workingDirectory));
SetArgListSize();
}
void MacroActionRunEdit::ProcessConfigChanged(const ProcessConfig &conf)
void MacroActionRunEdit::PathChanged(const QString &text)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_procConfig = conf;
adjustSize();
updateGeometry();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_path = text.toUtf8().constData();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
} // namespace advss
void MacroActionRunEdit::AddArg()
{
if (_loading || !_entryData) {
return;
}
std::string name;
bool accepted = AdvSSNameDialog::AskForName(
this,
obs_module_text("AdvSceneSwitcher.action.run.addArgument"),
obs_module_text(
"AdvSceneSwitcher.action.run.addArgumentDescription"),
name, "", 170, false);
if (!accepted || name.empty()) {
return;
}
auto arg = QString::fromStdString(name);
QVariant v = QVariant::fromValue(arg);
QListWidgetItem *item = new QListWidgetItem(arg, _argList);
item->setData(Qt::UserRole, arg);
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_args << arg;
SetArgListSize();
}
void MacroActionRunEdit::RemoveArg()
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
int idx = _argList->currentRow();
if (idx == -1) {
return;
}
_entryData->_args.removeAt(idx);
QListWidgetItem *item = _argList->currentItem();
if (!item) {
return;
}
delete item;
SetArgListSize();
}
void MacroActionRunEdit::ArgUp()
{
if (_loading || !_entryData) {
return;
}
int idx = _argList->currentRow();
if (idx != -1 && idx != 0) {
_argList->insertItem(idx - 1, _argList->takeItem(idx));
_argList->setCurrentRow(idx - 1);
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_args.move(idx, idx - 1);
}
}
void MacroActionRunEdit::ArgDown()
{
int idx = _argList->currentRow();
if (idx != -1 && idx != _argList->count() - 1) {
_argList->insertItem(idx + 1, _argList->takeItem(idx));
_argList->setCurrentRow(idx + 1);
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_args.move(idx, idx + 1);
}
}
void MacroActionRunEdit::ArgItemClicked(QListWidgetItem *item)
{
if (_loading || !_entryData) {
return;
}
std::string name;
bool accepted = AdvSSNameDialog::AskForName(
this,
obs_module_text("AdvSceneSwitcher.action.run.addArgument"),
obs_module_text(
"AdvSceneSwitcher.action.run.addArgumentDescription"),
name, item->text(), 170, false);
if (!accepted || name.empty()) {
return;
}
auto arg = QString::fromStdString(name);
QVariant v = QVariant::fromValue(arg);
item->setText(arg);
item->setData(Qt::UserRole, arg);
int idx = _argList->currentRow();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_args[idx] = arg;
}
void MacroActionRunEdit::WorkingDirectoryChanged(const QString &path)
{
if (_loading || !_entryData) {
return;
}
_entryData->_workingDirectory = path.toStdString();
}
void MacroActionRunEdit::SetArgListSize()
{
setHeightToContentHeight(_argList);
adjustSize();
}

View File

@@ -1,8 +1,11 @@
#pragma once
#include "macro-action-edit.hpp"
#include "process-config.hpp"
#include "file-selection.hpp"
namespace advss {
#include <QLineEdit>
#include <QPushButton>
#include <QListWidget>
#include <QStringList>
class MacroActionRun : public MacroAction {
public:
@@ -18,7 +21,9 @@ public:
return std::make_shared<MacroActionRun>(m);
}
ProcessConfig _procConfig;
std::string _path = obs_module_text("AdvSceneSwitcher.enterPath");
std::string _workingDirectory = "";
QStringList _args;
private:
static bool _registered;
@@ -41,7 +46,13 @@ public:
}
private slots:
void ProcessConfigChanged(const ProcessConfig &);
void PathChanged(const QString &text);
void AddArg();
void RemoveArg();
void ArgUp();
void ArgDown();
void ArgItemClicked(QListWidgetItem *);
void WorkingDirectoryChanged(const QString &text);
signals:
void HeaderInfoChanged(const QString &);
@@ -49,8 +60,14 @@ protected:
std::shared_ptr<MacroActionRun> _entryData;
private:
ProcessConfigEdit *_procConfig;
void SetArgListSize();
FileSelection *_filePath;
QListWidget *_argList;
QPushButton *_addArg;
QPushButton *_removeArg;
QPushButton *_argUp;
QPushButton *_argDown;
FileSelection *_workingDirectory;
bool _loading = true;
};
} // namespace advss

View File

@@ -1,9 +1,7 @@
#include "macro-action-scene-collection.hpp"
#include "switcher-data.hpp"
#include "advanced-scene-switcher.hpp"
#include "utility.hpp"
namespace advss {
const std::string MacroActionSceneCollection::id = "scene_collection";
bool MacroActionSceneCollection::_registered = MacroActionFactory::Register(
@@ -62,7 +60,7 @@ void populateSceneCollectionSelection(QComboBox *box)
}
bfree(sceneCollections);
box->model()->sort(0);
AddSelectionEntry(
addSelectionEntry(
box, obs_module_text("AdvSceneSwitcher.selectSceneCollection"),
false);
box->setCurrentIndex(0);
@@ -82,7 +80,7 @@ MacroActionSceneCollectionEdit::MacroActionSceneCollectionEdit(
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{sceneCollections}}", _sceneCollections},
};
PlaceWidgets(obs_module_text(
placeWidgets(obs_module_text(
"AdvSceneSwitcher.action.sceneCollection.entry"),
entryLayout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
@@ -112,10 +110,8 @@ void MacroActionSceneCollectionEdit::SceneCollectionChanged(const QString &text)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_sceneCollection = text.toStdString();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
} // namespace advss

View File

@@ -3,8 +3,6 @@
#include <QComboBox>
namespace advss {
class MacroActionSceneCollection : public MacroAction {
public:
MacroActionSceneCollection(Macro *m) : MacroAction(m) {}
@@ -55,5 +53,3 @@ protected:
private:
bool _loading = true;
};
} // namespace advss

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