Compare commits

..

1 Commits
1.23.0 ... osx

Author SHA1 Message Date
WarmUpTill
b74e9d2e2a Enable executing AppleScripts on MacOS 2023-03-04 18:14:16 +01:00
340 changed files with 6220 additions and 81397 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

@@ -104,7 +104,7 @@ function Build {
'-G', $CmakeGenerator
"-DCMAKE_SYSTEM_VERSION=${script:PlatformSDK}"
"-DCMAKE_GENERATOR_PLATFORM=$(if (${script:Target} -eq "x86") { "Win32" } else { "x64" })"
"-DCMAKE_BUILD_TYPE=${Configuration}"
"-DCMAKE_BUILD_TYPE=Release"
"-DCMAKE_PREFIX_PATH:PATH=${DepInstallPath}"
"-DCMAKE_INSTALL_PREFIX:PATH=${DepInstallPath}"
"-DSW_BUILD=OFF"
@@ -115,7 +115,7 @@ function Build {
Invoke-External cmake -S ${LeptonicaPath} -B ${LeptonicaBuildPath} @LeptonicaCmakeArgs
$LeptonicaCmakeArgs = @(
'--config', "${Configuration}"
'--config', "Release"
)
if ( $VerbosePreference -eq 'Continue' ) {
@@ -140,7 +140,7 @@ function Build {
'-G', $CmakeGenerator
"-DCMAKE_SYSTEM_VERSION=${script:PlatformSDK}"
"-DCMAKE_GENERATOR_PLATFORM=$(if (${script:Target} -eq "x86") { "Win32" } else { "x64" })"
"-DCMAKE_BUILD_TYPE=${Configuration}"
"-DCMAKE_BUILD_TYPE=Release"
"-DCMAKE_PREFIX_PATH:PATH=${DepInstallPath}"
"-DCMAKE_INSTALL_PREFIX:PATH=${DepInstallPath}"
"-DSW_BUILD=OFF"
@@ -154,7 +154,7 @@ function Build {
Invoke-External cmake -S ${TesseractPath} -B ${TesseractBuildPath} @TesseractCmakeArgs
$TesseractCmakeArgs = @(
'--config', "${Configuration}"
'--config', "Release"
)
if ( $VerbosePreference -eq 'Continue' ) {

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
@@ -125,8 +125,6 @@ target_sources(
src/macro-core/macro-action-run.hpp
src/macro-core/macro-action-scene-collection.cpp
src/macro-core/macro-action-scene-collection.hpp
src/macro-core/macro-action-scene-lock.cpp
src/macro-core/macro-action-scene-lock.hpp
src/macro-core/macro-action-scene-order.cpp
src/macro-core/macro-action-scene-order.hpp
src/macro-core/macro-action-scene-switch.cpp
@@ -167,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
@@ -195,16 +191,12 @@ 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
src/macro-core/macro-condition-scene-transform.hpp
src/macro-core/macro-condition-scene-visibility.cpp
src/macro-core/macro-condition-scene-visibility.hpp
src/macro-core/macro-condition-slideshow.cpp
src/macro-core/macro-condition-slideshow.hpp
src/macro-core/macro-condition-scene.cpp
src/macro-core/macro-condition-scene.hpp
src/macro-core/macro-condition-source.cpp
@@ -227,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
@@ -256,36 +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-combo-box.cpp
src/utils/filter-combo-box.hpp
src/utils/filter-selection.cpp
src/utils/filter-selection.hpp
src/utils/macro-export-import-dialog.cpp
src/utils/macro-export-import-dialog.hpp
src/utils/macro-list.cpp
src/utils/macro-list.hpp
src/utils/macro-segment-selection.cpp
src/utils/macro-segment-selection.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/non-modal-dialog.cpp
src/utils/non-modal-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
@@ -294,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
@@ -304,28 +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/switch-button.cpp
src/utils/switch-button.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
@@ -372,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 ---
@@ -384,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_)
@@ -502,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}}{{stringValue}}{{showPassword}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.run="Ausführen"
AdvSceneSwitcher.action.run.arguments="Argumente:"
AdvSceneSwitcher.action.run.addArgument="Argument hinzufügen"
@@ -451,7 +451,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.hide="Verstecken"
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Umschalten"
AdvSceneSwitcher.action.sceneVisibility.type.source="Quelle"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Beliebig"
AdvSceneSwitcher.action.sceneVisibility.entry="Auf{{scenes}}{{actions}}{{sources}}"
AdvSceneSwitcher.action.sceneVisibility.entry="Auf{{scenes}}{{actions}}{{sourceTypes}}{{sources}}{{sourceGroups}}"
AdvSceneSwitcher.action.filter="Filter"
AdvSceneSwitcher.action.filter.type.enable="Aktivieren"
AdvSceneSwitcher.action.filter.type.disable="Deaktivieren"
@@ -466,7 +466,7 @@ AdvSceneSwitcher.action.source.type.refreshSettings="Aktualisieren der Quellenei
AdvSceneSwitcher.action.source.type.pressSettingsButton="Drücken der Einstellungstaste"
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="Kann verwendet werden, um Browser-, Medien- usw. Quellen zu aktualisieren"
AdvSceneSwitcher.action.source.noSettingsButtons="Keine Buttons gefunden!"
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}"
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}"
AdvSceneSwitcher.action.source.warning="Warnung: Das globale Aktivieren und Deaktivieren von Quellen kann nicht über die OBS-Benutzeroberfläche gesteuert werden"
AdvSceneSwitcher.action.source.getSettings="Aktuelle Einstellungen abfragen"
AdvSceneSwitcher.action.media="Medien"
@@ -484,7 +484,7 @@ AdvSceneSwitcher.action.macro.type.unpause="Nicht mehr pausieren"
AdvSceneSwitcher.action.macro.type.resetCounter="Zähler zurücksetzen"
AdvSceneSwitcher.action.macro.type.run="Aktionen ausführen"
AdvSceneSwitcher.action.macro.type.stop="Aktionen stoppen"
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
AdvSceneSwitcher.action.pluginState="Plugin-Status"
AdvSceneSwitcher.action.pluginState.type.stop="Erweiterten Automatischen Szenenwechsler stoppen"
AdvSceneSwitcher.action.pluginState.type.noMatch="Ändern des Nichtübereinstimmungsverhaltens:"
@@ -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"
@@ -516,7 +516,7 @@ AdvSceneSwitcher.action.sceneOrder.type.movePosition="An Position verschieben"
AdvSceneSwitcher.action.sceneOrder.entry="Auf{{scenes}}{{actions}}{{sources}}{{position}}"
AdvSceneSwitcher.action.sceneTransform="Szenenelement transformieren"
AdvSceneSwitcher.action.sceneTransform.getTransform="Transformation erhalten"
AdvSceneSwitcher.action.sceneTransform.entry="Auf{{scenes}}{{action}}{{rotation}}{{sources}}"
AdvSceneSwitcher.action.sceneTransform.entry="Auf{{scenes}}transformieren{{sources}}"
AdvSceneSwitcher.action.file="Datei"
AdvSceneSwitcher.action.file.type.write="Schreiben"
AdvSceneSwitcher.action.file.type.append="Anhängen"
@@ -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
@@ -646,7 +647,7 @@ AdvSceneSwitcher.mediaTab.states.none="Keine Auswahl"
AdvSceneSwitcher.mediaTab.states.playing="Abspielen"
AdvSceneSwitcher.mediaTab.states.opening="Öffnen"
AdvSceneSwitcher.mediaTab.states.buffering="Buffern"
AdvSceneSwitcher.mediaTab.states.paused="Pausiert"
AdvSceneSwitcher.mediaTab.states.Paused="Pausiert"
AdvSceneSwitcher.mediaTab.states.stopped="Gestoppt"
AdvSceneSwitcher.mediaTab.states.ended="Beendet"
AdvSceneSwitcher.mediaTab.states.error="Fehler"

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,47 +83,23 @@ 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"
AdvSceneSwitcher.macroTab.ungroup="Ungroup Selected Groups"
AdvSceneSwitcher.macroTab.rename="Rename"
AdvSceneSwitcher.macroTab.remove="Remove"
AdvSceneSwitcher.macroTab.export="Export"
AdvSceneSwitcher.macroTab.export.info="Paste the string below into the import dialog to import the selected macros:"
AdvSceneSwitcher.macroTab.import="Import"
AdvSceneSwitcher.macroTab.import.info="Paste the export string into the below text box to import macros:"
AdvSceneSwitcher.macroTab.import.invalid="Invalid import data provided!"
AdvSceneSwitcher.macroTab.import.nameConflict="Cannot continue importing macro \"%1\" as a macro with the same name already exists!\nDo you want to continue with the import of \"%2\" and choose a new name? (Will be skipped otherwise)"
AdvSceneSwitcher.macroTab.expandAll="Expand all"
AdvSceneSwitcher.macroTab.collapseAll="Collapse all"
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.currentDockAddStatusLabel="Add status label"
AdvSceneSwitcher.macroTab.currentDockButtonText.run="Run button text:"
AdvSceneSwitcher.macroTab.currentDockButtonText.pause="Pause button text:"
AdvSceneSwitcher.macroTab.currentDockButtonText.unpause="Unpause button text:"
AdvSceneSwitcher.macroTab.currentDockStatusText.true="Conditions true text:"
AdvSceneSwitcher.macroTab.currentDockStatusText.false="Conditions false text:"
AdvSceneSwitcher.macroTab.currentDockHighlightIfExecuted="Highlight dock if macro actions were recently executed"
AdvSceneSwitcher.macroDock.pause="Pause"
AdvSceneSwitcher.macroDock.unpause="Unpause"
AdvSceneSwitcher.macroDock.run="Run"
AdvSceneSwitcher.macroDock.statusLabel.true="Conditions are true."
AdvSceneSwitcher.macroDock.statusLabel.false="Conditions are false."
; Macro List
AdvSceneSwitcher.macroList.deleted="deleted"
@@ -176,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"
@@ -210,7 +179,6 @@ AdvSceneSwitcher.condition.video.condition.pattern="matches pattern"
AdvSceneSwitcher.condition.video.condition.object="contains object"
AdvSceneSwitcher.condition.video.condition.brightness="brightness"
AdvSceneSwitcher.condition.video.condition.ocr="contains text"
AdvSceneSwitcher.condition.video.condition.color="matches color"
AdvSceneSwitcher.condition.video.askFileAction="Do you want to use an existing file or create a screenshot of the currently selected source?"
AdvSceneSwitcher.condition.video.askFileAction.file="Use existing file"
AdvSceneSwitcher.condition.video.askFileAction.screenshot="Create screenshot"
@@ -238,7 +206,6 @@ AdvSceneSwitcher.condition.video.screenshotFail="Failed to get screenshot of sou
AdvSceneSwitcher.condition.video.screenshotEmpty="Screenshot is empty - Is the source visible?"
AdvSceneSwitcher.condition.video.patternMatchFail="Pattern was not found!"
AdvSceneSwitcher.condition.video.patternMatchSuccess="Pattern is highlighted in red"
AdvSceneSwitcher.condition.video.patternMatchSuccessFullImage="Full image matches the pattern"
AdvSceneSwitcher.condition.video.objectMatchFail="Object was not found!"
AdvSceneSwitcher.condition.video.objectMatchSuccess="Object is highlighted in red"
AdvSceneSwitcher.condition.video.ocrMatchSuccess="Detected text:\n\n%1"
@@ -253,11 +220,6 @@ AdvSceneSwitcher.condition.video.ocrMode.circleWord="Single word in a circle"
AdvSceneSwitcher.condition.video.ocrMode.singleChar="Single character"
AdvSceneSwitcher.condition.video.ocrMode.sparseText="Find text in no particular order"
AdvSceneSwitcher.condition.video.ocrMode.sparseTextOSD="Find text in no particular order (OSD)"
AdvSceneSwitcher.condition.video.ocrLanguageNotFound="<html><head/><body><p>Language model for \"%1\" was not found in:<br>\"%2\"<br><br>You can find additional language models <a href=\"https://github.com/tesseract-ocr/tessdata\"><span style=\" text-decoration: underline; color:#268bd2;\">here</span></a>."
AdvSceneSwitcher.condition.video.colorMatchThreshold="Match threshold:"
AdvSceneSwitcher.condition.video.colorMatchThresholdDescription="How much of the image has to match the given color?\nA value of 1 requires every pixel of the input image to match the given color."
AdvSceneSwitcher.condition.video.colorDeviationThreshold="Color deviation:"
AdvSceneSwitcher.condition.video.colorDeviationThresholdDescription="How similar can the clolor be to the provided input color for it to still count as a match?\nA value of 0 requires a perfect color match, while a higher value includes similar colors also."
AdvSceneSwitcher.condition.video.type.main="OBS's main output"
AdvSceneSwitcher.condition.video.type.source="Source"
AdvSceneSwitcher.condition.video.type.scene="Scene"
@@ -269,8 +231,6 @@ AdvSceneSwitcher.condition.video.entry.checkAreaEnable="Perform check only in ar
AdvSceneSwitcher.condition.video.entry.checkArea="{{checkAreaEnable}}{{checkArea}}{{selectArea}}"
AdvSceneSwitcher.condition.video.entry.orcColorPick="Check for text color:{{textColor}}{{selectColor}}"
AdvSceneSwitcher.condition.video.entry.orcTextType="Check for text type:{{textType}}"
AdvSceneSwitcher.condition.video.entry.orcLanguage="Check for language:{{languageCode}}"
AdvSceneSwitcher.condition.video.entry.color="Check for color:{{color}}{{selectColor}}"
AdvSceneSwitcher.condition.video.minSize="Minimum size:"
AdvSceneSwitcher.condition.video.maxSize="Maximum size:"
AdvSceneSwitcher.condition.video.selectArea="Select area"
@@ -282,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"
@@ -299,7 +258,6 @@ AdvSceneSwitcher.condition.pluginState.state.start="Plugin started"
AdvSceneSwitcher.condition.pluginState.state.restart="Plugin restarted"
AdvSceneSwitcher.condition.pluginState.state.running="Plugin is running"
AdvSceneSwitcher.condition.pluginState.state.shutdown="OBS is shutting down"
AdvSceneSwitcher.condition.pluginState.state.shutdown.limitation="Note that while actions performing OBS specific changes will still be executed on shutdown those changes will not be saved as OBS is already shutting down!"
AdvSceneSwitcher.condition.pluginState.state.sceneCollection="Scene collection loaded"
AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="Scene changed by previous macro"
AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
@@ -314,12 +272,10 @@ AdvSceneSwitcher.condition.timer.entry.line2="Time remaining: {{remaining}} seco
AdvSceneSwitcher.condition.timer.entry.line3="{{pauseContinue}} {{reset}} {{saveRemaining}} Save time remaining {{autoReset}} Automatically reset timer after duration was reached"
AdvSceneSwitcher.condition.timer.reset="Reset"
AdvSceneSwitcher.condition.macro="Macro"
AdvSceneSwitcher.condition.macro.type.count="Macro run count"
AdvSceneSwitcher.condition.macro.type.state="Macro condition state"
AdvSceneSwitcher.condition.macro.type.multiState="Multiple macro condition state"
AdvSceneSwitcher.condition.macro.type.actionDisabled="Macro action disabled"
AdvSceneSwitcher.condition.macro.type.actionEnabled="Macro action enabled"
AdvSceneSwitcher.condition.macro.type.selection="{{types}}"
AdvSceneSwitcher.condition.macro.type.count="Count"
AdvSceneSwitcher.condition.macro.type.state="State"
AdvSceneSwitcher.condition.macro.type.multiState="Multiple states"
AdvSceneSwitcher.condition.macro.type.selection="Condition type: {{types}}"
AdvSceneSwitcher.condition.macro.count.type.below="Less than"
AdvSceneSwitcher.condition.macro.count.type.above="More than"
AdvSceneSwitcher.condition.macro.count.type.equal="Exactly"
@@ -332,17 +288,14 @@ AdvSceneSwitcher.condition.macro.state.entry="Conditions of {{macros}} are true"
AdvSceneSwitcher.condition.macro.multistate.entry="Conditions of {{multiStateConditions}}{{multiStateCount}} of the following macros are true:"
AdvSceneSwitcher.condition.macro.count.entry.line1="{{macros}} was executed {{conditions}} {{count}} times"
AdvSceneSwitcher.condition.macro.count.entry.line2="Current count: {{currentCount}} {{resetCount}}"
AdvSceneSwitcher.condition.macro.actionState.disabled.entry="Action{{actionIndex}}of{{macros}}is disabled"
AdvSceneSwitcher.condition.macro.actionState.enabled.entry="Action{{actionIndex}}of{{macros}}is enabled"
AdvSceneSwitcher.condition.source="Source"
AdvSceneSwitcher.condition.source.type.active="Is active"
AdvSceneSwitcher.condition.source.type.showing="Is showing"
AdvSceneSwitcher.condition.source.type.settings="Settings match"
AdvSceneSwitcher.condition.source.sceneVisibilityHint="Scene specific visibility can be checked using the \"Scene item visibility\" condition"
AdvSceneSwitcher.condition.source.getSettings="Get current settings"
AdvSceneSwitcher.condition.source.entry.line1="{{sources}}{{conditions}}"
AdvSceneSwitcher.condition.source.entry.line1="{{sources}} {{conditions}}"
AdvSceneSwitcher.condition.source.entry.line2="{{settings}}"
AdvSceneSwitcher.condition.source.entry.line3="{{regex}}{{getSettings}}"
AdvSceneSwitcher.condition.source.entry.line3="{{regex}} {{getSettings}}"
AdvSceneSwitcher.condition.virtualCamera="Virtual camera"
AdvSceneSwitcher.condition.virtualCamera.state.start="Virtual camera started"
AdvSceneSwitcher.condition.virtualCamera.state.stop="Virtual camera stopped"
@@ -354,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"
@@ -447,8 +400,8 @@ AdvSceneSwitcher.condition.stats.entry="{{stats}} is {{condition}} {{value}}"
AdvSceneSwitcher.condition.profile="Profile"
AdvSceneSwitcher.condition.profile.entry="Current active profile is {{profiles}}"
AdvSceneSwitcher.condition.websocket="Websocket"
AdvSceneSwitcher.condition.websocket.type.request="Scene Switcher Request"
AdvSceneSwitcher.condition.websocket.type.event="Scene Switcher Event"
AdvSceneSwitcher.condition.websocket.type.request="Request"
AdvSceneSwitcher.condition.websocket.type.event="Event"
AdvSceneSwitcher.condition.websocket.useRegex="Use regular expressions"
AdvSceneSwitcher.condition.websocket.entry.request="{{type}} was received:"
AdvSceneSwitcher.condition.websocket.entry.event="{{type}} was received from {{connection}}:"
@@ -463,22 +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}}"
AdvSceneSwitcher.condition.slideshow="Slide Show"
AdvSceneSwitcher.condition.slideshow.condition.slideChanged="Slide changed"
AdvSceneSwitcher.condition.slideshow.condition.slideIndex="Current slide number is"
AdvSceneSwitcher.condition.slideshow.condition.slidePath="Current slide path is"
AdvSceneSwitcher.condition.slideshow.updateIntervalTooltip="Information about the slide show status will only be updated based on the configured time between slides"
AdvSceneSwitcher.condition.slideshow.entry="{{sources}}{{conditions}}{{index}}{{path}}"
; Macro Actions
AdvSceneSwitcher.action.switchScene="Switch scene"
@@ -512,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"
@@ -526,24 +461,23 @@ 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.type.server="Set server URL"
AdvSceneSwitcher.action.streaming.type.streamKey="Set stream key"
AdvSceneSwitcher.action.streaming.type.username="Set username"
AdvSceneSwitcher.action.streaming.type.password="Set password"
AdvSceneSwitcher.action.streaming.entry="{{actions}}{{keyFrameInterval}}{{stringValue}}{{showPassword}}"
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"
AdvSceneSwitcher.action.sceneVisibility.type.toggle="Toggle"
AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Any"
AdvSceneSwitcher.action.sceneVisibility.entry="On{{scenes}}{{actions}}{{sources}}"
AdvSceneSwitcher.action.sceneVisibility.entry="On{{scenes}}{{actions}}{{sourceTypes}}{{sources}}{{sourceGroups}}"
AdvSceneSwitcher.action.filter="Filter"
AdvSceneSwitcher.action.filter.type.enable="Enable"
AdvSceneSwitcher.action.filter.type.disable="Disable"
AdvSceneSwitcher.action.filter.type.toggle="Toggle"
AdvSceneSwitcher.action.filter.type.settings="Set settings"
AdvSceneSwitcher.action.filter.entry="On {{sources}} {{actions}} {{filters}}"
AdvSceneSwitcher.action.filter.getSettings="Get current settings"
@@ -554,23 +488,10 @@ AdvSceneSwitcher.action.source.type.settings="Set settings"
AdvSceneSwitcher.action.source.type.refreshSettings="Refresh source settings"
AdvSceneSwitcher.action.source.type.pressSettingsButton="Press settings button"
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="Can be used to refresh browser, media, etc. sources"
AdvSceneSwitcher.action.source.type.deinterlaceMode="Set deinterlace mode"
AdvSceneSwitcher.action.source.type.deinterlaceOrder="Set deinterlace field order"
AdvSceneSwitcher.action.source.noSettingsButtons="No buttons found!"
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}"
AdvSceneSwitcher.action.source.warning="Warning: Enabling and disabling sources globally cannot be controlled by the OBS UI\nYou might be looking for \"Scene item visibility\""
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}"
AdvSceneSwitcher.action.source.warning="Warning: Enabling and disabling sources globally cannot be controlled by the OBS UI"
AdvSceneSwitcher.action.source.getSettings="Get current settings"
AdvSceneSwitcher.action.source.deinterlaceMode.disable="Disable"
AdvSceneSwitcher.action.source.deinterlaceMode.discard="Discard"
AdvSceneSwitcher.action.source.deinterlaceMode.retro="Retro"
AdvSceneSwitcher.action.source.deinterlaceMode.blend="Blend"
AdvSceneSwitcher.action.source.deinterlaceMode.blend2x="Blend 2x"
AdvSceneSwitcher.action.source.deinterlaceMode.linear="Linear"
AdvSceneSwitcher.action.source.deinterlaceMode.linear2x="Linear 2x"
AdvSceneSwitcher.action.source.deinterlaceMode.yadif="Yadif"
AdvSceneSwitcher.action.source.deinterlaceMode.yadif2x="Yadif 2x"
AdvSceneSwitcher.action.source.deinterlaceOrder.topFieldFirst="Top Field First"
AdvSceneSwitcher.action.source.deinterlaceOrder.bottomFieldFirst="Bottom Field First"
AdvSceneSwitcher.action.media="Media"
AdvSceneSwitcher.action.media.type.play="Play"
AdvSceneSwitcher.action.media.type.pause="Pause"
@@ -586,30 +507,18 @@ AdvSceneSwitcher.action.macro.type.unpause="Unpause"
AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter"
AdvSceneSwitcher.action.macro.type.run="Run actions"
AdvSceneSwitcher.action.macro.type.stop="Stop actions"
AdvSceneSwitcher.action.macro.type.disableAction="Disable action"
AdvSceneSwitcher.action.macro.type.enableAction="Enable action"
AdvSceneSwitcher.action.macro.type.toggleAction="Toggle action"
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
AdvSceneSwitcher.action.pluginState="Plugin state"
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
AdvSceneSwitcher.action.pluginState.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"
AdvSceneSwitcher.action.virtualCamera.type.start="Start virtual camera"
AdvSceneSwitcher.action.virtualCamera.entry="{{actions}}"
AdvSceneSwitcher.action.hotkey="Hotkey"
AdvSceneSwitcher.action.hotkey.type.obs="OBS hotkey"
AdvSceneSwitcher.action.hotkey.type.obs.type.frontend="Frontend"
AdvSceneSwitcher.action.hotkey.type.obs.type.soruce="Source"
AdvSceneSwitcher.action.hotkey.type.obs.type.output="Output"
AdvSceneSwitcher.action.hotkey.type.obs.type.encoder="Encoder"
AdvSceneSwitcher.action.hotkey.type.obs.type.service="Service"
AdvSceneSwitcher.action.hotkey.type.custom="Custom hotkey"
AdvSceneSwitcher.action.hotkey.leftShift="Left Shift"
AdvSceneSwitcher.action.hotkey.rightShift="Right Shift"
AdvSceneSwitcher.action.hotkey.leftCtrl="Left Ctrl"
@@ -620,8 +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.custom="Press{{actionType}}{{keys}}for{{duration}}"
AdvSceneSwitcher.action.hotkey.entry.obs="Press{{actionType}}{{hotkeyType}}{{obsHotkeys}}"
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"
@@ -630,18 +538,8 @@ AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Move to bottom"
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Move to position"
AdvSceneSwitcher.action.sceneOrder.entry="On{{scenes}}{{actions}}{{sources}}{{position}}"
AdvSceneSwitcher.action.sceneTransform="Scene item transform"
AdvSceneSwitcher.action.sceneTransform.type.manual="Transform"
AdvSceneSwitcher.action.sceneTransform.type.reset="Reset transform"
AdvSceneSwitcher.action.sceneTransform.type.rotate="Rotate by"
AdvSceneSwitcher.action.sceneTransform.type.flipHorizontal="Flip horizontally"
AdvSceneSwitcher.action.sceneTransform.type.flipVertical="Flip vertically"
AdvSceneSwitcher.action.sceneTransform.type.fitToScreen="Fit to screen"
AdvSceneSwitcher.action.sceneTransform.type.stretchToScreen="Stretch to screen"
AdvSceneSwitcher.action.sceneTransform.type.centerToScreen="Center to screen"
AdvSceneSwitcher.action.sceneTransform.type.centerVertically="Center vertically"
AdvSceneSwitcher.action.sceneTransform.type.centerHorizontally="Center horizontally"
AdvSceneSwitcher.action.sceneTransform.getTransform="Get transform"
AdvSceneSwitcher.action.sceneTransform.entry="On{{scenes}}{{action}}{{rotation}}{{sources}}"
AdvSceneSwitcher.action.sceneTransform.entry="On{{scenes}}transform{{sources}}"
AdvSceneSwitcher.action.file="File"
AdvSceneSwitcher.action.file.type.write="Write"
AdvSceneSwitcher.action.file.type.append="Append"
@@ -670,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"
@@ -694,20 +589,11 @@ AdvSceneSwitcher.action.sequence.status.none="none"
AdvSceneSwitcher.action.sequence.restart="Restart from beginning once end of list is reached"
AdvSceneSwitcher.action.sequence.continueFrom="Continue with selected item"
AdvSceneSwitcher.action.websocket="Websocket"
AdvSceneSwitcher.action.websocket.api.sceneSwitcher="Scene Switcher message"
AdvSceneSwitcher.action.websocket.api.obsWebsocket="OBS websocket message"
AdvSceneSwitcher.action.websocket.api.genericWebsocket="Generic websocket message"
AdvSceneSwitcher.action.websocket.type.request="Request"
AdvSceneSwitcher.action.websocket.type.event="Event"
AdvSceneSwitcher.action.websocket.settingsConflictGeneric="Possible settings conflict: Generic websocket message selection with connection which follows the OBS protocol!"
AdvSceneSwitcher.action.websocket.settingsConflictOBS="Possible settings conflict: Connection selected which only supports generic websockte messages while message type requires OBS protocol!"
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.request="Send{{api}}of type{{type}}via{{connection}}"
AdvSceneSwitcher.action.websocket.entry.sceneSwitcher.event="Send{{api}}of type{{type}}to connected clients"
AdvSceneSwitcher.action.websocket.entry.generic="Send{{api}}via{{connection}}"
AdvSceneSwitcher.action.http="HTTP"
AdvSceneSwitcher.action.http.setHeaders="Set headers"
AdvSceneSwitcher.action.http.headers="Headers:"
AdvSceneSwitcher.action.http.addHeader="Add header"
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.type.get="GET"
AdvSceneSwitcher.action.http.type.post="POST"
AdvSceneSwitcher.action.http.entry.line1="Send {{method}} to {{url}}"
@@ -722,25 +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.type.askForValue="Get user input"
AdvSceneSwitcher.action.variable.askForValuePromptDefault="Assign value to variable \"%1\":"
AdvSceneSwitcher.action.variable.askForValuePrompt="Assign value to variable:"
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.variable.entry.userInput="{{useCustomPrompt}}Use custom prompt{{inputPrompt}}"
AdvSceneSwitcher.action.projector="Projector"
AdvSceneSwitcher.action.projector.type.source="Source"
AdvSceneSwitcher.action.projector.type.scene="Scene"
@@ -752,15 +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"
AdvSceneSwitcher.action.sceneLock="Scene item lock"
AdvSceneSwitcher.action.sceneLock.type.lock="lock"
AdvSceneSwitcher.action.sceneLock.type.unlock="unlock"
AdvSceneSwitcher.action.sceneLock.type.toggle="toggle lock of"
AdvSceneSwitcher.action.sceneLock.entry="On{{scenes}}{{actions}}{{sources}}"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="Transition"
@@ -819,7 +687,7 @@ AdvSceneSwitcher.mediaTab.states.none="None"
AdvSceneSwitcher.mediaTab.states.playing="Playing"
AdvSceneSwitcher.mediaTab.states.opening="Opening"
AdvSceneSwitcher.mediaTab.states.buffering="Buffering"
AdvSceneSwitcher.mediaTab.states.paused="Paused"
AdvSceneSwitcher.mediaTab.states.Paused="Paused"
AdvSceneSwitcher.mediaTab.states.stopped="Stopped"
AdvSceneSwitcher.mediaTab.states.ended="Ended"
AdvSceneSwitcher.mediaTab.states.error="Error"
@@ -1022,11 +890,8 @@ AdvSceneSwitcher.item.emptyName="Empty name not allowed!"
AdvSceneSwitcher.item.nameNotAvailable="Name not available!"
AdvSceneSwitcher.item.nameReserved="Name reserved!"
AdvSceneSwitcher.macroSegmentSelection.invalid="Invalid selection!"
AdvSceneSwitcher.variable.select="--select variable--"
AdvSceneSwitcher.variable.add="Add new variable"
AdvSceneSwitcher.variable.configure="Configure variable settings"
AdvSceneSwitcher.variable.name="Name:"
AdvSceneSwitcher.variable.value="Current value:"
AdvSceneSwitcher.variable.save="Save / load behavior"
@@ -1036,17 +901,13 @@ AdvSceneSwitcher.variable.save.default="Set to value"
AdvSceneSwitcher.connection.select="--select connection--"
AdvSceneSwitcher.connection.add="Add new connection"
AdvSceneSwitcher.connection.configure="Configure connection settings"
AdvSceneSwitcher.connection.name="Name:"
AdvSceneSwitcher.connection.useCustomURI="Use custom URI"
AdvSceneSwitcher.connection.customURI="Address:"
AdvSceneSwitcher.connection.address="Address:"
AdvSceneSwitcher.connection.port="Port:"
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"
@@ -1054,75 +915,12 @@ AdvSceneSwitcher.connection.status.connected="Connected, but not authenticated"
AdvSceneSwitcher.connection.status.authenticated="Connected and authenticated"
AdvSceneSwitcher.regex.enable="Enable regular expressions"
AdvSceneSwitcher.regex.configure="Configure regular expression settings"
AdvSceneSwitcher.regex.partialMatch="Allow partial match"
AdvSceneSwitcher.regex.caseInsensitive="Match case insensitive"
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"
@@ -1146,25 +944,8 @@ AdvSceneSwitcher.selectSceneCollection="--select scene collection--"
AdvSceneSwitcher.enterPath="--enter path--"
AdvSceneSwitcher.enterText="--enter text--"
AdvSceneSwitcher.enterURL="--enter URL--"
AdvSceneSwitcher.selectHotkey="--select hotkey--"
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved"
AdvSceneSwitcher.selectWindowTip="Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB"
AdvSceneSwitcher.sceneItemSelection.configure="Configure scene item selection type"
AdvSceneSwitcher.sceneItemSelection.type.sourceName="Source name"
AdvSceneSwitcher.sceneItemSelection.type.sourceName.entry="{{nameConflictIndex}}{{sourceName}}"
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable="Variable name"
AdvSceneSwitcher.sceneItemSelection.type.sourceVariable.entry="{{nameConflictIndex}}{{variable}}"
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern="Source name matches pattern"
AdvSceneSwitcher.sceneItemSelection.type.sourceNamePattern.entry="{{nameConflictIndex}}matching{{pattern}}{{regex}}"
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup="Sources of type"
AdvSceneSwitcher.sceneItemSelection.type.sourceGroup.entry="{{nameConflictIndex}}Source type{{sourceGroups}}"
AdvSceneSwitcher.sceneItemSelection.type.index="Source with index"
AdvSceneSwitcher.sceneItemSelection.type.index.entry="{{index}}source"
AdvSceneSwitcher.sceneItemSelection.type.indexRange="Sources in index range"
AdvSceneSwitcher.sceneItemSelection.type.indexRange.entry="Sources from{{index}}to{{indexEnd}}"
AdvSceneSwitcher.sceneItemSelection.type.all="All sources"
AdvSceneSwitcher.sceneItemSelection.type.all.entry="All sources"
AdvSceneSwitcher.sceneItemSelection.all="All"
AdvSceneSwitcher.sceneItemSelection.any="Any"

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}}{{stringValue}}{{showPassword}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.run="Ejecutar"
AdvSceneSwitcher.action.run.arguments="Argumentos:"
AdvSceneSwitcher.action.run.addArgument="Agregar argumento"
@@ -371,7 +371,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.show="Mostrar"
AdvSceneSwitcher.action.sceneVisibility.type.hide="Ocultar"
AdvSceneSwitcher.action.sceneVisibility.type.source="Fuente"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Cualquiera"
AdvSceneSwitcher.action.sceneVisibility.entry="En{{scenes}}{{actions}}{{sources}}"
AdvSceneSwitcher.action.sceneVisibility.entry="En{{scenes}}{{actions}}{{sourceTypes}}{{sources}}{{sourceGroups}}"
AdvSceneSwitcher.action.filter="Filtro"
AdvSceneSwitcher.action.filter.type.enable="Habilitar"
AdvSceneSwitcher.action.filter.type.disable="Deshabilitar"
@@ -382,7 +382,7 @@ AdvSceneSwitcher.action.source="Fuente"
AdvSceneSwitcher.action.source.type.enable="Habilitar"
AdvSceneSwitcher.action.source.type.disable="Deshabilitar"
AdvSceneSwitcher.action.source.type.settings="Establecer configuración"
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}"
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}"
AdvSceneSwitcher.action.source.warning="Advertencia: la IU de OBS no puede controlar la habilitación y deshabilitación global de fuentes"
AdvSceneSwitcher.action.source.getSettings="Obtener la configuración actual"
AdvSceneSwitcher.action.media="Medios"
@@ -400,7 +400,7 @@ AdvSceneSwitcher.action.macro.type.unpause="Reanudar"
AdvSceneSwitcher.action.macro.type.resetCounter="Reiniciar contador"
AdvSceneSwitcher.action.macro.type.run="Ejecutar"
AdvSceneSwitcher.action.macro.type.stop="Detener"
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
AdvSceneSwitcher.action.pluginState="Estado del complemento"
AdvSceneSwitcher.action.pluginState.type.stop="Detener el complemento Advanced Scene Switcher"
AdvSceneSwitcher.action.pluginState.type.noMatch="Cambiar el comportamiento de no coincidencia:"
@@ -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"
@@ -432,7 +432,7 @@ AdvSceneSwitcher.action.sceneOrder.type.movePosition="Mover a la posición"
AdvSceneSwitcher.action.sceneOrder.entry="En{{scenes}}{{actions}}{{sources}}{{position}}"
AdvSceneSwitcher.action.sceneTransform="Transformar elemento de escena"
AdvSceneSwitcher.action.sceneTransform.getTransform="Obtener transformación"
AdvSceneSwitcher.action.sceneTransform.entry="En{{scenes}}{{action}}{{rotation}}{{sources}}"
AdvSceneSwitcher.action.sceneTransform.entry="En{{scenes}}transformar{{sources}}"
AdvSceneSwitcher.action.file="Archivo"
AdvSceneSwitcher.action.file.type.write="Escribir"
AdvSceneSwitcher.action.file.type.append="Agregar"
@@ -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"
@@ -531,7 +532,7 @@ AdvSceneSwitcher.mediaTab.states.none="Ninguno"
AdvSceneSwitcher.mediaTab.states.playing="Reproduciéndose"
AdvSceneSwitcher.mediaTab.states.opening="Abriendo"
AdvSceneSwitcher.mediaTab.states.buffering="Almacenando en búfer"
AdvSceneSwitcher.mediaTab.states.paused="Pausado"
AdvSceneSwitcher.mediaTab.states.Paused="Pausado"
AdvSceneSwitcher.mediaTab.states.stopped="Detenido"
AdvSceneSwitcher.mediaTab.states.ended="Finalizado"
AdvSceneSwitcher.mediaTab.states.error="Error"

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}}{{stringValue}}{{showPassword}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.run="Запустить"
@@ -205,7 +205,7 @@ AdvSceneSwitcher.mediaTab.states.none="Нет"
AdvSceneSwitcher.mediaTab.states.playing="Играет"
AdvSceneSwitcher.mediaTab.states.opening="Открытие"
AdvSceneSwitcher.mediaTab.states.buffering="Буферизация"
AdvSceneSwitcher.mediaTab.states.paused="Приостановлено"
AdvSceneSwitcher.mediaTab.states.Paused="Приостановлено"
AdvSceneSwitcher.mediaTab.states.stopped="Остановлено"
AdvSceneSwitcher.mediaTab.states.ended="Закончилось"
AdvSceneSwitcher.mediaTab.states.error="Ошибка"

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}}{{stringValue}}{{showPassword}}"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.run="Çalıştır"
AdvSceneSwitcher.action.run.arguments="Argümanlar:"
AdvSceneSwitcher.action.run.addArgument="Argüman ekle"
@@ -301,7 +301,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.show="Göster"
AdvSceneSwitcher.action.sceneVisibility.type.hide="Gizle"
AdvSceneSwitcher.action.sceneVisibility.type.source="Kayıt"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Herhangi"
AdvSceneSwitcher.action.sceneVisibility.entry="Açık{{scenes}}{{actions}}{{sources}}"
AdvSceneSwitcher.action.sceneVisibility.entry="Açık{{scenes}}{{actions}}{{sourceTypes}}{{sources}}{{sourceGroups}}"
AdvSceneSwitcher.action.filter="Filtrele"
AdvSceneSwitcher.action.filter.type.enable="Etkin"
AdvSceneSwitcher.action.filter.type.disable="Etkisiz"
@@ -312,7 +312,7 @@ AdvSceneSwitcher.action.source="Kaynak"
AdvSceneSwitcher.action.source.type.enable="Etkin"
AdvSceneSwitcher.action.source.type.disable="Etkisiz"
AdvSceneSwitcher.action.source.type.settings="Ayarları yap"
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}"
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}"
AdvSceneSwitcher.action.source.warning="Uyarı: Kaynakların global olarak etkinleştirilmesi ve devre dışı bırakılması, OBS UI tarafından kontrol edilemez"
AdvSceneSwitcher.action.source.getSettings="Mevcut Ayarları yap"
AdvSceneSwitcher.action.media="Medya"
@@ -328,7 +328,7 @@ AdvSceneSwitcher.action.macro.type.pause="Duraklat"
AdvSceneSwitcher.action.macro.type.unpause="Duraklatma"
AdvSceneSwitcher.action.macro.type.resetCounter="Sayacı sıfırla"
AdvSceneSwitcher.action.macro.type.run="Çalıştır"
AdvSceneSwitcher.action.macro.entry="{{actions}}{{actionIndex}}{{macros}}"
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
AdvSceneSwitcher.action.pluginState="Eklenti durumu"
AdvSceneSwitcher.action.pluginState.type.stop="Advanced Scene Switcher eklentisini durdurun"
AdvSceneSwitcher.action.pluginState.type.noMatch="Eşleşmeme davranışını değiştirin:"
@@ -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"
@@ -360,7 +360,7 @@ AdvSceneSwitcher.action.sceneOrder.type.movePosition="Konuma taşı"
AdvSceneSwitcher.action.sceneOrder.entry="Açık{{scenes}}{{actions}}{{sources}}{{position}}"
AdvSceneSwitcher.action.sceneTransform="Sahne öğesi dönüşümü"
AdvSceneSwitcher.action.sceneTransform.getTransform="Dönüşümü al"
AdvSceneSwitcher.action.sceneTransform.entry="Açık{{scenes}}{{action}}{{rotation}}{{sources}}"
AdvSceneSwitcher.action.sceneTransform.entry="Açık{{scenes}}transform{{sources}}"
AdvSceneSwitcher.action.file="Dosya"
AdvSceneSwitcher.action.file.type.write="Yaz"
AdvSceneSwitcher.action.file.type.append="Ekle"
@@ -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"
@@ -442,7 +443,7 @@ AdvSceneSwitcher.mediaTab.states.none="Yok"
AdvSceneSwitcher.mediaTab.states.playing="Oynamak"
AdvSceneSwitcher.mediaTab.states.opening="Açmak"
AdvSceneSwitcher.mediaTab.states.buffering="Arabelleğe alma"
AdvSceneSwitcher.mediaTab.states.paused="Duraklatıldı"
AdvSceneSwitcher.mediaTab.states.Paused="Duraklatıldı"
AdvSceneSwitcher.mediaTab.states.stopped="Durduruldu"
AdvSceneSwitcher.mediaTab.states.ended="Bitti"
AdvSceneSwitcher.mediaTab.states.error="Hata"

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,45 +391,43 @@ 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}}{{stringValue}}{{showPassword}}"
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}}{{sources}}"
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.entry="{{actions}}{{sources}}{{settingsButtons}}{{deinterlaceMode}}{{deinterlaceOrder}}"
AdvSceneSwitcher.action.source.type.refreshSettings.tooltip="可用于刷新浏览器、媒体等源"
AdvSceneSwitcher.action.source.entry="{{actions}}{{sources}}{{settingsButtons}}"
AdvSceneSwitcher.action.source.warning="警告OBS UI无法控制全局启用和禁用源注意通过这个设置禁用我测试你必须通过这个在启用才行不然点击小眼睛你无法显示"
AdvSceneSwitcher.action.source.getSettings="获取当前设置"
AdvSceneSwitcher.action.media="媒体"
@@ -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.entry="{{actions}}{{actionIndex}}{{macros}}"
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}}{{action}}{{rotation}}{{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="转场特效"
@@ -732,7 +601,7 @@ AdvSceneSwitcher.mediaTab.states.none="无"
AdvSceneSwitcher.mediaTab.states.playing="播放中"
AdvSceneSwitcher.mediaTab.states.opening="打开中"
AdvSceneSwitcher.mediaTab.states.buffering="缓冲中"
AdvSceneSwitcher.mediaTab.states.paused="暂停"
AdvSceneSwitcher.mediaTab.states.Paused="暂停"
AdvSceneSwitcher.mediaTab.states.stopped="停止"
AdvSceneSwitcher.mediaTab.states.ended="结束"
AdvSceneSwitcher.mediaTab.states.error="错误"
@@ -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,9 +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">
<g class="layer">
<title>Layer 1</title>
<path d="m1,2c0,-0.27 0.11,-0.52 0.29,-0.71c0.39,-0.39 1.03,-0.39 1.42,0l5.29,5.3l5.29,-5.3c0.39,-0.39 1.03,-0.39 1.42,0c0.18,0.19 0.29,0.44 0.29,0.71s-0.11,0.52 -0.29,0.71l-6,6c-0.39,0.39 -1.03,0.39 -1.42,0l-6,-6c-0.18,-0.19 -0.29,-0.44 -0.29,-0.71zm0,0" fill="#fefefe" id="svg_1" transform="matrix(1, 0, 0, 1, 0, 0)"/>
<path d="m1,8c0,-0.27 0.09,-0.52 0.28,-0.71c0.38,-0.39 1.03,-0.39 1.41,0l5.31,5.3l5.28,-5.3c0.38,-0.39 1.03,-0.39 1.41,0c0.19,0.19 0.31,0.44 0.31,0.71s-0.13,0.52 -0.31,0.71l-6,6c-0.38,0.39 -1.03,0.39 -1.41,0l-6,-6c-0.19,-0.19 -0.28,-0.44 -0.28,-0.71zm0,0" fill="#fefefe" id="svg_2"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 791 B

View File

@@ -1,9 +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">
<g class="layer">
<title>Layer 1</title>
<path d="m1,8c0,-0.27 0.11,-0.52 0.29,-0.71l6,-6c0.39,-0.39 1.03,-0.39 1.42,0l6,6c0.18,0.19 0.29,0.44 0.29,0.71s-0.11,0.52 -0.29,0.71c-0.39,0.39 -1.03,0.39 -1.42,0l-5.29,-5.3l-5.29,5.3c-0.39,0.39 -1.03,0.39 -1.42,0c-0.18,-0.19 -0.29,-0.44 -0.29,-0.71zm0,0" fill="#fefefe" id="svg_1"/>
<path d="m1,14c0,-0.27 0.11,-0.52 0.28,-0.71l6,-6c0.39,-0.39 1.03,-0.39 1.42,0l6,6c0.19,0.19 0.3,0.44 0.3,0.71s-0.11,0.52 -0.3,0.71c-0.39,0.39 -1.03,0.39 -1.42,0l-5.28,-5.3l-5.3,5.3c-0.39,0.39 -1.03,0.39 -1.42,0c-0.17,-0.19 -0.28,-0.44 -0.28,-0.71zm0,0" fill="#fefefe" id="svg_2"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 753 B

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,9 +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">
<g class="layer">
<title>Layer 1</title>
<path d="m1,2c0,-0.27 0.11,-0.52 0.29,-0.71c0.39,-0.39 1.03,-0.39 1.42,0l5.29,5.3l5.29,-5.3c0.39,-0.39 1.03,-0.39 1.42,0c0.18,0.19 0.29,0.44 0.29,0.71s-0.11,0.52 -0.29,0.71l-6,6c-0.39,0.39 -1.03,0.39 -1.42,0l-6,-6c-0.18,-0.19 -0.29,-0.44 -0.29,-0.71zm0,0" fill="#202020" id="svg_1"/>
<path d="m1,8c0,-0.27 0.11,-0.52 0.29,-0.71c0.39,-0.39 1.03,-0.39 1.42,0l5.29,5.3l5.29,-5.3c0.39,-0.39 1.03,-0.39 1.42,0c0.18,0.19 0.29,0.44 0.29,0.71s-0.11,0.52 -0.29,0.71l-6,6c-0.39,0.39 -1.03,0.39 -1.42,0l-6,-6c-0.18,-0.19 -0.29,-0.44 -0.29,-0.71zm0,0" fill="#202020" id="svg_4" transform="matrix(1, 0, 0, 1, 0, 0)"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 791 B

View File

@@ -1,9 +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">
<g class="layer">
<title>Layer 1</title>
<path d="m1,8c0,-0.27 0.11,-0.52 0.29,-0.71l6,-6c0.39,-0.39 1.03,-0.39 1.42,0l6,6c0.18,0.19 0.29,0.44 0.29,0.71s-0.11,0.52 -0.29,0.71c-0.39,0.39 -1.03,0.39 -1.42,0l-5.29,-5.3l-5.29,5.3c-0.39,0.39 -1.03,0.39 -1.42,0c-0.18,-0.19 -0.29,-0.44 -0.29,-0.71zm0,0" fill="#202020" id="svg_1"/>
<path d="m1,14c0,-0.27 0.11,-0.52 0.29,-0.71l6,-6c0.39,-0.39 1.03,-0.39 1.42,0l6,6c0.18,0.19 0.29,0.44 0.29,0.71s-0.11,0.52 -0.29,0.71c-0.39,0.39 -1.03,0.39 -1.42,0l-5.29,-5.3l-5.29,5.3c-0.39,0.39 -1.03,0.39 -1.42,0c-0.18,-0.19 -0.29,-0.44 -0.29,-0.71zm0,0" fill="#202020" id="svg_2"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 757 B

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>
@@ -988,19 +964,6 @@
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="conditionTop">
<property name="maximumSize">
<size>
<width>22</width>
<height>16777215</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="conditionUp">
<property name="maximumSize">
@@ -1036,19 +999,6 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="conditionBottom">
<property name="maximumSize">
<size>
<width>22</width>
<height>16777215</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_15">
<property name="orientation">
@@ -1156,19 +1106,6 @@
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="actionTop">
<property name="maximumSize">
<size>
<width>22</width>
<height>16777215</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="actionUp">
<property name="maximumSize">
@@ -1201,19 +1138,6 @@
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="actionBottom">
<property name="maximumSize">
<size>
<width>22</width>
<height>16777215</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_14">
<property name="orientation">
@@ -4615,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,19 +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 (!switcher) {
return;
}
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 {
@@ -145,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();
@@ -158,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
******************************************************************************/
@@ -229,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();
@@ -243,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) {
@@ -257,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");
@@ -275,13 +229,13 @@ void SwitcherData::Thread()
}
}
ResetForNextInterval();
ClearWebsocketMessages();
if (match) {
if (macroMatch) {
RunMacros();
runMacros();
} else {
SwitchScene({scene, transition, 0});
switchScene({scene, transition, 0});
}
}
@@ -294,7 +248,7 @@ void SwitcherData::Thread()
blog(LOG_INFO, "stopped");
}
void SwitcherData::SetPreconditions()
void SwitcherData::setPreconditions()
{
// Window title
lastTitle = currentTitle;
@@ -322,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)
@@ -388,7 +332,7 @@ bool SwitcherData::CheckForMatch(OBSWeakSource &scene,
match = checkVideoSwitch(scene, transition);
break;
case macro_func:
if (CheckMacros()) {
if (checkMacros()) {
match = true;
macroMatch = true;
}
@@ -405,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);
@@ -443,7 +415,13 @@ void SwitcherData::Start()
}
}
bool CloseAllInputDialogs();
void ResetMacros()
{
for (auto &m : switcher->macros) {
m->ResetRunCount();
m->ResetTimers();
}
}
void SwitcherData::Stop()
{
@@ -453,24 +431,12 @@ void SwitcherData::Stop()
abortMacroWait = true;
macroWaitCv.notify_all();
macroTransitionCv.notify_all();
th->wait();
delete th;
th = nullptr;
// Not waiting if a dialog was closed is a workaround to avoid
// deadlocks when a variable input dialog is opened while Stop()
// is called.
//
// The QEventLoop handling the dialog would not exit until Stop()
// would return, which itself would wait for the switcher thread
// to complete, which itself is blocked by the variable input
// dialog.
//
// Must be reworked in the future, as this will not go well when
// OBS is shutting down and a dialog is still opened.
if (!CloseAllInputDialogs()) {
th->wait();
delete th;
th = nullptr;
}
writeToStatusFile("Advanced Scene Switcher stopped");
ResetMacros();
}
server.stop();
@@ -483,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) {
@@ -502,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);
@@ -523,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();
}
@@ -557,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();
@@ -594,51 +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 handleShutdown()
void handleExit()
{
if (!switcher) {
return;
}
switcher->obsIsShuttingDown = true;
if (switcher->shutdownConditionCount) {
if (switcher && switcher->obsIsShuttingDown &&
switcher->shutdownConditionCount) {
switcher->Stop();
switcher->CheckMacros();
switcher->RunMacros();
// Unfortunately this will not work as OBS will now allow saving
// the scene collection data at this point, So any OBS specific
// changes done during shutdown will be lost
//
// TODO: Look for a way to possibly resolve this
obs_frontend_save();
switcher->checkMacros();
switcher->runMacros();
}
FreeSceneSwitcher();
}
static void handleSceneCollectionChanging()
void handleSceneCollectionChanging()
{
if (switcher->settingsWindowOpened) {
AdvSceneSwitcher::window->close();
@@ -659,12 +615,8 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
}
switch (event) {
case OBS_FRONTEND_EVENT_SCRIPTING_SHUTDOWN:
// Note: We are intentionally not listening for
// OBS_FRONTEND_EVENT_EXIT here as at that point all scene
// collection data will already have been cleared and thus all
// macros will have already been cleared
handleShutdown();
case OBS_FRONTEND_EVENT_EXIT:
handleExit();
break;
case OBS_FRONTEND_EVENT_SCENE_CHANGED:
handleSceneChange();
@@ -702,16 +654,13 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CHANGING:
handleSceneCollectionChanging();
break;
case OBS_FRONTEND_EVENT_SCENE_COLLECTION_CLEANUP:
SaveSceneSwitcher(nullptr, false, nullptr);
break;
#endif
default:
break;
}
}
static void LoadPlugins()
void LoadPlugins()
{
QFileInfo libPath(
QString(obs_get_module_binary_path(obs_current_module())));
@@ -735,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;
}
}
}
@@ -755,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();
@@ -773,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();
@@ -102,17 +133,14 @@ public slots:
void on_runMacroOnChange_stateChanged(int value);
void on_conditionAdd_clicked();
void on_conditionRemove_clicked();
void on_conditionTop_clicked();
void on_conditionUp_clicked();
void on_conditionDown_clicked();
void on_conditionBottom_clicked();
void on_actionAdd_clicked();
void on_actionRemove_clicked();
void on_actionTop_clicked();
void on_actionUp_clicked();
void on_actionDown_clicked();
void on_actionBottom_clicked();
void MacroSelectionChanged();
void MacroSelectionChanged(const QItemSelection &,
const QItemSelection &);
void UpMacroSegementHotkey();
void DownMacroSegementHotkey();
void DeleteMacroSegementHotkey();
@@ -121,8 +149,6 @@ public slots:
void ShowMacroConditionsContextMenu(const QPoint &);
void CopyMacro();
void RenameCurrentMacro();
void ExportMacros();
void ImportMacros();
void ExpandAllActions();
void ExpandAllConditions();
void CollapseAllActions();
@@ -149,24 +175,137 @@ 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 ResolveMacroImportNameConflict(std::shared_ptr<Macro> &);
bool MacroTabIsInFocus();
MacroSegmentList *conditionsList = nullptr;
@@ -179,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,25 +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;
startupLoadDone = true;
}
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);
@@ -544,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));
@@ -575,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);
@@ -590,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");
@@ -652,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) {
@@ -666,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());
@@ -680,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]);
@@ -713,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);
@@ -754,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");
@@ -769,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);
@@ -783,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) {
@@ -801,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);
}
}
@@ -825,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"));
@@ -835,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"));
@@ -847,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) {
@@ -898,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(
@@ -1022,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;
@@ -437,11 +419,17 @@ void MacroActionAudioEdit::SetWidgetVisibility()
_balance->setVisible(_entryData->_action ==
MacroActionAudio::Action::BALANCE);
_fadeTypes->setDisabled(!_entryData->_fade);
_wait->setDisabled(!_entryData->_fade);
_abortActiveFade->setDisabled(!_entryData->_fade);
_duration->setDisabled(!_entryData->_fade);
_rate->setDisabled(!_entryData->_fade);
_fadeTypeLayout->removeWidget(_fade);
_fadeTypeLayout->removeWidget(_fadeTypes);
_fadeTypeLayout->removeWidget(_duration);
_fadeTypeLayout->removeWidget(_rate);
ClearLayout(_fadeTypeLayout);
clearLayout(_fadeTypeLayout);
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{fade}}", _fade},
{"{{duration}}", _duration},
@@ -449,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);
}
@@ -464,16 +452,10 @@ void MacroActionAudioEdit::SetWidgetVisibility()
_rate->setVisible(_entryData->_fadeType ==
MacroActionAudio::FadeType::RATE);
SetLayoutVisible(_fadeTypeLayout,
setLayoutVisible(_fadeTypeLayout,
hasVolumeControl(_entryData->_action));
SetLayoutVisible(_fadeOptionsLayout,
setLayoutVisible(_fadeOptionsLayout,
hasVolumeControl(_entryData->_action));
_abortActiveFade->setVisible(hasVolumeControl(_entryData->_action) &&
_entryData->_fade);
_wait->setVisible(hasVolumeControl(_entryData->_action) &&
_entryData->_fade);
updateGeometry();
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,15 +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 "switch-button.hpp"
#include "utility.hpp"
#include <QGraphicsOpacityEffect>
namespace advss {
std::map<std::string, MacroActionInfo> &MacroActionFactory::GetMap()
{
static std::map<std::string, MacroActionInfo> _methods;
@@ -81,32 +75,26 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
std::shared_ptr<MacroAction> *entryData,
const std::string &id)
: MacroSegmentEdit(switcher->macroProperties._highlightActions, parent),
_actionSelection(new FilterComboBox()),
_enable(new SwitchButton()),
_actionSelection(new QComboBox()),
_entryData(entryData)
{
QWidget::connect(_actionSelection,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(ActionSelectionChanged(const QString &)));
QWidget::connect(_enable, SIGNAL(checked(bool)), this,
SLOT(ActionEnableChanged(bool)));
QWidget::connect(window(), SIGNAL(HighlightActionsChanged(bool)), this,
SLOT(EnableHighlight(bool)));
QWidget::connect(&_actionStateTimer, SIGNAL(timeout()), this,
SLOT(UpdateActionState()));
populateActionSelection(_actionSelection);
_section->AddHeaderWidget(_enable);
_section->AddHeaderWidget(_actionSelection);
_section->AddHeaderWidget(_headerInfo);
auto actionLayout = new QVBoxLayout;
QVBoxLayout *actionLayout = new QVBoxLayout;
actionLayout->setContentsMargins({7, 7, 7, 7});
actionLayout->addWidget(_section);
_contentLayout->addLayout(actionLayout);
auto mainLayout = new QHBoxLayout;
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->setContentsMargins(0, 0, 0, 0);
mainLayout->setSpacing(0);
mainLayout->addWidget(_frame);
@@ -115,7 +103,6 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
_entryData = entryData;
UpdateEntryData(id);
_actionStateTimer.start(300);
_loading = false;
}
@@ -125,14 +112,10 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
return;
}
std::string id = MacroActionFactory::GetIdByName(text);
if (id.empty()) {
return;
}
HeaderInfoChanged("");
auto idx = _entryData->get()->GetIndex();
auto macro = _entryData->get()->GetMacro();
std::string id = MacroActionFactory::GetIdByName(text);
HeaderInfoChanged("");
{
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->reset();
@@ -150,9 +133,6 @@ void MacroActionEdit::UpdateEntryData(const std::string &id)
{
_actionSelection->setCurrentText(
obs_module_text(MacroActionFactory::GetActionName(id).c_str()));
const bool enabled = (*_entryData)->Enabled();
_enable->setChecked(enabled);
SetDisableEffect(!enabled);
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
this, SLOT(HeaderInfoChanged(const QString &)));
@@ -167,43 +147,6 @@ void MacroActionEdit::SetEntryData(std::shared_ptr<MacroAction> *data)
_entryData = data;
}
void MacroActionEdit::SetDisableEffect(bool value)
{
if (value) {
auto effect = new QGraphicsOpacityEffect(this);
effect->setOpacity(0.5);
_section->setGraphicsEffect(effect);
} else {
_section->setGraphicsEffect(nullptr);
}
}
void MacroActionEdit::ActionEnableChanged(bool value)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
(*_entryData)->SetEnabled(value);
SetDisableEffect(!value);
}
void MacroActionEdit::UpdateActionState()
{
if (_loading || !_entryData) {
return;
}
SetEnableAppearance((*_entryData)->Enabled());
}
void MacroActionEdit::SetEnableAppearance(bool value)
{
_enable->setChecked(value);
SetDisableEffect(!value);
}
std::shared_ptr<MacroSegment> MacroActionEdit::Data()
{
return *_entryData;
@@ -211,7 +154,7 @@ std::shared_ptr<MacroSegment> MacroActionEdit::Data()
void AdvSceneSwitcher::AddMacroAction(int idx)
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -250,7 +193,7 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
void AdvSceneSwitcher::on_actionAdd_clicked()
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -268,7 +211,7 @@ void AdvSceneSwitcher::on_actionAdd_clicked()
void AdvSceneSwitcher::RemoveMacroAction(int idx)
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -294,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;
}
@@ -305,18 +248,9 @@ void AdvSceneSwitcher::on_actionRemove_clicked()
MacroActionSelectionChanged(-1);
}
void AdvSceneSwitcher::on_actionTop_clicked()
{
if (currentActionIdx == -1) {
return;
}
MacroActionReorder(0, currentActionIdx);
MacroActionSelectionChanged(0);
}
void AdvSceneSwitcher::on_actionUp_clicked()
{
if (currentActionIdx == -1 || currentActionIdx == 0) {
if (currentActionIdx == -1) {
return;
}
MoveMacroActionUp(currentActionIdx);
@@ -324,24 +258,13 @@ void AdvSceneSwitcher::on_actionUp_clicked()
}
void AdvSceneSwitcher::on_actionDown_clicked()
{
if (currentActionIdx == -1 ||
currentActionIdx == actionsList->ContentLayout()->count() - 1) {
if (currentActionIdx == -1) {
return;
}
MoveMacroActionDown(currentActionIdx);
MacroActionSelectionChanged(currentActionIdx + 1);
}
void AdvSceneSwitcher::on_actionBottom_clicked()
{
if (currentActionIdx == -1) {
return;
}
const int newIdx = actionsList->ContentLayout()->count() - 1;
MacroActionReorder(newIdx, currentActionIdx);
MacroActionSelectionChanged(newIdx);
}
void AdvSceneSwitcher::SwapActions(Macro *m, int pos1, int pos2)
{
if (pos1 == pos2) {
@@ -366,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;
}
@@ -381,7 +304,7 @@ void AdvSceneSwitcher::MoveMacroActionUp(int idx)
void AdvSceneSwitcher::MoveMacroActionDown(int idx)
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -396,7 +319,7 @@ void AdvSceneSwitcher::MoveMacroActionDown(int idx)
void AdvSceneSwitcher::MacroActionSelectionChanged(int idx)
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
@@ -416,13 +339,13 @@ void AdvSceneSwitcher::MacroActionSelectionChanged(int idx)
void AdvSceneSwitcher::MacroActionReorder(int to, int from)
{
auto macro = GetSelectedMacro();
auto macro = getSelectedMacro();
if (!macro) {
return;
}
if (to == from || from < 0 || from > (int)macro->Actions().size() ||
to < 0 || to > (int)macro->Actions().size()) {
if (from < 0 || from > (int)macro->Actions().size() || to < 0 ||
to > (int)macro->Actions().size()) {
return;
}
{
@@ -438,5 +361,3 @@ void AdvSceneSwitcher::MacroActionReorder(int to, int from)
HighlightAction(to);
emit(MacroSegmentOrderChanged());
}
} // namespace advss

View File

@@ -1,13 +1,9 @@
#pragma once
#include "macro-action.hpp"
#include "filter-combo-box.hpp"
#include <QComboBox>
#include <memory>
namespace advss {
class SwitchButton;
struct MacroActionInfo {
using TCreateMethod = std::shared_ptr<MacroAction> (*)(Macro *m);
using TCreateWidgetMethod = QWidget *(*)(QWidget *parent,
@@ -46,20 +42,12 @@ public:
private slots:
void ActionSelectionChanged(const QString &text);
void ActionEnableChanged(bool);
void UpdateActionState();
private:
std::shared_ptr<MacroSegment> Data();
void SetDisableEffect(bool);
void SetEnableAppearance(bool);
FilterComboBox *_actionSelection;
SwitchButton *_enable;
QComboBox *_actionSelection;
std::shared_ptr<MacroAction> *_entryData;
QTimer _actionStateTimer;
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(
@@ -15,15 +14,28 @@ const static std::map<MacroActionFilter::Action, std::string> actionTypes = {
"AdvSceneSwitcher.action.filter.type.enable"},
{MacroActionFilter::Action::DISABLE,
"AdvSceneSwitcher.action.filter.type.disable"},
{MacroActionFilter::Action::TOGGLE,
"AdvSceneSwitcher.action.filter.type.toggle"},
{MacroActionFilter::Action::SETTINGS,
"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);
@@ -31,11 +43,8 @@ bool MacroActionFilter::PerformAction()
case Action::DISABLE:
obs_source_set_enabled(s, false);
break;
case Action::TOGGLE:
obs_source_set_enabled(s, !obs_source_enabled(s));
break;
case Action::SETTINGS:
SetSourceSettings(s, _settings);
setSourceSettings(s, _settings);
break;
default:
break;
@@ -50,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",
@@ -62,10 +71,9 @@ 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");
obs_data_set_int(obj, "version", 1);
return true;
}
@@ -73,26 +81,18 @@ bool MacroActionFilter::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_source.Load(obj);
_filter.Load(obj, _source, "filter");
// TODO: Remove this fallback in future version
if (!obs_data_has_user_value(obj, "version")) {
const auto value = obs_data_get_int(obj, "action");
if (value == 2) {
_action = Action::SETTINGS;
} else {
_action = static_cast<Action>(value);
}
} else {
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
}
_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;
}
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 "";
}
@@ -108,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"))),
@@ -126,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,
@@ -141,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);
@@ -168,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);
@@ -182,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()));
}
@@ -205,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);
@@ -213,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()
@@ -228,7 +234,7 @@ void MacroActionFilterEdit::SettingsChanged()
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_settings = _settings->toPlainText().toStdString();
adjustSize();
@@ -240,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) {}
@@ -27,18 +24,22 @@ public:
enum class Action {
ENABLE,
DISABLE,
TOGGLE,
SETTINGS,
};
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 {
@@ -59,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();
@@ -68,7 +69,7 @@ signals:
protected:
SourceSelectionWidget *_sources;
FilterSelectionWidget *_filters;
QComboBox *_filters;
QComboBox *_actions;
QPushButton *_getSettings;
VariableTextEdit *_settings;
@@ -78,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(
@@ -13,26 +10,6 @@ bool MacroActionHotkey::_registered = MacroActionFactory::Register(
{MacroActionHotkey::Create, MacroActionHotkeyEdit::Create,
"AdvSceneSwitcher.action.hotkey"});
const static std::map<MacroActionHotkey::Action, std::string> actionTypes = {
{MacroActionHotkey::Action::OBS_HOTKEY,
"AdvSceneSwitcher.action.hotkey.type.obs"},
{MacroActionHotkey::Action::CUSTOM,
"AdvSceneSwitcher.action.hotkey.type.custom"},
};
const static std::map<obs_hotkey_registerer_type, std::string> hotkeyTypes = {
{OBS_HOTKEY_REGISTERER_FRONTEND,
"AdvSceneSwitcher.action.hotkey.type.obs.type.frontend"},
{OBS_HOTKEY_REGISTERER_SOURCE,
"AdvSceneSwitcher.action.hotkey.type.obs.type.soruce"},
{OBS_HOTKEY_REGISTERER_OUTPUT,
"AdvSceneSwitcher.action.hotkey.type.obs.type.output"},
{OBS_HOTKEY_REGISTERER_ENCODER,
"AdvSceneSwitcher.action.hotkey.type.obs.type.encoder"},
{OBS_HOTKEY_REGISTERER_SERVICE,
"AdvSceneSwitcher.action.hotkey.type.obs.type.service"},
};
static std::unordered_map<HotkeyType, long> keyTable = {
// Chars
{HotkeyType::Key_A, OBS_KEY_A},
@@ -153,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());
@@ -202,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)) {
@@ -216,92 +192,7 @@ static void InjectKeys(const std::vector<HotkeyType> &keys, int duration)
obs_hotkey_inject_event(combo, false);
}
static void addNamePrefix(std::string &name, obs_hotkey_t *hotkey)
{
const auto type = obs_hotkey_get_registerer_type(hotkey);
std::string prefix;
if (type == OBS_HOTKEY_REGISTERER_SOURCE) {
auto source = reinterpret_cast<obs_weak_source_t *>(
obs_hotkey_get_registerer(hotkey));
prefix = "[" + GetWeakSourceName(source) + "] ";
} else if (type == OBS_HOTKEY_REGISTERER_OUTPUT) {
auto weakOutput = reinterpret_cast<obs_weak_output_t *>(
obs_hotkey_get_registerer(hotkey));
std::string name;
auto output = obs_weak_output_get_output(weakOutput);
if (output) {
name = obs_output_get_name(output);
obs_output_release(output);
}
prefix = "[" + name + "] ";
} else if (type == OBS_HOTKEY_REGISTERER_ENCODER) {
auto weakEncoder = reinterpret_cast<obs_weak_encoder_t *>(
obs_hotkey_get_registerer(hotkey));
std::string name;
auto encoder = obs_weak_encoder_get_encoder(weakEncoder);
if (encoder) {
name = obs_encoder_get_name(encoder);
obs_encoder_release(encoder);
}
prefix = "[" + name + "] ";
} else if (type == OBS_HOTKEY_REGISTERER_SERVICE) {
auto weakService = reinterpret_cast<obs_weak_service_t *>(
obs_hotkey_get_registerer(hotkey));
std::string name;
auto service = obs_weak_service_get_service(weakService);
if (service) {
name = obs_service_get_name(service);
obs_service_release(service);
}
prefix = "[" + name + "] ";
}
name = prefix + name;
}
static obs_hotkey_id getHotkeyIdByName(const std::string &name)
{
struct Parameters {
std::string name;
obs_hotkey_id id = OBS_INVALID_HOTKEY_ID;
} params;
auto func = [](void *param, obs_hotkey_id id, obs_hotkey_t *hotkey) {
auto params = static_cast<Parameters *>(param);
std::string name = obs_hotkey_get_name(hotkey);
addNamePrefix(name, hotkey);
if (name == params->name) {
params->id = id;
return false;
}
return true;
};
params.name = name;
obs_enum_hotkeys(func, &params);
return params.id;
}
void MacroActionHotkey::SendOBSHotkey()
{
auto id = getHotkeyIdByName(_hotkeyName);
if (id == OBS_INVALID_HOTKEY_ID) {
blog(LOG_WARNING,
"failed to get hotkey id for \"%s\" - key will not be pressed",
_hotkeyName.c_str());
return;
}
obs_queue_task(
OBS_TASK_UI,
[](void *param) {
auto id = (size_t *)param;
obs_hotkey_trigger_routed_callback(*id, false);
obs_hotkey_trigger_routed_callback(*id, true);
obs_hotkey_trigger_routed_callback(*id, false);
},
&id, true);
}
void MacroActionHotkey::SendCustomHotkey()
bool MacroActionHotkey::PerformAction()
{
std::vector<HotkeyType> keys;
if (_leftShift) {
@@ -333,7 +224,7 @@ void MacroActionHotkey::SendCustomHotkey()
}
if (!keys.empty()) {
int dur = _duration.Milliseconds();
int dur = _duration;
if (_onlySendToObs || !canSimulateKeyPresses) {
std::thread t([keys, dur]() { InjectKeys(keys, dur); });
t.detach();
@@ -342,35 +233,18 @@ void MacroActionHotkey::SendCustomHotkey()
t.detach();
}
}
}
bool MacroActionHotkey::PerformAction()
{
switch (_action) {
case advss::MacroActionHotkey::Action::OBS_HOTKEY:
SendOBSHotkey();
break;
case advss::MacroActionHotkey::Action::CUSTOM:
SendCustomHotkey();
break;
default:
break;
}
return true;
}
void MacroActionHotkey::LogAction() const
{
vblog(LOG_INFO, "sent hotkey type %d", static_cast<int>(_action));
vblog(LOG_INFO, "sent hotkey");
}
bool MacroActionHotkey::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
obs_data_set_int(obj, "action", static_cast<int>(_action));
obs_data_set_int(obj, "hotkeyType", _hotkeyType);
obs_data_set_string(obj, "hotkeyName", _hotkeyName.c_str());
obs_data_set_int(obj, "key", static_cast<int>(_key));
obs_data_set_bool(obj, "left_shift", _leftShift);
obs_data_set_bool(obj, "right_shift", _rightShift);
@@ -380,24 +254,14 @@ 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", 2);
return true;
}
bool MacroActionHotkey::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
int version = obs_data_get_int(obj, "version");
if (version != 2) {
_action = Action::CUSTOM;
} else {
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
}
_hotkeyType = static_cast<obs_hotkey_registerer_type>(
obs_data_get_int(obj, "hotkeyType"));
_hotkeyName = obs_data_get_string(obj, "hotkeyName");
_key = static_cast<HotkeyType>(obs_data_get_int(obj, "key"));
_leftShift = obs_data_get_bool(obj, "left_shift");
_rightShift = obs_data_get_bool(obj, "right_shift");
@@ -407,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 (version == 0) {
_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;
}
@@ -526,100 +386,36 @@ static inline void populateKeySelection(QComboBox *list)
list->addItem("NumpadEnter");
}
static void populateActionSelection(QComboBox *list)
{
for (const auto &[_, value] : actionTypes) {
list->addItem(obs_module_text(value.c_str()));
}
}
static void populateHotkeyTypeSelection(QComboBox *list)
{
for (const auto &[_, value] : hotkeyTypes) {
list->addItem(obs_module_text(value.c_str()));
}
}
static void addNamePrefix(QString &name, obs_hotkey_t *hotkey)
{
auto temp = name.toStdString();
addNamePrefix(temp, hotkey);
name = QString::fromStdString(temp);
}
static void populateHotkeyNames(QComboBox *list,
obs_hotkey_registerer_type type)
{
struct Parameters {
QStringList names;
QStringList descriptions;
obs_hotkey_registerer_type type;
} params;
auto func = [](void *param, obs_hotkey_id, obs_hotkey_t *hotkey) {
auto params = static_cast<Parameters *>(param);
if (obs_hotkey_get_registerer_type(hotkey) == params->type) {
QString description(obs_hotkey_get_description(hotkey));
addNamePrefix(description, hotkey);
params->descriptions.append(description);
QString name(obs_hotkey_get_name(hotkey));
addNamePrefix(name, hotkey);
params->names.append(name);
}
return true;
};
params.type = type;
obs_enum_hotkeys(func, &params);
list->clear();
for (int i = 0; i < params.names.size(); i++) {
list->addItem(params.descriptions.at(i), params.names.at(i));
}
AddSelectionEntry(list,
obs_module_text("AdvSceneSwitcher.selectHotkey"));
}
MacroActionHotkeyEdit::MacroActionHotkeyEdit(
QWidget *parent, std::shared_ptr<MacroActionHotkey> entryData)
: QWidget(parent),
_actionType(new QComboBox()),
_hotkeyType(new QComboBox()),
_obsHotkeys(new QComboBox()),
_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"))),
_entryLayout(new QHBoxLayout()),
_keyConfigLayout(new QHBoxLayout())
: QWidget(parent)
{
populateKeySelection(_keys);
populateActionSelection(_actionType);
populateHotkeyTypeSelection(_hotkeyType);
_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(_actionType, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionChanged(int)));
QWidget::connect(_hotkeyType, SIGNAL(currentIndexChanged(int)), this,
SLOT(HotkeyTypeChanged(int)));
QWidget::connect(_obsHotkeys, SIGNAL(currentIndexChanged(int)), this,
SLOT(OBSHotkeyChanged(int)));
QWidget::connect(_keys, SIGNAL(currentIndexChanged(int)), this,
SLOT(KeyChanged(int)));
QWidget::connect(_leftShift, SIGNAL(stateChanged(int)), this,
@@ -638,26 +434,33 @@ 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)));
_entryLayout->setContentsMargins(0, 0, 0, 0);
_keyConfigLayout->setContentsMargins(0, 0, 0, 0);
_keyConfigLayout->addWidget(_leftShift);
_keyConfigLayout->addWidget(_rightShift);
_keyConfigLayout->addWidget(_leftCtrl);
_keyConfigLayout->addWidget(_rightCtrl);
_keyConfigLayout->addWidget(_leftAlt);
_keyConfigLayout->addWidget(_rightAlt);
_keyConfigLayout->addWidget(_leftMeta);
_keyConfigLayout->addWidget(_rightMeta);
_keyConfigLayout->addStretch();
QHBoxLayout *line1Layout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{keys}}", _keys},
{"{{duration}}", _duration},
};
placeWidgets(obs_module_text("AdvSceneSwitcher.action.hotkey.entry"),
line1Layout, widgetPlaceholders);
auto mainLayout = new QVBoxLayout;
mainLayout->addLayout(_entryLayout);
mainLayout->addLayout(_keyConfigLayout);
QHBoxLayout *line2Layout = new QHBoxLayout;
line2Layout->addWidget(_leftShift);
line2Layout->addWidget(_rightShift);
line2Layout->addWidget(_leftCtrl);
line2Layout->addWidget(_rightCtrl);
line2Layout->addWidget(_leftAlt);
line2Layout->addWidget(_rightAlt);
line2Layout->addWidget(_leftMeta);
line2Layout->addWidget(_rightMeta);
line2Layout->addStretch();
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(line1Layout);
mainLayout->addLayout(line2Layout);
mainLayout->addWidget(_onlySendToOBS);
mainLayout->addWidget(_noKeyPressSimulationWarning);
setLayout(mainLayout);
@@ -669,76 +472,10 @@ MacroActionHotkeyEdit::MacroActionHotkeyEdit(
_loading = false;
}
void MacroActionHotkeyEdit::RepopulateOBSHotkeySelection()
void MacroActionHotkeyEdit::SetWarningVisibility()
{
populateHotkeyNames(_obsHotkeys, _entryData->_hotkeyType);
}
void MacroActionHotkeyEdit::SetWidgetVisibility()
{
_entryLayout->removeWidget(_actionType);
_entryLayout->removeWidget(_hotkeyType);
_entryLayout->removeWidget(_obsHotkeys);
_entryLayout->removeWidget(_keys);
_entryLayout->removeWidget(_duration);
ClearLayout(_entryLayout);
PlaceWidgets(
obs_module_text(
_entryData->_action ==
MacroActionHotkey::Action::OBS_HOTKEY
? "AdvSceneSwitcher.action.hotkey.entry.obs"
: "AdvSceneSwitcher.action.hotkey.entry.custom"),
_entryLayout,
{
{"{{actionType}}", _actionType},
{"{{hotkeyType}}", _hotkeyType},
{"{{obsHotkeys}}", _obsHotkeys},
{"{{keys}}", _keys},
{"{{duration}}", _duration},
});
_noKeyPressSimulationWarning->setVisible(!_entryData->_onlySendToObs &&
!canSimulateKeyPresses);
SetLayoutVisible(_keyConfigLayout,
_entryData->_action ==
MacroActionHotkey::Action::CUSTOM);
_duration->setVisible(_entryData->_action ==
MacroActionHotkey::Action::CUSTOM);
_keys->setVisible(_entryData->_action ==
MacroActionHotkey::Action::CUSTOM);
_onlySendToOBS->setVisible(_entryData->_action ==
MacroActionHotkey::Action::CUSTOM);
_hotkeyType->setVisible(_entryData->_action ==
MacroActionHotkey::Action::OBS_HOTKEY);
_obsHotkeys->setVisible(_entryData->_action ==
MacroActionHotkey::Action::OBS_HOTKEY);
adjustSize();
updateGeometry();
}
static QString getHotkeyDescriptionByName(const std::string &name)
{
struct Parameters {
std::string name;
QString description = "";
} params;
auto func = [](void *param, obs_hotkey_id id, obs_hotkey_t *hotkey) {
auto params = static_cast<Parameters *>(param);
std::string name = obs_hotkey_get_name(hotkey);
addNamePrefix(name, hotkey);
if (name == params->name) {
params->description =
obs_hotkey_get_description(hotkey);
addNamePrefix(params->description, hotkey);
return false;
}
return true;
};
params.name = name;
obs_enum_hotkeys(func, &params);
return params.description;
}
void MacroActionHotkeyEdit::UpdateEntryData()
@@ -747,11 +484,6 @@ void MacroActionHotkeyEdit::UpdateEntryData()
return;
}
_actionType->setCurrentIndex(static_cast<int>(_entryData->_action));
_hotkeyType->setCurrentIndex(static_cast<int>(_entryData->_hotkeyType));
RepopulateOBSHotkeySelection();
_obsHotkeys->setCurrentText(
getHotkeyDescriptionByName(_entryData->_hotkeyName));
_keys->setCurrentIndex(static_cast<int>(_entryData->_key));
_leftShift->setChecked(_entryData->_leftShift);
_rightShift->setChecked(_entryData->_rightShift);
@@ -761,10 +493,10 @@ 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);
SetWidgetVisibility();
SetWarningVisibility();
}
void MacroActionHotkeyEdit::LShiftChanged(int state)
@@ -773,7 +505,7 @@ void MacroActionHotkeyEdit::LShiftChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_leftShift = state;
}
@@ -783,7 +515,7 @@ void MacroActionHotkeyEdit::RShiftChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_rightShift = state;
}
@@ -793,7 +525,7 @@ void MacroActionHotkeyEdit::LCtrlChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_leftCtrl = state;
}
@@ -803,7 +535,7 @@ void MacroActionHotkeyEdit::RCtrlChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_rightCtrl = state;
}
@@ -813,7 +545,7 @@ void MacroActionHotkeyEdit::LAltChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_leftAlt = state;
}
@@ -823,7 +555,7 @@ void MacroActionHotkeyEdit::RAltChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_rightAlt = state;
}
@@ -833,7 +565,7 @@ void MacroActionHotkeyEdit::LMetaChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_leftMeta = state;
}
@@ -843,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)
@@ -863,9 +595,9 @@ void MacroActionHotkeyEdit::OnlySendToOBSChanged(int state)
return;
}
auto lock = LockContext();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_onlySendToObs = state;
SetWidgetVisibility();
SetWarningVisibility();
}
void MacroActionHotkeyEdit::KeyChanged(int key)
@@ -874,47 +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);
}
void MacroActionHotkeyEdit::ActionChanged(int value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_action = static_cast<MacroActionHotkey::Action>(value);
SetWidgetVisibility();
}
void MacroActionHotkeyEdit::HotkeyTypeChanged(int value)
{
if (_loading || !_entryData) {
return;
}
{
auto lock = LockContext();
_entryData->_hotkeyType =
static_cast<obs_hotkey_registerer_type>(value);
}
RepopulateOBSHotkeySelection();
}
void MacroActionHotkeyEdit::OBSHotkeyChanged(int idx)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
if (idx == -1) {
_entryData->_hotkeyName = "";
return;
}
_entryData->_hotkeyName =
_obsHotkeys->itemData(idx).toString().toStdString();
}
} // 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) {}
@@ -23,15 +20,7 @@ public:
return std::make_shared<MacroActionHotkey>(m);
}
enum class Action {
OBS_HOTKEY,
CUSTOM,
};
Action _action = Action::OBS_HOTKEY;
obs_hotkey_registerer_type _hotkeyType = OBS_HOTKEY_REGISTERER_FRONTEND;
std::string _hotkeyName;
OBSWeakSource _HotkeySource;
HotkeyType _key = HotkeyType::Key_NoKey;
bool _leftShift = false;
bool _rightShift = false;
@@ -41,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
@@ -49,9 +38,6 @@ public:
#endif
private:
void SendOBSHotkey();
void SendCustomHotkey();
static bool _registered;
static const std::string id;
};
@@ -73,9 +59,6 @@ public:
}
private slots:
void ActionChanged(int key);
void HotkeyTypeChanged(int key);
void OBSHotkeyChanged(int);
void KeyChanged(int key);
void LShiftChanged(int state);
void RShiftChanged(int state);
@@ -85,13 +68,10 @@ 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:
QComboBox *_actionType;
QComboBox *_hotkeyType;
QComboBox *_obsHotkeys;
QComboBox *_keys;
QCheckBox *_leftShift;
QCheckBox *_rightShift;
@@ -101,19 +81,14 @@ protected:
QCheckBox *_rightAlt;
QCheckBox *_leftMeta;
QCheckBox *_rightMeta;
DurationSelection *_duration;
QSpinBox *_duration;
QCheckBox *_onlySendToOBS;
QLabel *_noKeyPressSimulationWarning;
std::shared_ptr<MacroActionHotkey> _entryData;
private:
void RepopulateOBSHotkeySelection();
void SetWidgetVisibility();
QHBoxLayout *_entryLayout;
QHBoxLayout *_keyConfigLayout;
void SetWarningVisibility();
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,19 +122,12 @@ 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);
_headerList->SetMaxStringSize(4096);
QWidget::connect(_url, SIGNAL(editingFinished()), this,
SLOT(URLChanged()));
@@ -164,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},
@@ -179,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);
@@ -210,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();
@@ -225,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()));
}
@@ -236,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();
@@ -289,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(
@@ -11,68 +9,39 @@ bool MacroActionMacro::_registered = MacroActionFactory::Register(
{MacroActionMacro::Create, MacroActionMacroEdit::Create,
"AdvSceneSwitcher.action.macro"});
const static std::map<MacroActionMacro::Action, std::string> actionTypes = {
{MacroActionMacro::Action::PAUSE,
"AdvSceneSwitcher.action.macro.type.pause"},
{MacroActionMacro::Action::UNPAUSE,
const static std::map<PerformMacroAction, std::string> actionTypes = {
{PerformMacroAction::PAUSE, "AdvSceneSwitcher.action.macro.type.pause"},
{PerformMacroAction::UNPAUSE,
"AdvSceneSwitcher.action.macro.type.unpause"},
{MacroActionMacro::Action::RESET_COUNTER,
{PerformMacroAction::RESET_COUNTER,
"AdvSceneSwitcher.action.macro.type.resetCounter"},
{MacroActionMacro::Action::RUN,
"AdvSceneSwitcher.action.macro.type.run"},
{MacroActionMacro::Action::STOP,
"AdvSceneSwitcher.action.macro.type.stop"},
{MacroActionMacro::Action::DISABLE_ACTION,
"AdvSceneSwitcher.action.macro.type.disableAction"},
{MacroActionMacro::Action::ENABLE_ACTION,
"AdvSceneSwitcher.action.macro.type.enableAction"},
{MacroActionMacro::Action::TOGGLE_ACTION,
"AdvSceneSwitcher.action.macro.type.toggleAction"},
{PerformMacroAction::RUN, "AdvSceneSwitcher.action.macro.type.run"},
{PerformMacroAction::STOP, "AdvSceneSwitcher.action.macro.type.stop"},
};
bool MacroActionMacro::PerformAction()
{
auto macro = _macro.GetMacro();
if (!macro) {
if (!_macro.get()) {
return true;
}
switch (_action) {
case Action::PAUSE:
macro->SetPaused();
case PerformMacroAction::PAUSE:
_macro->SetPaused();
break;
case Action::UNPAUSE:
macro->SetPaused(false);
case PerformMacroAction::UNPAUSE:
_macro->SetPaused(false);
break;
case Action::RESET_COUNTER:
macro->ResetRunCount();
case PerformMacroAction::RESET_COUNTER:
_macro->ResetRunCount();
break;
case Action::RUN:
if (!macro->Paused()) {
macro->PerformActions();
case PerformMacroAction::RUN:
if (!_macro->Paused()) {
_macro->PerformActions();
}
break;
case Action::STOP:
macro->Stop();
break;
case Action::DISABLE_ACTION:
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
false)) {
macro->Actions().at(_actionIndex - 1)->SetEnabled(false);
}
break;
case Action::ENABLE_ACTION:
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
false)) {
macro->Actions().at(_actionIndex - 1)->SetEnabled(true);
}
break;
case Action::TOGGLE_ACTION:
if (IsValidMacroSegmentIndex(macro.get(), _actionIndex - 1,
false)) {
auto action = macro->Actions().at(_actionIndex - 1);
action->SetEnabled(!action->Enabled());
}
case PerformMacroAction::STOP:
_macro->Stop();
break;
default:
break;
@@ -82,39 +51,26 @@ bool MacroActionMacro::PerformAction()
void MacroActionMacro::LogAction() const
{
auto macro = _macro.GetMacro();
if (!macro) {
if (!_macro.get()) {
return;
}
switch (_action) {
case Action::PAUSE:
vblog(LOG_INFO, "paused \"%s\"", macro->Name().c_str());
case PerformMacroAction::PAUSE:
vblog(LOG_INFO, "paused \"%s\"", _macro->Name().c_str());
break;
case Action::UNPAUSE:
vblog(LOG_INFO, "unpaused \"%s\"", macro->Name().c_str());
case PerformMacroAction::UNPAUSE:
vblog(LOG_INFO, "unpaused \"%s\"", _macro->Name().c_str());
break;
case Action::RESET_COUNTER:
case PerformMacroAction::RESET_COUNTER:
vblog(LOG_INFO, "reset counter for \"%s\"",
macro->Name().c_str());
_macro->Name().c_str());
break;
case Action::RUN:
case PerformMacroAction::RUN:
vblog(LOG_INFO, "run nested macro \"%s\"",
macro->Name().c_str());
_macro->Name().c_str());
break;
case Action::STOP:
vblog(LOG_INFO, "stopped macro \"%s\"", macro->Name().c_str());
break;
case Action::DISABLE_ACTION:
vblog(LOG_INFO, "disabled action %d of macro \"%s\"",
_actionIndex.GetValue(), macro->Name().c_str());
break;
case Action::ENABLE_ACTION:
vblog(LOG_INFO, "enabled action %d of macro \"%s\"",
_actionIndex.GetValue(), macro->Name().c_str());
break;
case Action::TOGGLE_ACTION:
vblog(LOG_INFO, "toggled action %d of macro \"%s\"",
_actionIndex.GetValue(), macro->Name().c_str());
case PerformMacroAction::STOP:
vblog(LOG_INFO, "stopped macro \"%s\"", _macro->Name().c_str());
break;
default:
break;
@@ -125,7 +81,6 @@ bool MacroActionMacro::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
_macro.Save(obj);
_actionIndex.Save(obj, "actionIndex");
obs_data_set_int(obj, "action", static_cast<int>(_action));
return true;
}
@@ -134,15 +89,17 @@ bool MacroActionMacro::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_macro.Load(obj);
_actionIndex.Load(obj, "actionIndex");
_action = static_cast<MacroActionMacro::Action>(
_action = static_cast<PerformMacroAction>(
obs_data_get_int(obj, "action"));
return true;
}
std::string MacroActionMacro::GetShortDesc() const
{
return _macro.Name();
if (_macro.get()) {
return _macro->Name();
}
return "";
}
static inline void populateActionSelection(QComboBox *list)
@@ -154,28 +111,27 @@ static inline void populateActionSelection(QComboBox *list)
MacroActionMacroEdit::MacroActionMacroEdit(
QWidget *parent, std::shared_ptr<MacroActionMacro> entryData)
: QWidget(parent),
_macros(new MacroSelection(parent)),
_actionIndex(new MacroSegmentSelection(
this, MacroSegmentSelection::Type::ACTION)),
_actions(new QComboBox())
: QWidget(parent)
{
_macros = new MacroSelection(parent);
_actions = new QComboBox();
populateActionSelection(_actions);
QWidget::connect(_macros, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(MacroChanged(const QString &)));
QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this,
SLOT(MacroRemove(const QString &)));
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ActionChanged(int)));
QWidget::connect(_actionIndex,
SIGNAL(SelectionChanged(const IntVariable &)), this,
SLOT(ActionIndexChanged(const IntVariable &)));
auto mainLayout = new QHBoxLayout;
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.macro.entry"),
mainLayout,
{{"{{actions}}", _actions},
{"{{actionIndex}}", _actionIndex},
{"{{macros}}", _macros}});
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{actions}}", _actions},
{"{{macros}}", _macros},
};
placeWidgets(obs_module_text("AdvSceneSwitcher.action.macro.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
_entryData = entryData;
@@ -189,10 +145,11 @@ void MacroActionMacroEdit::UpdateEntryData()
return;
}
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
_actionIndex->SetValue(_entryData->_actionIndex);
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
_macros->SetCurrentMacro(_entryData->_macro);
SetWidgetVisibility();
_macros->SetCurrentMacro(_entryData->_macro.get());
if (_entryData->_action == PerformMacroAction::RUN ||
_entryData->_action == PerformMacroAction::STOP) {
_macros->HideSelectedMacro();
}
}
void MacroActionMacroEdit::MacroChanged(const QString &text)
@@ -201,9 +158,8 @@ void MacroActionMacroEdit::MacroChanged(const QString &text)
return;
}
auto lock = LockContext();
_entryData->_macro = text;
_actionIndex->SetMacro(_entryData->_macro.GetMacro());
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_macro.UpdateRef(text);
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
@@ -214,37 +170,20 @@ void MacroActionMacroEdit::ActionChanged(int value)
return;
}
auto lock = LockContext();
_entryData->_action = static_cast<MacroActionMacro::Action>(value);
SetWidgetVisibility();
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_action = static_cast<PerformMacroAction>(value);
void MacroActionMacroEdit::ActionIndexChanged(const IntVariable &value)
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_actionIndex = value;
}
void MacroActionMacroEdit::SetWidgetVisibility()
{
if (_entryData->_action == MacroActionMacro::Action::RUN ||
_entryData->_action == MacroActionMacro::Action::STOP) {
if (_entryData->_action == PerformMacroAction::RUN ||
_entryData->_action == PerformMacroAction::STOP) {
_macros->HideSelectedMacro();
} else {
_macros->ShowAllMacros();
}
const bool isModifyingActionState =
_entryData->_action ==
MacroActionMacro::Action::DISABLE_ACTION ||
_entryData->_action ==
MacroActionMacro::Action::ENABLE_ACTION ||
_entryData->_action == MacroActionMacro::Action::TOGGLE_ACTION;
_actionIndex->setVisible(isModifyingActionState);
}
} // namespace advss
void MacroActionMacroEdit::MacroRemove(const QString &)
{
if (_entryData) {
_entryData->_macro.UpdateRef();
}
}

View File

@@ -1,11 +1,16 @@
#pragma once
#include "macro-action-edit.hpp"
#include "macro-selection.hpp"
#include "macro-segment-selection.hpp"
#include <QHBoxLayout>
namespace advss {
enum class PerformMacroAction {
PAUSE,
UNPAUSE,
RESET_COUNTER,
RUN,
STOP,
};
class MacroActionMacro : public MacroRefAction {
public:
@@ -21,18 +26,7 @@ public:
return std::make_shared<MacroActionMacro>(m);
}
enum class Action {
PAUSE,
UNPAUSE,
RESET_COUNTER,
RUN,
STOP,
DISABLE_ACTION,
ENABLE_ACTION,
TOGGLE_ACTION,
};
Action _action = Action::PAUSE;
IntVariable _actionIndex = 1;
PerformMacroAction _action = PerformMacroAction::PAUSE;
private:
static bool _registered;
@@ -57,21 +51,17 @@ public:
private slots:
void MacroChanged(const QString &text);
void MacroRemove(const QString &name);
void ActionChanged(int value);
void ActionIndexChanged(const IntVariable &value);
signals:
void HeaderInfoChanged(const QString &);
protected:
MacroSelection *_macros;
MacroSegmentSelection *_actionIndex;
QComboBox *_actions;
std::shared_ptr<MacroActionMacro> _entryData;
private:
void SetWidgetVisibility();
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

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