I18n Support (#72)

* adapt UI for i18n

* add placeWidgets() helper function to ease translation

* add hint about Transition Matrix plugin on Transition tab

* translate

* rework UI of file tab

* write status of plugin to scene info file
This commit is contained in:
shugen002
2020-12-21 18:24:04 +08:00
committed by GitHub
parent 07b95cb8ae
commit 8ba78b12c1
32 changed files with 1340 additions and 873 deletions

View File

@@ -182,6 +182,7 @@ jobs:
echo "FILE_NAME=${FILE_NAME}" >> $GITHUB_ENV
mkdir -p ./${{ env.PLUGIN_NAME }}/bin/64bit/
mv ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.LIB_NAME }}.so ./${{ env.PLUGIN_NAME }}/bin/64bit/${{ env.LIB_NAME }}.so
mv ./UI/frontend-plugins/${{ env.PLUGIN_NAME }}/data ./${{ env.PLUGIN_NAME }}/data
tar -cvzf "${FILE_NAME}" ${{ env.PLUGIN_NAME }}
- name: 'Publish'
uses: actions/upload-artifact@v2.2.1
@@ -235,6 +236,7 @@ jobs:
$env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-win64.zip"
echo "FILE_NAME=${env:FILE_NAME}" >> ${env:GITHUB_ENV}
robocopy .\build64\rundir\RelWithDebInfo\obs-plugins\64bit\ .\build\obs-plugins\64bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
robocopy .\build64\rundir\RelWithDebInfo\data\obs-plugins\${{ env.LIB_NAME }}\ .\build\data\obs-plugins\${{ env.LIB_NAME }}\ /E /XF .gitignore
7z a ${env:FILE_NAME} .\build\*
- name: Publish
if: success()
@@ -289,6 +291,7 @@ jobs:
$env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-win32.zip"
echo "FILE_NAME=${env:FILE_NAME}" >> ${env:GITHUB_ENV}
robocopy .\build32\rundir\RelWithDebInfo\obs-plugins\32bit\ .\build\obs-plugins\32bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
robocopy .\build32\rundir\RelWithDebInfo\data\obs-plugins\${{ env.LIB_NAME }}\ .\build\data\obs-plugins\${{ env.LIB_NAME }}\ /E /XF .gitignore
7z a ${env:FILE_NAME} .\build\*
- name: Publish
if: success()

View File

@@ -60,6 +60,22 @@
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../data</string>
<key>PATH_TYPE</key>
<integer>1</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
</array>
<key>GID</key>
<integer>80</integer>

View File

@@ -275,5 +275,5 @@ else ()
Qt5::Widgets
libobs)
install_obs_plugin(advanced-scene-switcher data)
install_obs_plugin_with_data(advanced-scene-switcher data)
endif()

205
data/locale/en-US.ini Normal file
View File

@@ -0,0 +1,205 @@
AdvSceneSwitcher.pluginName="Advanced Scene Switcher"
AdvSceneSwitcher.windowTitle="Advanced Scene Switcher"
; General Tab
AdvSceneSwitcher.generalTab.title="General"
AdvSceneSwitcher.generalTab.status="Status"
AdvSceneSwitcher.generalTab.status.hotkeytips="Hotkeys can be defined in the OBS settings"
AdvSceneSwitcher.generalTab.status.currentStatus="Advanced Scene Switcher is:"
AdvSceneSwitcher.generalTab.status.onStartup="On startup:"
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="Start the scene switcher if it was running"
AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="Always start the scene switcher"
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="Do not start the scene switcher"
AdvSceneSwitcher.generalTab.status.start="Start"
AdvSceneSwitcher.generalTab.status.stop="Stop"
AdvSceneSwitcher.generalTab.status.checkInterval="Check switch conditions every"
AdvSceneSwitcher.generalTab.generalBehavior="General behavior"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recording="Recording"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.streaming="Streaming"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recordingAndStreaming="Recording and Streaming"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart1="Automatically start"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart2="on scene"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="If no switch condition is met for"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="Will only ever be as accurate as the configured check interval."
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="Don't switch"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="Switch to any scene in Random tab"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="Switch to:"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Enable verbose logging"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStop="Automatically stop streaming/recording on scene"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Disable UI hints"
AdvSceneSwitcher.generalTab.priority="Priority"
AdvSceneSwitcher.generalTab.priority.description="Switching methods priority (Highest priority is at the top)"
AdvSceneSwitcher.generalTab.priority.threadPriority="Use thread priority"
AdvSceneSwitcher.generalTab.priority.threadPriorityNotice="(Raising the priority above \"Normal\" is not recommended)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings="Save / load settings"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="Export"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="Import"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="Export Advanced Scene Switcher settings to file ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="Import Advanced Scene Switcher settings from file ..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="Text files (*.txt)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="Advanced Scene Switcher failed to import settings"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="Advanced Scene Switcher settings imported successfully"
AdvSceneSwitcher.generalTab.priority.fileContent="File Content"
AdvSceneSwitcher.generalTab.priority.sceneSequence="Scene Sequence"
AdvSceneSwitcher.generalTab.priority.idleDetection="Idle Detection"
AdvSceneSwitcher.generalTab.priority.executable="Executable"
AdvSceneSwitcher.generalTab.priority.screenRegion="Screen Region"
AdvSceneSwitcher.generalTab.priority.windowTitle="Window Title"
AdvSceneSwitcher.generalTab.priority.media="Media"
AdvSceneSwitcher.generalTab.priority.time="Time"
AdvSceneSwitcher.generalTab.priority.audio="Audio"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="Transition"
AdvSceneSwitcher.transitionTab.transitionOverride="Scene transitions defined in the scene switcher take priority over Transition Overrides defined per scene"
AdvSceneSwitcher.transitionTab.transitionForAToB="Use transition for automated scene switch from scene A to scene B"
AdvSceneSwitcher.transitionTab.transitionForAToB.description="<html><head/><body><p>These settings <span style=\"font-style:italic;\">only</span> affect transitions caused by the scene switcher - Check out <a href=\"https://obsproject.com/forum/resources/obs-transition-matrix.751/\"><span style=\" text-decoration: underline; color:#268bd2;\">Transition Matrix</span></a> if you want to configure this for manual scene changes.<br/>Settings defined here take priority over transition settings configured elsewhere in the scene switcher.</p></body></html>"
AdvSceneSwitcher.transitionTab.defaultTransition="Change transition if scene is active"
AdvSceneSwitcher.transitionTab.entry="Switch from {{scenes}} to {{scenes2}} using {{transitions}}"
AdvSceneSwitcher.transitionTab.defaultTransitionEntry="When scene {{scenes}} is active change default scene transition to {{transitions}}"
; Pause Scenes Tab
AdvSceneSwitcher.pauseScenesTab.title="Pause"
AdvSceneSwitcher.pauseScenesTab.pauseOnScene="Pause the Scene Switcher on scene"
AdvSceneSwitcher.pauseScenesTab.pauseInFocus1="Pause the Scene Switcher when "
AdvSceneSwitcher.pauseScenesTab.pauseInFocus2="is in focus"
; Window Title Tab
AdvSceneSwitcher.windowTitleTab.title="Title"
AdvSceneSwitcher.windowTitleTab.regexrDescription="<html><head/><body><p>Enter either direct window titles or valid regex. You can check syntax and matches for regular expressions using <a href=\"https://regexr.com\"><span style=\" text-decoration: underline; color:#268bd2;\">RegExr</span></a></p></body></html>"
AdvSceneSwitcher.windowTitleTab.stayInFocus1="Stay on the currently selected scene when "
AdvSceneSwitcher.windowTitleTab.stayInFocus2="is focused"
AdvSceneSwitcher.windowTitleTab.fullscreen="if fullscreen"
AdvSceneSwitcher.windowTitleTab.maximized="if maximized"
AdvSceneSwitcher.windowTitleTab.focused="if focused"
AdvSceneSwitcher.windowTitleTab.entry="{{windows}} {{scenes}} {{transitions}} {{fullscreen}} {{maximized}} {{focused}}"
; Executable Tab
AdvSceneSwitcher.executableTab.title="Executable"
AdvSceneSwitcher.executableTab.implemented="Implemented by dasOven"
AdvSceneSwitcher.executableTab.requiresFocus="only if focused"
AdvSceneSwitcher.executableTab.entry="When {{processes}} is running switch to {{scenes}} using {{transitions}} {{requiresFocus}}"
; Screen Region Tab
AdvSceneSwitcher.screenRegionTab.title="Region"
AdvSceneSwitcher.screenRegionTab.currentPosition="Cursor is currently at:"
AdvSceneSwitcher.screenRegionTab.showGuideFrames="Show guide frames"
AdvSceneSwitcher.screenRegionTab.hideGuideFrames="Hide guide frames"
AdvSceneSwitcher.screenRegionTab.entry="If cursor is in {{minX}} {{minY}} x {{maxX}} {{maxY}} switch to {{scenes}} using {{transitions}}"
; Media Tab
AdvSceneSwitcher.mediaTab.title="Media"
AdvSceneSwitcher.mediaTab.implemented="Implemented by Exeldro"
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.stopped="Stopped"
AdvSceneSwitcher.mediaTab.states.ended="Ended"
AdvSceneSwitcher.mediaTab.states.error="Error"
AdvSceneSwitcher.mediaTab.states.playedToEnd="Played to end"
AdvSceneSwitcher.mediaTab.states.any="Any"
AdvSceneSwitcher.mediaTab.timeRestriction.none="None"
AdvSceneSwitcher.mediaTab.timeRestriction.shorter="Time shorter"
AdvSceneSwitcher.mediaTab.timeRestriction.longer="Time longer"
AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter="Time remaining shorter"
AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger="Time remaining longer"
AdvSceneSwitcher.mediaTab.entry="When {{meidaSources}} state is {{states}} and {{timeRestrictions}} {{time}} switch to {{scenes}} using {{transitions}}"
; File Tab
AdvSceneSwitcher.fileTab.title="File"
AdvSceneSwitcher.fileTab.readWriteSceneFile="Read / write scene to / from file"
AdvSceneSwitcher.fileTab.currentSceneOutputFile="Write the name of the current scene to this file:"
AdvSceneSwitcher.fileTab.switchSceneBaseOnFile="Enable switching of scenes based on file input"
AdvSceneSwitcher.fileTab.switchSceneNameInputFile="Read scene name to be switched to from this file:"
AdvSceneSwitcher.fileTab.switchSceneBaseOnFileContent="Switch scene based on file contents"
AdvSceneSwitcher.fileTab.remoteFileWarning="Please note that if you choose the remote option the scene switcher will try to access the remote location every x ms as specified on the General tab!"
AdvSceneSwitcher.fileTab.remoteFileWarning1="Note that the scene switcher will try to access the remote location every "
AdvSceneSwitcher.fileTab.remoteFileWarning2="ms"
AdvSceneSwitcher.fileTab.libcurlWarning="Failed to load libcurl! Accesssing remote files will not be possible!"
AdvSceneSwitcher.fileTab.selectWrite="Select a file to write to ..."
AdvSceneSwitcher.fileTab.selectRead="Select a file to read from ..."
AdvSceneSwitcher.fileTab.textFileType="Text files (*.txt)"
AdvSceneSwitcher.fileTab.anyFileType="Any files (*.*)"
AdvSceneSwitcher.fileTab.remote="remote file"
AdvSceneSwitcher.fileTab.local="local file"
AdvSceneSwitcher.fileTab.useRegExp="use regular expressions (pattern matching)"
AdvSceneSwitcher.fileTab.checkfileContentTime="if modification date changed"
AdvSceneSwitcher.fileTab.checkfileContent="if content changed"
AdvSceneSwitcher.fileTab.entry="Switch to {{scenes}} using {{transitions}} if content of {{fileType}} {{filePath}} {{browseButton}} matches:"
AdvSceneSwitcher.fileTab.entry2="{{matchText}}"
AdvSceneSwitcher.fileTab.entry3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
; Random Tab
AdvSceneSwitcher.randomTab.title="Random"
AdvSceneSwitcher.randomTab.randomDisabledWarning="Functionality disabled - To activate select \"If no switch condition is met switch to any scene in Random tab\" on General tab"
AdvSceneSwitcher.randomTab.entry="If no switch condition is met switch to {{scenes}} using {{transitions}} for {{delay}}"
; Time Tab
AdvSceneSwitcher.timeTab.title="Time"
AdvSceneSwitcher.timeTab.anyDay="On any day"
AdvSceneSwitcher.timeTab.mondays="Mondays"
AdvSceneSwitcher.timeTab.tuesdays="Tuesdays"
AdvSceneSwitcher.timeTab.wednesdays="Wednesdays"
AdvSceneSwitcher.timeTab.thursdays="Thursdays"
AdvSceneSwitcher.timeTab.fridays="Fridays"
AdvSceneSwitcher.timeTab.saturdays="Saturdays"
AdvSceneSwitcher.timeTab.sundays="Sundays"
AdvSceneSwitcher.timeTab.afterstart="Atfer streaming/recording start"
AdvSceneSwitcher.timeTab.afterstart.tip="The time relative to the start of streaming / recording will be used"
AdvSceneSwitcher.timeTab.entry="{{triggers}} at {{time}} switch to {{scenes}} using {{transitions}}"
; Idle Tab
AdvSceneSwitcher.idleTab.title="Idle"
AdvSceneSwitcher.idleTab.enable="Enable Idle Detection"
AdvSceneSwitcher.idleTab.condition1="After "
AdvSceneSwitcher.idleTab.condition2="of no keyboard or mouse inputs "
AdvSceneSwitcher.idleTab.switchToScene="switch to scene"
AdvSceneSwitcher.idleTab.usingTransition1="using the"
AdvSceneSwitcher.idleTab.usingTransition2="transition"
AdvSceneSwitcher.idleTab.dontSwitchIfFocus1="Do not switch if"
AdvSceneSwitcher.idleTab.dontSwitchIfFocus2="is in focus"
; Scene Sequence Tab
AdvSceneSwitcher.sceneSequenceTab.title="Sequence"
AdvSceneSwitcher.sceneSequenceTab.description="A sequence of automatic scene switches can be cancelled by either pausing/stopping the scene switcher or manually switching to a different scene"
AdvSceneSwitcher.sceneSequenceTab.save="Save Round Trips to file"
AdvSceneSwitcher.sceneSequenceTab.load="Load Round Trips from file"
AdvSceneSwitcher.sceneSequenceTab.saveTitle="Save Scene Sequence to file ..."
AdvSceneSwitcher.sceneSequenceTab.loadTitle="Select a file to read Scene Sequence from ..."
AdvSceneSwitcher.sceneSequenceTab.loadFail="Advanced Scene Switcher failed to import settings!"
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="Advanced Scene Switcher settings imported successfully!"
AdvSceneSwitcher.sceneSequenceTab.fileType="Text files (*.txt)"
AdvSceneSwitcher.sceneSequenceTab.entry="When {{startScenes}} is active switch to {{scenes}} after {{delay}} {{delayUnits}} using {{transitions}}"
; Audio Tab
AdvSceneSwitcher.audioTab.title="Audio"
AdvSceneSwitcher.audioTab.entry="When the volume of {{audioSources}} is above {{volumeWidget}} switch to {{scenes}} using {{transitions}}"
; Hotkey
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher"
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="Stop the Advanced Scene Switcher"
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Toggle Start/Stop for the Advanced Scene Switcher"
AdvSceneSwitcher.close="Close"
AdvSceneSwitcher.browse="Browse"
AdvSceneSwitcher.selectScene="--select scene--"
AdvSceneSwitcher.selectTransition="--select transition--"
AdvSceneSwitcher.selectWindow="--select window--"
AdvSceneSwitcher.selectAudioSource="--select audio source--"
AdvSceneSwitcher.selectMediaSource="--select media source--"
AdvSceneSwitcher.selectProcess="--select process--"
AdvSceneSwitcher.enterPath="--enter path--"
AdvSceneSwitcher.enterText="--enter text--"
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved"
AdvSceneSwitcher.selectWindowTip="Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB"
AdvSceneSwitcher.status.active="Active"
AdvSceneSwitcher.status.inactive="Inactive"
AdvSceneSwitcher.unit.milliseconds="milliseconds"
AdvSceneSwitcher.unit.secends="seconds"
AdvSceneSwitcher.unit.minutes="minutes"
AdvSceneSwitcher.unit.hours="hours"

206
data/locale/zh-CN.ini Normal file
View File

@@ -0,0 +1,206 @@
AdvSceneSwitcher.pluginName="高级场景切换器"
AdvSceneSwitcher.windowTitle="高级场景切换器"
; General Tab
AdvSceneSwitcher.generalTab.title="通用"
AdvSceneSwitcher.generalTab.status="状态"
AdvSceneSwitcher.generalTab.status.hotkeytips="快捷键可在OBS设置中设置"
AdvSceneSwitcher.generalTab.status.currentStatus="当前状态:"
AdvSceneSwitcher.generalTab.status.onStartup="在OBS启动时"
AdvSceneSwitcher.generalTab.status.onStartup.asLastRun="按照最后运行时的状态"
AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="总是自动启动"
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="不要启动"
AdvSceneSwitcher.generalTab.status.start="启动"
AdvSceneSwitcher.generalTab.status.stop="停止"
AdvSceneSwitcher.generalTab.status.checkInterval="检查切换条件时间间隔"
AdvSceneSwitcher.generalTab.generalBehavior="一般表现"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recording="录制"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.streaming="推流"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recordingAndStreaming="录制和推流"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart1="自动开始"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart2="当切换到场景时"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="如果不符合任何切换条件"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="时间精度最高只能达到配置的轮询间隔"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="不切换"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="切换到随机场景列表中任意随机场景"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="切换到"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="详细日志输出"
AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStop="当切换到场景时自动停止推流和录制"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="禁用UI提示"
AdvSceneSwitcher.generalTab.priority="优先级"
AdvSceneSwitcher.generalTab.priority.description="切换场景优先级 (最上方的项优先级最高)"
AdvSceneSwitcher.generalTab.priority.threadPriority="使用线程优先级"
AdvSceneSwitcher.generalTab.priority.threadPriorityNotice="(不推荐使用高于 \"Normal\" 的优先级)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings="导出或导入设置"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.export="导出设置"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.import="导入设置"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle="导出高级场景切换器到文件..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle="导入高级场景切换器到文件..."
AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType="文本文件 (*.txt)"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail="高级场景切换器导入设置失败"
AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess="高级场景切换器导入设置成功"
AdvSceneSwitcher.generalTab.priority.fileContent="文件内容"
AdvSceneSwitcher.generalTab.priority.sceneSequence="场景序列"
AdvSceneSwitcher.generalTab.priority.idleDetection="闲置检测"
AdvSceneSwitcher.generalTab.priority.executable="程序"
AdvSceneSwitcher.generalTab.priority.screenRegion="屏幕区域"
AdvSceneSwitcher.generalTab.priority.windowTitle="窗口标题"
AdvSceneSwitcher.generalTab.priority.media="媒体"
AdvSceneSwitcher.generalTab.priority.time="时间"
AdvSceneSwitcher.generalTab.priority.audio="音频"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="转场特效"
AdvSceneSwitcher.transitionTab.transitionOverride="在场景切换器中设定的转场特效优先级高于场景设定的转场特效"
AdvSceneSwitcher.transitionTab.transitionForAToB="当自动从场景A切换到场景B时使用的转场特效"
AdvSceneSwitcher.transitionTab.transitionForAToB.description="<html><head/><body><p>这里的设定<span style=\"font-style:bold;\">只影响由场景切换器引起的转场有效</span>,不影响你手动的引起的转场。<br/>在这里设定的转场特效优先级高于场景切换器其他地方设置的</p></body></html>"
AdvSceneSwitcher.transitionTab.defaultTransition="当切换到这个场景时修改默认转场特效"
AdvSceneSwitcher.transitionTab.switchDefaultLabel="活跃时切换默认转场特效为"
AdvSceneSwitcher.transitionTab.entry="从场景 {{scenes}} 切换到场景 {{scenes2}} 时使用转场特效 {{transitions}}"
AdvSceneSwitcher.transitionTab.defaultTransitionEntry="当场景 {{scenes}} 被激活时更改默认转场特效为 {{transitions}}"
; Pause Scenes Tab
AdvSceneSwitcher.pauseScenesTab.title="暂停"
AdvSceneSwitcher.pauseScenesTab.pauseOnScene="当切换到这个场景时暂停场景切换器"
AdvSceneSwitcher.pauseScenesTab.pauseInFocus1="当窗口"
AdvSceneSwitcher.pauseScenesTab.pauseInFocus2="获得焦点时暂停场景切换器"
; Window Title Tab
AdvSceneSwitcher.windowTitleTab.title="窗口标题"
AdvSceneSwitcher.windowTitleTab.regexrDescription="<html><head/><body><p>你可以直接输入窗口标题或正则表达式. 你可以使用<a href=\"https://regexr.com\"><span style=\" text-decoration: underline; color:#268bd2;\">RegExr</span></a>来检查验证你的正则表达式</p></body></html>"
AdvSceneSwitcher.windowTitleTab.stayInFocus1="当前焦点窗口标题为"
AdvSceneSwitcher.windowTitleTab.stayInFocus2="时保持当前场景"
AdvSceneSwitcher.windowTitleTab.fullscreen="全屏时"
AdvSceneSwitcher.windowTitleTab.maximized="最大化时"
AdvSceneSwitcher.windowTitleTab.focused="窗口聚集时"
AdvSceneSwitcher.windowTitleTab.entry="{{windows}} {{scenes}} {{transitions}} {{fullscreen}} {{maximized}} {{focused}}"
; Executable Tab
AdvSceneSwitcher.executableTab.title="程序"
AdvSceneSwitcher.executableTab.implemented="感谢dasOven的实现"
AdvSceneSwitcher.executableTab.requiresFocus="仅获得焦点时"
AdvSceneSwitcher.executableTab.entry="当 {{processes}} 正在运行时使用 {{transitions}} 切换到 {{scenes}} {{requiresFocus}}"
; Screen Region Tab
AdvSceneSwitcher.screenRegionTab.title="屏幕区域"
AdvSceneSwitcher.screenRegionTab.currentPosition="鼠标当前位置:"
AdvSceneSwitcher.screenRegionTab.showGuideFrames="显示区域边界"
AdvSceneSwitcher.screenRegionTab.hideGuideFrames="隐藏区域边界"
AdvSceneSwitcher.screenRegionTab.entry="如果鼠标在 {{minX}} {{minY}} x {{maxX}} {{maxY}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
; Media Tab
AdvSceneSwitcher.mediaTab.title="媒体"
AdvSceneSwitcher.mediaTab.implemented="感谢Exeldro的实现"
AdvSceneSwitcher.mediaTab.states.none="空"
AdvSceneSwitcher.mediaTab.states.playing="播放中"
AdvSceneSwitcher.mediaTab.states.opening="正在打开"
AdvSceneSwitcher.mediaTab.states.buffering="缓冲中"
AdvSceneSwitcher.mediaTab.states.Paused="暂停"
AdvSceneSwitcher.mediaTab.states.stopped="停止"
AdvSceneSwitcher.mediaTab.states.ended="结束"
AdvSceneSwitcher.mediaTab.states.error="错误"
AdvSceneSwitcher.mediaTab.states.any="任意"
AdvSceneSwitcher.mediaTab.timeRestriction.none="无"
AdvSceneSwitcher.mediaTab.timeRestriction.shorter="播放时间小于"
AdvSceneSwitcher.mediaTab.timeRestriction.longer="播放时间大于"
AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter="剩余时间少于"
AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger="剩余时间多于"
AdvSceneSwitcher.mediaTab.entry="当 {{meidaSources}} 状态为 {{states}} 并且 {{timeRestrictions}} {{time}} 时使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
; File Tab
AdvSceneSwitcher.fileTab.title="文件"
AdvSceneSwitcher.fileTab.readWriteSceneFile="从文件加载或保存当前场景名"
AdvSceneSwitcher.fileTab.currentSceneOutputFile="将当前场景写入到这个文件:"
AdvSceneSwitcher.fileTab.switchSceneBaseOnFile="启用从文件读取应切换到的场景名"
AdvSceneSwitcher.fileTab.switchSceneNameInputFile="从这个文件读取应切换到的场景名:"
AdvSceneSwitcher.fileTab.switchSceneBaseOnFileContent="根据文件内容切换场景"
AdvSceneSwitcher.fileTab.remoteFileWarning="请注意 如果你使用网络文件,场景切换器会按照你在通用页设置的间隔时间尝试访问网络文件!"
AdvSceneSwitcher.fileTab.remoteFileWarning1="注意,场景切换器会每 "
AdvSceneSwitcher.fileTab.remoteFileWarning2="毫秒尝试访问网络文件"
AdvSceneSwitcher.fileTab.libcurlWarning="无法加载 libcurl 库! 访问网络文件功能将不可用!"
AdvSceneSwitcher.fileTab.selectWrite="写入到文件..."
AdvSceneSwitcher.fileTab.selectRead="从文件读取..."
AdvSceneSwitcher.fileTab.textFileType="文本文件 (*.txt)"
AdvSceneSwitcher.fileTab.anyFileType="任意文件 (*.*)"
AdvSceneSwitcher.fileTab.remote="网络"
AdvSceneSwitcher.fileTab.local="本地"
AdvSceneSwitcher.fileTab.useRegExp="使用正则表达式(模式匹配)"
AdvSceneSwitcher.fileTab.checkfileContentTime="仅当文件修改时间改变时检查文件内容"
AdvSceneSwitcher.fileTab.checkfileContent="仅当文件发生修改时"
AdvSceneSwitcher.fileTab.entry="如果 {{fileType}} 文件 {{filePath}} {{browseButton}} 匹配下列规则,使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
AdvSceneSwitcher.fileTab.entry2="{{matchText}}"
AdvSceneSwitcher.fileTab.entry3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
; Random Tab
AdvSceneSwitcher.randomTab.title="随机场景列表"
AdvSceneSwitcher.randomTab.randomDisabledWarning="功能已被禁用 - 可通过在通用页设置\"如果不符合任何切换条件切换到随机场景列表中任意随机场景\"启用"
AdvSceneSwitcher.randomTab.entry="如果没有切换器条件满足,使用转场特效 {{transitions}} 切换到场景 {{scenes}} 并停留 {{delay}}"
; Time Tab
AdvSceneSwitcher.timeTab.title="时间"
AdvSceneSwitcher.timeTab.anyDay="每天"
AdvSceneSwitcher.timeTab.mondays="每周一"
AdvSceneSwitcher.timeTab.tuesdays="每周二"
AdvSceneSwitcher.timeTab.wednesdays="每周三"
AdvSceneSwitcher.timeTab.thursdays="每周四"
AdvSceneSwitcher.timeTab.fridays="每周五"
AdvSceneSwitcher.timeTab.saturdays="每周六"
AdvSceneSwitcher.timeTab.sundays="每周日"
AdvSceneSwitcher.timeTab.afterstart="推流或录制开始后"
AdvSceneSwitcher.timeTab.afterstart.tip="相对于直播或录制开始之后的时间点"
AdvSceneSwitcher.timeTab.entry="{{triggers}} 的 {{time}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
; Idle Tab
AdvSceneSwitcher.idleTab.title="闲置检测"
AdvSceneSwitcher.idleTab.enable="启用闲置检测"
AdvSceneSwitcher.idleTab.condition1="超过"
AdvSceneSwitcher.idleTab.condition2="没有鼠标或键盘操作"
AdvSceneSwitcher.idleTab.switchToScene="切换到场景"
AdvSceneSwitcher.idleTab.usingTransition1="使用"
AdvSceneSwitcher.idleTab.usingTransition2="转场特效"
AdvSceneSwitcher.idleTab.dontSwitchIfFocus1="如果当前窗口焦点在"
AdvSceneSwitcher.idleTab.dontSwitchIfFocus2="时不切换"
; Scene Sequence Tab
AdvSceneSwitcher.sceneSequenceTab.title="场景序列"
AdvSceneSwitcher.sceneSequenceTab.description="自动场景序列可以通过暂停或停止场景切换器或者手动切换到其他场景来取消"
AdvSceneSwitcher.sceneSequenceTab.save="保存当前序列到文件"
AdvSceneSwitcher.sceneSequenceTab.load="从文件加载序列"
AdvSceneSwitcher.sceneSequenceTab.saveTitle="保存当前序列到文件 ..."
AdvSceneSwitcher.sceneSequenceTab.loadTitle="从文件加载序列 ..."
AdvSceneSwitcher.sceneSequenceTab.loadFail="导入失败"
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="导入失败成功"
AdvSceneSwitcher.sceneSequenceTab.fileType="文本文件 (*.txt)"
AdvSceneSwitcher.sceneSequenceTab.entry="当场景 {{startScenes}} 被激活 {{delay}} {{delayUnits}}后使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
; Audio Tab
AdvSceneSwitcher.audioTab.title="音频"
AdvSceneSwitcher.audioTab.entry="当{{audioSources}} 的音量高于 {{volumeWidget}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
; Hotkey
AdvSceneSwitcher.hotkey.startSwitcherHotkey="启动高级场景切换器"
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="停止高级场景切换器"
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="切换(启动/停止)高级场景切换器"
AdvSceneSwitcher.close="关闭"
AdvSceneSwitcher.browse="浏览文件"
AdvSceneSwitcher.selectScene="--选择场景--"
AdvSceneSwitcher.selectTransition="--选择转场特效--"
AdvSceneSwitcher.selectWindow="--选择窗口--"
AdvSceneSwitcher.selectAudioSource="--选择音频源--"
AdvSceneSwitcher.selectMediaSource="--选择媒体源--"
AdvSceneSwitcher.selectProcess="--选择进程--"
AdvSceneSwitcher.enterPath="--输入路径--"
AdvSceneSwitcher.enterText="--输入文本--"
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="无效项将不会被保存"
AdvSceneSwitcher.selectWindowTip="使用 \"OBS\" 来指定OBS窗口\n使用 \"Task Switching\" 来指定 Alt + Tab"
AdvSceneSwitcher.status.active="运行中"
AdvSceneSwitcher.status.inactive="已停止"
AdvSceneSwitcher.unit.milliseconds="毫秒"
AdvSceneSwitcher.unit.secends="秒"
AdvSceneSwitcher.unit.minutes="分钟"
AdvSceneSwitcher.unit.hours="小时"

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,15 @@
#include <obs-module.h>
#include <obs-frontend-api.h>
OBS_DECLARE_MODULE()
OBS_MODULE_USE_DEFAULT_LOCALE("advanced-scene-switcher", "en-US")
void InitSceneSwitcher();
void FreeSceneSwitcher();
bool obs_module_load(void)
{
obs_frontend_push_ui_translation(obs_module_get_string);
InitSceneSwitcher();
return true;
}

View File

@@ -4,6 +4,7 @@
#include <QPropertyAnimation>
#include <QGraphicsColorizeEffect>
#include <obs-module.h>
#include <obs-frontend-api.h>
#include <util/util.hpp>
@@ -77,8 +78,10 @@ void AdvSceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious,
bool addSelect)
{
if (addSelect)
addSelectionEntry(sel, "--select scene--",
"invalid entries will not be saved");
addSelectionEntry(
sel, obs_module_text("AdvSceneSwitcher.selectScene"),
obs_module_text(
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
BPtr<char *> scenes = obs_frontend_get_scene_names();
char **temp = scenes;
@@ -96,7 +99,9 @@ void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel,
bool addSelect)
{
if (addSelect)
addSelectionEntry(sel, "--select transition--");
addSelectionEntry(
sel,
obs_module_text("AdvSceneSwitcher.selectTransition"));
obs_frontend_source_list *transitions = new obs_frontend_source_list();
obs_frontend_get_transitions(transitions);
@@ -113,7 +118,8 @@ void AdvSceneSwitcher::populateTransitionSelection(QComboBox *sel,
void AdvSceneSwitcher::populateWindowSelection(QComboBox *sel, bool addSelect)
{
if (addSelect)
addSelectionEntry(sel, "--select window--");
addSelectionEntry(
sel, obs_module_text("AdvSceneSwitcher.selectWindow"));
std::vector<std::string> windows;
GetWindowList(windows);
@@ -124,18 +130,19 @@ void AdvSceneSwitcher::populateWindowSelection(QComboBox *sel, bool addSelect)
}
#ifdef WIN32
sel->setItemData(
0,
"Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB",
Qt::ToolTipRole);
sel->setItemData(0, obs_module_text("AdvSceneSwitcher.selectWindowTip"),
Qt::ToolTipRole);
#endif
}
void AdvSceneSwitcher::populateAudioSelection(QComboBox *sel, bool addSelect)
{
if (addSelect)
addSelectionEntry(sel, "--select audio source--",
"invalid entries will not be saved");
addSelectionEntry(
sel,
obs_module_text("AdvSceneSwitcher.selectAudioSource"),
obs_module_text(
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{
@@ -155,8 +162,11 @@ void AdvSceneSwitcher::populateAudioSelection(QComboBox *sel, bool addSelect)
void AdvSceneSwitcher::populateMediaSelection(QComboBox *sel, bool addSelect)
{
if (addSelect)
addSelectionEntry(sel, "--select media source--",
"invalid entries will not be saved");
addSelectionEntry(
sel,
obs_module_text("AdvSceneSwitcher.selectMediaSource"),
obs_module_text(
"AdvSceneSwitcher.invaildEntriesWillNotBeSaved"));
auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */
{
@@ -176,7 +186,8 @@ void AdvSceneSwitcher::populateMediaSelection(QComboBox *sel, bool addSelect)
void AdvSceneSwitcher::populateProcessSelection(QComboBox *sel, bool addSelect)
{
if (addSelect)
addSelectionEntry(sel, "--select process--");
addSelectionEntry(
sel, obs_module_text("AdvSceneSwitcher.selectProcess"));
QStringList processes;
GetProcessList(processes);
@@ -486,6 +497,9 @@ void SwitcherData::Start()
switcher->th = new SwitcherThread();
switcher->th->start(
(QThread::Priority)switcher->threadPriority);
// Will be overwritten quickly but might be useful
writeToStatusFile("Advanced Scene Switcher running");
}
}
@@ -498,6 +512,8 @@ void SwitcherData::Stop()
th->wait();
delete th;
th = nullptr;
writeToStatusFile("Advanced Scene Switcher stopped");
}
}
@@ -594,7 +610,7 @@ extern "C" void InitSceneSwitcher()
blog(LOG_INFO, "version: %s", g_GIT_SHA1);
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
"Advanced Scene Switcher");
obs_module_text("AdvSceneSwitcher.pluginName"));
switcher = new SwitcherData;

View File

@@ -94,15 +94,19 @@ void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
void AdvSceneSwitcher::SetStarted()
{
ui->toggleStartButton->setText("Stop");
ui->pluginRunningText->setText("Active");
ui->toggleStartButton->setText(
obs_module_text("AdvSceneSwitcher.generalTab.status.stop"));
ui->pluginRunningText->setText(
obs_module_text("AdvSceneSwitcher.status.active"));
ui->pluginRunningText->disconnect(inactivePluse);
}
void AdvSceneSwitcher::SetStopped()
{
ui->toggleStartButton->setText("Start");
ui->pluginRunningText->setText("Inactive");
ui->toggleStartButton->setText(
obs_module_text("AdvSceneSwitcher.generalTab.status.start"));
ui->pluginRunningText->setText(
obs_module_text("AdvSceneSwitcher.status.inactive"));
inactivePluse = PulseWidget(ui->pluginRunningText, QColor(Qt::red),
QColor(0, 0, 0, 0), "QLabel ");
}
@@ -280,8 +284,12 @@ void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
void AdvSceneSwitcher::on_exportSettings_clicked()
{
QString directory = QFileDialog::getSaveFileName(
this, tr("Export Advanced Scene Switcher settings to file ..."),
QDir::currentPath(), tr("Text files (*.txt)"));
this,
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle")),
QDir::currentPath(),
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType")));
if (directory.isEmpty())
return;
@@ -317,8 +325,11 @@ void AdvSceneSwitcher::on_importSettings_clicked()
QString directory = QFileDialog::getOpenFileName(
this,
tr("Import Advanced Scene Switcher settings from file ..."),
QDir::currentPath(), tr("Text files (*.txt)"));
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle")),
QDir::currentPath(),
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType")));
if (directory.isEmpty())
return;
@@ -331,8 +342,8 @@ void AdvSceneSwitcher::on_importSettings_clicked()
if (!obj) {
QMessageBox Msgbox;
Msgbox.setText(
"Advanced Scene Switcher failed to import settings");
Msgbox.setText(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail"));
Msgbox.exec();
return;
}
@@ -355,8 +366,8 @@ void AdvSceneSwitcher::on_importSettings_clicked()
obs_data_release(obj);
QMessageBox Msgbox;
Msgbox.setText(
"Advanced Scene Switcher settings imported successfully");
Msgbox.setText(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess"));
Msgbox.exec();
close();
}
@@ -688,8 +699,8 @@ void AdvSceneSwitcher::setupGeneralTab()
ui->noMatchSwitchScene->setCurrentText(
GetWeakSourceName(switcher->nonMatchingScene).c_str());
ui->noMatchDelay->setValue(switcher->noMatchDelay);
ui->noMatchDelay->setToolTip(
"Will only ever be as accurate as the configured check interval.");
ui->noMatchDelay->setToolTip(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip"));
ui->checkInterval->setValue(switcher->interval);
ui->autoStopSceneCheckBox->setChecked(switcher->autoStopEnable);
@@ -702,9 +713,12 @@ void AdvSceneSwitcher::setupGeneralTab()
ui->autoStopScenes->setDisabled(true);
}
ui->autoStartType->addItem("Recording");
ui->autoStartType->addItem("Streaming");
ui->autoStartType->addItem("Recording and Streaming");
ui->autoStartType->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recording"));
ui->autoStartType->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.streaming"));
ui->autoStartType->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart.recordingAndStreaming"));
ui->autoStartSceneCheckBox->setChecked(switcher->autoStartEnable);
ui->autoStartScenes->setCurrentText(
@@ -726,31 +740,40 @@ void AdvSceneSwitcher::setupGeneralTab()
std::string s = "";
switch (p) {
case read_file_func:
s = "File Content";
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.fileContent");
break;
case round_trip_func:
s = "Scene Sequence";
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.sceneSequence");
break;
case idle_func:
s = "Idle Detection";
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.idleDetection");
break;
case exe_func:
s = "Executable";
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.executable");
break;
case screen_region_func:
s = "Screen Region";
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.screenRegion");
break;
case window_title_func:
s = "Window Title";
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.windowTitle");
break;
case media_func:
s = "Media";
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.media");
break;
case time_func:
s = "Time";
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.time");
break;
case audio_func:
s = "Audio";
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.audio");
break;
}
QString text(s.c_str());
@@ -772,10 +795,12 @@ void AdvSceneSwitcher::setupGeneralTab()
}
}
ui->startupBehavior->addItem(
"Start the scene switcher if it was running");
ui->startupBehavior->addItem("Always start the scene switcher");
ui->startupBehavior->addItem("Do not start the scene switcher");
ui->startupBehavior->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.onStartup.asLastRun"));
ui->startupBehavior->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart"));
ui->startupBehavior->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.onStartup.doNotStart"));
ui->startupBehavior->setCurrentIndex(switcher->startupBehavior);

View File

@@ -145,7 +145,6 @@ public slots:
void on_browseButton_clicked();
void on_readFileCheckBox_stateChanged(int state);
void on_fileType_currentIndexChanged(int idx);
void on_readPathLineEdit_textChanged(const QString &text);
void on_writePathLineEdit_textChanged(const QString &text);
void on_browseButton_2_clicked();
@@ -168,8 +167,7 @@ public slots:
void on_fileAdd_clicked();
void on_fileRemove_clicked();
void on_fileScenesList_currentRowChanged(int idx);
void on_browseButton_3_clicked();
void on_fileSwitches_currentRowChanged(int idx);
void on_fileUp_clicked();
void on_fileDown_clicked();

View File

@@ -53,13 +53,7 @@ private slots:
private:
QComboBox *audioSources;
QSpinBox *audioVolumeThreshold;
VolControl *volMeter;
QLabel *whenLabel;
QLabel *aboveLabel;
QLabel *switchLabel;
QLabel *usingLabel;
AudioSwitch *switchData;
};

View File

@@ -40,9 +40,5 @@ private:
QComboBox *processes;
QCheckBox *requiresFocus;
QLabel *whenLabel;
QLabel *switchLabel;
QLabel *usingLabel;
ExecutableSwitch *switchData;
};

View File

@@ -1,12 +1,19 @@
#pragma once
#include "switch-generic.hpp"
#include <QPlainTextEdit>
#include <obs-module.h>
constexpr auto read_file_func = 0;
constexpr auto default_priority_0 = read_file_func;
typedef enum {
LOCAL,
REMOTE,
} file_type;
struct FileSwitch : SceneSwitcherEntry {
std::string file;
std::string text;
std::string file = obs_module_text("AdvSceneSwitcher.enterPath");
std::string text = obs_module_text("AdvSceneSwitcher.enterText");
bool remote = false;
bool useRegex = false;
bool useTime = false;
@@ -16,6 +23,7 @@ struct FileSwitch : SceneSwitcherEntry {
const char *getType() { return "file"; }
inline FileSwitch(){};
inline FileSwitch(OBSWeakSource scene_, OBSWeakSource transition_,
const char *file_, const char *text_, bool remote_,
bool useRegex_, bool useTime_,
@@ -32,6 +40,38 @@ struct FileSwitch : SceneSwitcherEntry {
}
};
class FileSwitchWidget : public SwitchWidget {
Q_OBJECT
public:
FileSwitchWidget(FileSwitch *s);
FileSwitch *getSwitchData();
void setSwitchData(FileSwitch *s);
static void swapSwitchData(FileSwitchWidget *as1,
FileSwitchWidget *as2);
private slots:
void FileTypeChanged(int index);
void FilePathChanged();
void MatchTextChanged();
void UseRegexChanged(int state);
void CheckModificationDateChanged(int state);
void CheckFileContentChanged(int state);
void BrowseButtonClicked();
private:
QComboBox *fileType;
QLineEdit *filePath;
QPushButton *browseButton;
QPlainTextEdit *matchText;
QCheckBox *useRegex;
QCheckBox *checkModificationDate;
QCheckBox *checkFileContent;
FileSwitch *switchData;
};
struct FileIOData {
bool readEnabled = false;
std::string readPath;

View File

@@ -75,11 +75,5 @@ private:
QComboBox *timeRestrictions;
QSpinBox *time;
QLabel *whenLabel;
QLabel *stateLabel;
QLabel *andLabel;
QLabel *switchLabel;
QLabel *usingLabel;
MediaSwitch *switchData;
};

View File

@@ -31,9 +31,5 @@ private slots:
private:
QDoubleSpinBox *delay;
QLabel *switchLabel;
QLabel *usingLabel;
QLabel *forLabel;
RandomSwitch *switchData;
};

View File

@@ -51,11 +51,6 @@ private:
QFrame helperFrame;
QLabel *cursorLabel;
QLabel *xLabel;
QLabel *switchLabel;
QLabel *usingLabel;
ScreenRegionSwitch *switchData;
void drawFrame();

View File

@@ -55,10 +55,5 @@ private:
QComboBox *delayUnits;
QComboBox *startScenes;
QLabel *whenLabel;
QLabel *switchLabel;
QLabel *afterLabel;
QLabel *usingLabel;
SceneSequenceSwitch *switchData;
};

View File

@@ -53,9 +53,5 @@ private:
QComboBox *triggers;
QTimeEdit *time;
QLabel *atLabel;
QLabel *switchLabel;
QLabel *usingLabel;
TimeSwitch *switchData;
};

View File

@@ -45,10 +45,6 @@ private slots:
private:
QComboBox *scenes2;
QLabel *switchLabel;
QLabel *toLabel;
QLabel *usingLabel;
SceneTransition *switchData;
};
@@ -64,8 +60,5 @@ public:
DefTransitionSwitchWidget *s2);
private:
QLabel *whenLabel;
QLabel *switchLabel;
DefaultSceneTransition *switchData;
};

View File

@@ -86,7 +86,7 @@ struct SwitcherData {
IdleData idleData;
FileIOData fileIO;
std::vector<FileSwitch> fileSwitches;
std::deque<FileSwitch> fileSwitches;
CURL *curl = nullptr;
std::deque<ExecutableSwitch> executableSwitches;
@@ -156,6 +156,7 @@ struct SwitcherData {
bool sceneChangedDuringWait();
bool prioFuncsValid();
void writeSceneInfoToFile();
void writeToStatusFile(QString status);
void autoStopStreamAndRecording();
void autoStartStreamRecording();
bool checkPause();

View File

@@ -1,6 +1,12 @@
#pragma once
#include <obs.hpp>
#include <QString>
#include <QLayout>
#include <QLabel>
#include <unordered_map>
#include <obs.hpp>
#include <obs-module.h>
#include <obs-frontend-api.h>
static inline bool WeakSourceValid(obs_weak_source_t *ws)
@@ -82,3 +88,64 @@ static inline OBSWeakSource GetWeakTransitionByQString(const QString &name)
{
return GetWeakTransitionByName(name.toUtf8().constData());
}
static inline std::string
getNextDelim(std::string text,
std::unordered_map<std::string, QWidget *> placeholders)
{
size_t pos = std::string::npos;
std::string res = "";
for (const auto &ph : placeholders) {
size_t newPos = text.find(ph.first);
if (newPos <= pos) {
pos = newPos;
res = ph.first;
}
}
if (pos == std::string::npos)
return "";
return res;
}
/**
* Populate layout with labels and widgets based on provided text
*
* @param text Text based on which labels are generated and widgets are placed.
* @param layout Layout in which the widgets and labels will be placed.
* @param placeholders Map containing a mapping of placeholder strings to widgets.
* @param addStretch Add addStretch() to layout.
*/
static inline void
placeWidgets(std::string text, QBoxLayout *layout,
std::unordered_map<std::string, QWidget *> placeholders,
bool addStretch = true)
{
std::vector<std::pair<std::string, QWidget *>> labelsWidgetsPairs;
std::string delim = getNextDelim(text, placeholders);
while (delim != "") {
size_t pos = text.find(delim);
if (pos != std::string::npos) {
labelsWidgetsPairs.emplace_back(text.substr(0, pos),
placeholders[delim]);
text.erase(0, pos + delim.length());
}
delim = getNextDelim(text, placeholders);
}
if (text != "") {
labelsWidgetsPairs.emplace_back(text, nullptr);
}
for (auto &lw : labelsWidgetsPairs) {
if (lw.first != "")
layout->addWidget(new QLabel(lw.first.c_str()));
if (lw.second)
layout->addWidget(lw.second);
}
if (addStretch)
layout->addStretch();
}

View File

@@ -47,14 +47,17 @@ void startStopToggleHotkeyFunc(void *data, obs_hotkey_id id,
void registerHotkeys()
{
switcher->startHotkey = obs_hotkey_register_frontend(
"startSwitcherHotkey", "Start the Advanced Scene Switcher",
"startSwitcherHotkey",
obs_module_text("AdvSceneSwitcher.hotkey.startSwitcherHotkey"),
startHotkeyFunc, NULL);
switcher->stopHotkey = obs_hotkey_register_frontend(
"stopSwitcherHotkey", "Stop the Advanced Scene Switcher",
"stopSwitcherHotkey",
obs_module_text("AdvSceneSwitcher.hotkey.stopSwitcherHotkey"),
stopHotkeyFunc, NULL);
switcher->toggleHotkey = obs_hotkey_register_frontend(
"startStopToggleSwitcherHotkey",
"Toggle Start/Stop for the Advanced Scene Switcher",
obs_module_text(
"AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey"),
startStopToggleHotkeyFunc, NULL);
switcher->hotkeysRegistered = true;

View File

@@ -330,11 +330,6 @@ AudioSwitchWidget::AudioSwitchWidget(AudioSwitch *s) : SwitchWidget(s)
volMeter = new VolControl(soruce);
obs_source_release(soruce);
whenLabel = new QLabel("When the volume of");
aboveLabel = new QLabel("is above");
switchLabel = new QLabel("switch to");
usingLabel = new QLabel("using");
audioVolumeThreshold->setSuffix("%");
audioVolumeThreshold->setMaximum(100);
audioVolumeThreshold->setMinimum(0);
@@ -360,16 +355,13 @@ AudioSwitchWidget::AudioSwitchWidget(AudioSwitch *s) : SwitchWidget(s)
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *switchLayout = new QHBoxLayout;
switchLayout->addWidget(whenLabel);
switchLayout->addWidget(audioSources);
switchLayout->addWidget(aboveLabel);
switchLayout->addWidget(audioVolumeThreshold);
switchLayout->addWidget(switchLabel);
switchLayout->addWidget(scenes);
switchLayout->addWidget(usingLabel);
switchLayout->addWidget(transitions);
switchLayout->addStretch();
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{audioSources}}", audioSources},
{"{{volumeWidget}}", audioVolumeThreshold},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
placeWidgets(obs_module_text("AdvSceneSwitcher.audioTab.entry"),
switchLayout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;

View File

@@ -206,11 +206,8 @@ ExecutableSwitchWidget::ExecutableSwitchWidget(ExecutableSwitch *s)
: SwitchWidget(s, false)
{
processes = new QComboBox();
requiresFocus = new QCheckBox("only if focused");
whenLabel = new QLabel("When");
switchLabel = new QLabel("is running switch to");
usingLabel = new QLabel("using");
requiresFocus = new QCheckBox(obs_module_text(
"AdvSceneSwitcher.executableTab.requiresFocus"));
QWidget::connect(processes, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(ProcessChanged(const QString &)));
@@ -230,16 +227,13 @@ ExecutableSwitchWidget::ExecutableSwitchWidget(ExecutableSwitch *s)
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(whenLabel);
mainLayout->addWidget(processes);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addWidget(requiresFocus);
mainLayout->addStretch();
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{processes}}", processes},
{"{{requiresFocus}}", requiresFocus},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
placeWidgets(obs_module_text("AdvSceneSwitcher.executableTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
switchData = s;

View File

@@ -8,16 +8,16 @@
#include "headers/curl-helper.hpp"
#include "headers/utility.hpp"
#define LOCAL_FILE_IDX 0
#define REMOTE_FILE_IDX 1
std::hash<std::string> strHash;
static QMetaObject::Connection addPulse;
static std::hash<std::string> strHash;
void AdvSceneSwitcher::on_browseButton_clicked()
{
QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to write to ..."), QDir::currentPath(),
tr("Text files (*.txt)"));
this,
tr(obs_module_text("AdvSceneSwitcher.fileTab.selectWrite")),
QDir::currentPath(),
tr(obs_module_text("AdvSceneSwitcher.fileTab.textFileType")));
if (!path.isEmpty())
ui->writePathLineEdit->setText(path);
}
@@ -70,8 +70,10 @@ void AdvSceneSwitcher::on_writePathLineEdit_textChanged(const QString &text)
void AdvSceneSwitcher::on_browseButton_2_clicked()
{
QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to read from ..."), QDir::currentPath(),
tr("Any files (*.*)"));
this,
tr(obs_module_text("AdvSceneSwitcher.fileTab.selectRead")),
QDir::currentPath(),
tr(obs_module_text("AdvSceneSwitcher.fileTab.anyFileType")));
if (!path.isEmpty())
ui->readPathLineEdit->setText(path);
}
@@ -92,6 +94,19 @@ void SwitcherData::writeSceneInfoToFile()
obs_source_release(currentSource);
}
void SwitcherData::writeToStatusFile(QString msg)
{
if (!fileIO.writeEnabled || fileIO.writePath.empty())
return;
QFile file(QString::fromStdString(fileIO.writePath));
if (file.open(QIODevice::ReadWrite)) {
QTextStream stream(&file);
stream << msg << endl;
}
file.close();
}
void SwitcherData::checkSwitchInfoFromFile(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition)
{
@@ -151,7 +166,7 @@ bool compareIgnoringLineEnding(QString &s1, QString &s2)
QTextStream s1stream(&s1);
QTextStream s2stream(&s2);
while (!s1stream.atEnd() && !s2stream.atEnd()) {
while (!s1stream.atEnd() || !s2stream.atEnd()) {
QString s1s = s1stream.readLine();
QString s2s = s2stream.readLine();
if (QString::compare(s1s, s2s, Qt::CaseSensitive) != 0) {
@@ -171,8 +186,8 @@ bool matchFileContent(QString &filedata, FileSwitch &s)
}
if (s.useRegex) {
return filedata.contains(
QRegularExpression(QString::fromStdString(s.text)));
QRegExp rx(QString::fromStdString(s.text));
return rx.exactMatch(filedata);
}
QString text = QString::fromStdString(s.text);
@@ -190,7 +205,7 @@ bool checkLocalFileContent(FileSwitch &s)
{
QString t = QString::fromStdString(s.text);
QFile file(QString::fromStdString(s.file));
if (!file.open(QIODevice::ReadOnly))
if (s.file.empty() || !file.open(QIODevice::ReadOnly))
return false;
if (s.useTime) {
@@ -230,86 +245,37 @@ void SwitcherData::checkFileContent(bool &match, OBSWeakSource &scene,
}
}
void AdvSceneSwitcher::on_browseButton_3_clicked()
{
QString path = QFileDialog::getOpenFileName(
this, tr("Select a file to read from ..."), QDir::currentPath(),
tr("Any files (*.*)"));
if (!path.isEmpty())
ui->filePathLineEdit->setText(path);
}
void AdvSceneSwitcher::on_fileType_currentIndexChanged(int idx)
{
if (idx == -1)
return;
if (idx == LOCAL_FILE_IDX) {
ui->browseButton_3->setDisabled(false);
ui->fileContentTimeCheckBox->setDisabled(false);
ui->remoteFileWarningLabel->hide();
}
if (idx == REMOTE_FILE_IDX) {
ui->browseButton_3->setDisabled(true);
ui->fileContentTimeCheckBox->setDisabled(true);
ui->remoteFileWarningLabel->show();
}
}
void AdvSceneSwitcher::on_fileAdd_clicked()
{
QString sceneName = ui->fileScenes->currentText();
QString transitionName = ui->fileTransitions->currentText();
QString fileName = ui->filePathLineEdit->text();
QString text = ui->fileTextEdit->toPlainText();
bool remote = (ui->fileType->currentIndex() == REMOTE_FILE_IDX);
bool useRegex = ui->fileContentRegExCheckBox->isChecked();
bool useTime = ui->fileContentTimeCheckBox->isChecked();
bool onlyMatchIfChanged = ui->onlyMatchIfChanged->isChecked();
if (sceneName.isEmpty() || transitionName.isEmpty() ||
fileName.isEmpty() || text.isEmpty())
return;
OBSWeakSource source = GetWeakSourceByQString(sceneName);
OBSWeakSource transition = GetWeakTransitionByQString(transitionName);
QString switchText = MakeFileSwitchName(sceneName, transitionName,
fileName, text, useRegex,
useTime, onlyMatchIfChanged);
QVariant v = QVariant::fromValue(switchText);
QListWidgetItem *item =
new QListWidgetItem(switchText, ui->fileScenesList);
item->setData(Qt::UserRole, v);
std::lock_guard<std::mutex> lock(switcher->m);
switcher->fileSwitches.emplace_back(source, transition,
fileName.toUtf8().constData(),
text.toUtf8().constData(), remote,
useRegex, useTime,
onlyMatchIfChanged);
switcher->fileSwitches.emplace_back();
QListWidgetItem *item;
item = new QListWidgetItem(ui->fileSwitches);
ui->fileSwitches->addItem(item);
FileSwitchWidget *sw =
new FileSwitchWidget(&switcher->fileSwitches.back());
item->setSizeHint(sw->minimumSizeHint());
ui->fileSwitches->setItemWidget(item, sw);
}
void AdvSceneSwitcher::on_fileRemove_clicked()
{
QListWidgetItem *item = ui->fileScenesList->currentItem();
QListWidgetItem *item = ui->fileSwitches->currentItem();
if (!item)
return;
int idx = ui->fileScenesList->currentRow();
if (idx == -1)
return;
{
std::lock_guard<std::mutex> lock(switcher->m);
int idx = ui->fileSwitches->currentRow();
auto &switches = switcher->fileSwitches;
switches.erase(switches.begin() + idx);
}
qDeleteAll(ui->fileScenesList->selectedItems());
delete item;
}
void AdvSceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
void AdvSceneSwitcher::on_fileSwitches_currentRowChanged(int idx)
{
if (loading)
return;
@@ -321,51 +287,47 @@ void AdvSceneSwitcher::on_fileScenesList_currentRowChanged(int idx)
if ((int)switcher->fileSwitches.size() <= idx)
return;
FileSwitch s = switcher->fileSwitches[idx];
std::string sceneName = GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
ui->fileScenes->setCurrentText(sceneName.c_str());
ui->fileTransitions->setCurrentText(transitionName.c_str());
ui->fileTextEdit->setPlainText(s.text.c_str());
ui->filePathLineEdit->setText(s.file.c_str());
if (s.remote)
ui->fileType->setCurrentIndex(REMOTE_FILE_IDX);
ui->remoteFileWarningLabel->show();
else
ui->fileType->setCurrentIndex(LOCAL_FILE_IDX);
ui->fileContentRegExCheckBox->setChecked(s.useRegex);
ui->fileContentTimeCheckBox->setChecked(s.useTime);
ui->onlyMatchIfChanged->setChecked(s.onlyMatchIfChanged);
ui->remoteFileWarningLabel->hide();
}
void AdvSceneSwitcher::on_fileUp_clicked()
{
int index = ui->fileScenesList->currentRow();
if (index != -1 && index != 0) {
ui->fileScenesList->insertItem(
index - 1, ui->fileScenesList->takeItem(index));
ui->fileScenesList->setCurrentRow(index - 1);
int index = ui->fileSwitches->currentRow();
if (!listMoveUp(ui->fileSwitches))
return;
std::lock_guard<std::mutex> lock(switcher->m);
FileSwitchWidget *s1 = (FileSwitchWidget *)ui->fileSwitches->itemWidget(
ui->fileSwitches->item(index));
FileSwitchWidget *s2 = (FileSwitchWidget *)ui->fileSwitches->itemWidget(
ui->fileSwitches->item(index - 1));
FileSwitchWidget::swapSwitchData(s1, s2);
iter_swap(switcher->fileSwitches.begin() + index,
switcher->fileSwitches.begin() + index - 1);
}
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->fileSwitches[index],
switcher->fileSwitches[index - 1]);
}
void AdvSceneSwitcher::on_fileDown_clicked()
{
int index = ui->fileScenesList->currentRow();
if (index != -1 && index != ui->fileScenesList->count() - 1) {
ui->fileScenesList->insertItem(
index + 1, ui->fileScenesList->takeItem(index));
ui->fileScenesList->setCurrentRow(index + 1);
int index = ui->fileSwitches->currentRow();
std::lock_guard<std::mutex> lock(switcher->m);
if (!listMoveDown(ui->fileSwitches))
return;
iter_swap(switcher->fileSwitches.begin() + index,
switcher->fileSwitches.begin() + index + 1);
}
FileSwitchWidget *s1 = (FileSwitchWidget *)ui->fileSwitches->itemWidget(
ui->fileSwitches->item(index));
FileSwitchWidget *s2 = (FileSwitchWidget *)ui->fileSwitches->itemWidget(
ui->fileSwitches->item(index + 1));
FileSwitchWidget::swapSwitchData(s1, s2);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(switcher->fileSwitches[index],
switcher->fileSwitches[index + 1]);
}
void SwitcherData::saveFileSwitches(obs_data_t *obj)
@@ -447,31 +409,27 @@ void SwitcherData::loadFileSwitches(obs_data_t *obj)
void AdvSceneSwitcher::setupFileTab()
{
populateSceneSelection(ui->fileScenes, false);
populateTransitionSelection(ui->fileTransitions);
ui->fileType->addItem("local");
ui->fileType->addItem("remote");
ui->remoteFileWarningLabel->setText(
"Note that the scene switcher will try to access the remote location every " +
QString::number(switcher->interval) + "ms");
obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning1") +
QString::number(switcher->interval) +
obs_module_text("AdvSceneSwitcher.fileTab.remoteFileWarning2"));
ui->remoteFileWarningLabel->hide();
if (switcher->curl)
ui->libcurlWarning->setVisible(false);
for (auto &s : switcher->fileSwitches) {
std::string sceneName = GetWeakSourceName(s.scene);
std::string transitionName = GetWeakSourceName(s.transition);
QString listText = MakeFileSwitchName(
sceneName.c_str(), transitionName.c_str(),
s.file.c_str(), s.text.c_str(), s.useRegex, s.useTime,
s.onlyMatchIfChanged);
QListWidgetItem *item =
new QListWidgetItem(listText, ui->fileScenesList);
item->setData(Qt::UserRole, listText);
QListWidgetItem *item;
item = new QListWidgetItem(ui->fileSwitches);
ui->fileSwitches->addItem(item);
FileSwitchWidget *sw = new FileSwitchWidget(&s);
item->setSizeHint(sw->minimumSizeHint());
ui->fileSwitches->setItemWidget(item, sw);
}
if (switcher->fileSwitches.size() == 0)
addPulse = PulseWidget(ui->fileAdd, QColor(Qt::green));
ui->readPathLineEdit->setText(
QString::fromStdString(switcher->fileIO.readPath.c_str()));
ui->readFileCheckBox->setChecked(switcher->fileIO.readEnabled);
@@ -487,28 +445,175 @@ void AdvSceneSwitcher::setupFileTab()
}
}
static inline QString MakeFileSwitchName(const QString &scene,
const QString &transition,
const QString &fileName,
const QString &text, bool useRegex,
bool useTime, bool onlyMatchIfChanged)
FileSwitchWidget::FileSwitchWidget(FileSwitch *s) : SwitchWidget(s, false)
{
QString switchName = QStringLiteral("Switch to ") + scene +
QStringLiteral(" using ") + transition +
QStringLiteral(" if ") + fileName;
if (useTime)
switchName += QStringLiteral(" was modified and");
if (onlyMatchIfChanged)
switchName += QStringLiteral(" if the contents changed and");
switchName += QStringLiteral(" contains");
if (useRegex)
switchName += QStringLiteral(" (RegEx): \n\"");
else
switchName += QStringLiteral(": \n\"");
if (text.length() > 30)
switchName += text.left(27) + QStringLiteral("...\"");
else
switchName += text + QStringLiteral("\"");
fileType = new QComboBox();
filePath = new QLineEdit();
browseButton =
new QPushButton(obs_module_text("AdvSceneSwitcher.browse"));
browseButton->setStyleSheet("border:1px solid gray;");
matchText = new QPlainTextEdit();
useRegex = new QCheckBox(
obs_module_text("AdvSceneSwitcher.fileTab.useRegExp"));
checkModificationDate = new QCheckBox(obs_module_text(
"AdvSceneSwitcher.fileTab.checkfileContentTime"));
checkFileContent = new QCheckBox(
obs_module_text("AdvSceneSwitcher.fileTab.checkfileContent"));
return switchName;
QWidget::connect(fileType, SIGNAL(currentIndexChanged(int)), this,
SLOT(FileTypeChanged(int)));
QWidget::connect(filePath, SIGNAL(editingFinished()), this,
SLOT(FilePathChanged()));
QWidget::connect(browseButton, SIGNAL(clicked()), this,
SLOT(BrowseButtonClicked()));
QWidget::connect(matchText, SIGNAL(textChanged()), this,
SLOT(MatchTextChanged()));
QWidget::connect(useRegex, SIGNAL(stateChanged(int)), this,
SLOT(UseRegexChanged(int)));
QWidget::connect(checkModificationDate, SIGNAL(stateChanged(int)), this,
SLOT(CheckModificationDateChanged(int)));
QWidget::connect(checkFileContent, SIGNAL(stateChanged(int)), this,
SLOT(CheckFileContentChanged(int)));
fileType->addItem(obs_module_text("AdvSceneSwitcher.fileTab.local"));
fileType->addItem(obs_module_text("AdvSceneSwitcher.fileTab.remote"));
if (s) {
if (s->remote)
fileType->setCurrentIndex(1);
else
fileType->setCurrentIndex(0);
filePath->setText(QString::fromStdString(s->file));
matchText->setPlainText(QString::fromStdString(s->text));
useRegex->setChecked(s->useRegex);
checkModificationDate->setChecked(s->useTime);
checkFileContent->setChecked(s->onlyMatchIfChanged);
}
setStyleSheet("* { background-color: transparent; }");
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{fileType}}", fileType},
{"{{filePath}}", filePath},
{"{{browseButton}}", browseButton},
{"{{matchText}}", matchText},
{"{{useRegex}}", useRegex},
{"{{checkModificationDate}}", checkModificationDate},
{"{{checkFileContent}}", checkFileContent},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
QVBoxLayout *mainLayout = new QVBoxLayout;
QHBoxLayout *line1Layout = new QHBoxLayout;
QHBoxLayout *line2Layout = new QHBoxLayout;
QHBoxLayout *line3Layout = new QHBoxLayout;
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry"),
line1Layout, widgetPlaceholders);
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry2"),
line2Layout, widgetPlaceholders, false);
placeWidgets(obs_module_text("AdvSceneSwitcher.fileTab.entry3"),
line3Layout, widgetPlaceholders);
mainLayout->addLayout(line1Layout);
mainLayout->addLayout(line2Layout);
mainLayout->addLayout(line3Layout);
setLayout(mainLayout);
switchData = s;
loading = false;
}
FileSwitch *FileSwitchWidget::getSwitchData()
{
return switchData;
}
void FileSwitchWidget::setSwitchData(FileSwitch *s)
{
switchData = s;
}
void FileSwitchWidget::swapSwitchData(FileSwitchWidget *s1,
FileSwitchWidget *s2)
{
SwitchWidget::swapSwitchData(s1, s2);
FileSwitch *t = s1->getSwitchData();
s1->setSwitchData(s2->getSwitchData());
s2->setSwitchData(t);
}
void FileSwitchWidget::FileTypeChanged(int index)
{
if (loading || !switchData)
return;
if ((file_type)index == LOCAL) {
browseButton->setDisabled(false);
checkModificationDate->setDisabled(false);
} else {
browseButton->setDisabled(true);
checkModificationDate->setDisabled(true);
}
std::lock_guard<std::mutex> lock(switcher->m);
switchData->remote = (file_type)index == REMOTE;
}
void FileSwitchWidget::FilePathChanged()
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->file = filePath->text().toUtf8().constData();
}
void FileSwitchWidget::BrowseButtonClicked()
{
if (loading || !switchData)
return;
QString path = QFileDialog::getOpenFileName(
this,
tr(obs_module_text("AdvSceneSwitcher.fileTab.selectRead")),
QDir::currentPath(),
tr(obs_module_text("AdvSceneSwitcher.fileTab.anyFileType")));
if (path.isEmpty())
return;
filePath->setText(path);
FilePathChanged();
}
void FileSwitchWidget::MatchTextChanged()
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->text = matchText->toPlainText().toUtf8().constData();
}
void FileSwitchWidget::UseRegexChanged(int state)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->useRegex = state;
}
void FileSwitchWidget::CheckModificationDateChanged(int state)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->useTime = state;
}
void FileSwitchWidget::CheckFileContentChanged(int state)
{
if (loading || !switchData)
return;
std::lock_guard<std::mutex> lock(switcher->m);
switchData->onlyMatchIfChanged = state;
}

View File

@@ -414,25 +414,38 @@ void swap(MediaSwitch &first, MediaSwitch &second)
void populateMediaStates(QComboBox *list)
{
list->addItem("None");
list->addItem("Playing");
list->addItem("Opening");
list->addItem("Buffering");
list->addItem("Paused");
list->addItem("Stopped");
list->addItem("Ended");
list->addItem("Error");
list->addItem("Played to end");
list->addItem("Any");
list->addItem(obs_module_text("AdvSceneSwitcher.mediaTab.states.none"));
list->addItem(
obs_module_text("AdvSceneSwitcher.mediaTab.states.playing"));
list->addItem(
obs_module_text("AdvSceneSwitcher.mediaTab.states.opening"));
list->addItem(
obs_module_text("AdvSceneSwitcher.mediaTab.states.buffering"));
list->addItem(
obs_module_text("AdvSceneSwitcher.mediaTab.states.paused"));
list->addItem(
obs_module_text("AdvSceneSwitcher.mediaTab.states.stopped"));
list->addItem(
obs_module_text("AdvSceneSwitcher.mediaTab.states.ended"));
list->addItem(
obs_module_text("AdvSceneSwitcher.mediaTab.states.error"));
list->addItem(obs_module_text(
"AdvSceneSwitcher.mediaTab.states.playedToEnd"));
list->addItem(obs_module_text("AdvSceneSwitcher.mediaTab.states.any"));
}
void populateTimeRestrictions(QComboBox *list)
{
list->addItem("None");
list->addItem("Time shorter");
list->addItem("Time longer");
list->addItem("Time remaining shorter");
list->addItem("Time remaining longer");
list->addItem(obs_module_text(
"AdvSceneSwitcher.mediaTab.timeRestriction.none"));
list->addItem(obs_module_text(
"AdvSceneSwitcher.mediaTab.timeRestriction.shorter"));
list->addItem(obs_module_text(
"AdvSceneSwitcher.mediaTab.timeRestriction.longer"));
list->addItem(obs_module_text(
"AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter"));
list->addItem(obs_module_text(
"AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger"));
}
MediaSwitchWidget::MediaSwitchWidget(MediaSwitch *s) : SwitchWidget(s)
@@ -442,12 +455,6 @@ MediaSwitchWidget::MediaSwitchWidget(MediaSwitch *s) : SwitchWidget(s)
timeRestrictions = new QComboBox();
time = new QSpinBox();
whenLabel = new QLabel("When");
stateLabel = new QLabel("state is");
andLabel = new QLabel("and");
switchLabel = new QLabel("switch to");
usingLabel = new QLabel("using");
time->setSuffix("ms");
time->setMaximum(99999999);
time->setMinimum(0);
@@ -479,20 +486,15 @@ MediaSwitchWidget::MediaSwitchWidget(MediaSwitch *s) : SwitchWidget(s)
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(whenLabel);
mainLayout->addWidget(meidaSources);
mainLayout->addWidget(stateLabel);
mainLayout->addWidget(states);
mainLayout->addWidget(andLabel);
mainLayout->addWidget(timeRestrictions);
mainLayout->addWidget(time);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{meidaSources}}", meidaSources},
{"{{states}}", states},
{"{{timeRestrictions}}", timeRestrictions},
{"{{time}}", time},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
placeWidgets(obs_module_text("AdvSceneSwitcher.mediaTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
switchData = s;

View File

@@ -143,10 +143,6 @@ RandomSwitchWidget::RandomSwitchWidget(RandomSwitch *s) : SwitchWidget(s, false)
{
delay = new QDoubleSpinBox();
switchLabel = new QLabel("If no switch condition is met switch to ");
usingLabel = new QLabel("using");
forLabel = new QLabel("for");
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
SLOT(DelayChanged(double)));
@@ -160,15 +156,12 @@ RandomSwitchWidget::RandomSwitchWidget(RandomSwitch *s) : SwitchWidget(s, false)
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addWidget(forLabel);
mainLayout->addWidget(delay);
mainLayout->addStretch();
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{scenes}}", scenes},
{"{{transitions}}", transitions},
{"{{delay}}", delay}};
placeWidgets(obs_module_text("AdvSceneSwitcher.randomTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
switchData = s;

View File

@@ -27,12 +27,14 @@ void showCurrentFrame(QListWidget *list)
void AdvSceneSwitcher::SetShowFrames()
{
ui->showFrame->setText("Show guide frames");
ui->showFrame->setText(obs_module_text(
"AdvSceneSwitcher.screenRegionTab.showGuideFrames"));
}
void AdvSceneSwitcher::SetHideFrames()
{
ui->showFrame->setText("Hide guide frames");
ui->showFrame->setText(obs_module_text(
"AdvSceneSwitcher.screenRegionTab.hideGuideFrames"));
}
void AdvSceneSwitcher::on_showFrame_clicked()
@@ -257,11 +259,6 @@ ScreenRegionWidget::ScreenRegionWidget(ScreenRegionSwitch *s)
maxX = new QSpinBox();
maxY = new QSpinBox();
cursorLabel = new QLabel("If cursor is in");
xLabel = new QLabel("x");
switchLabel = new QLabel("switch to");
usingLabel = new QLabel("using");
minX->setPrefix("Min X: ");
minY->setPrefix("Min Y: ");
maxX->setPrefix("Max X: ");
@@ -296,19 +293,12 @@ ScreenRegionWidget::ScreenRegionWidget(ScreenRegionSwitch *s)
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(cursorLabel);
mainLayout->addWidget(minX);
mainLayout->addWidget(minY);
mainLayout->addWidget(xLabel);
mainLayout->addWidget(maxX);
mainLayout->addWidget(maxY);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{minX}}", minX}, {"{{minY}}", minY},
{"{{maxX}}", maxX}, {"{{maxY}}", maxY},
{"{{scenes}}", scenes}, {"{{transitions}}", transitions}};
placeWidgets(obs_module_text("AdvSceneSwitcher.screenRegionTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
switchData = s;

View File

@@ -92,8 +92,12 @@ void AdvSceneSwitcher::on_sceneSequenceDown_clicked()
void AdvSceneSwitcher::on_sceneSequenceSave_clicked()
{
QString directory = QFileDialog::getSaveFileName(
this, tr("Save Scene Sequence to file ..."),
QDir::currentPath(), tr("Text files (*.txt)"));
this,
tr(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.saveTitle")),
QDir::currentPath(),
tr(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.fileType")));
if (directory.isEmpty())
return;
QFile file(directory);
@@ -109,8 +113,12 @@ void AdvSceneSwitcher::on_sceneSequenceSave_clicked()
void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
{
QString directory = QFileDialog::getOpenFileName(
this, tr("Select a file to read Scene Sequence from ..."),
QDir::currentPath(), tr("Text files (*.txt)"));
this,
tr(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.loadTitle")),
QDir::currentPath(),
tr(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.fileType")));
if (directory.isEmpty())
return;
@@ -123,8 +131,8 @@ void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
if (!obj) {
QMessageBox Msgbox;
Msgbox.setText(
"Advanced Scene Switcher failed to import settings!");
Msgbox.setText(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.loadFail"));
Msgbox.exec();
return;
}
@@ -143,8 +151,8 @@ void AdvSceneSwitcher::on_sceneSequenceLoad_clicked()
obs_data_release(obj);
QMessageBox Msgbox;
Msgbox.setText(
"Advanced Scene Switcher settings imported successfully!");
Msgbox.setText(obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.loadSuccess"));
Msgbox.exec();
close();
}
@@ -304,9 +312,9 @@ void SceneSequenceSwitch::logSleep(int dur)
void populateDelayUnits(QComboBox *list)
{
list->addItem("seconds");
list->addItem("minutes");
list->addItem("hours");
list->addItem(obs_module_text("AdvSceneSwitcher.unit.secends"));
list->addItem(obs_module_text("AdvSceneSwitcher.unit.minutes"));
list->addItem(obs_module_text("AdvSceneSwitcher.unit.hours"));
}
SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
@@ -315,11 +323,6 @@ SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
delayUnits = new QComboBox();
startScenes = new QComboBox();
whenLabel = new QLabel("When");
switchLabel = new QLabel("is active switch to");
afterLabel = new QLabel("after");
usingLabel = new QLabel("using");
QWidget::connect(delay, SIGNAL(valueChanged(double)), this,
SLOT(DelayChanged(double)));
QWidget::connect(delayUnits, SIGNAL(currentIndexChanged(int)), this,
@@ -353,18 +356,14 @@ SequenceWidget::SequenceWidget(SceneSequenceSwitch *s) : SwitchWidget(s)
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(whenLabel);
mainLayout->addWidget(startScenes);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(afterLabel);
mainLayout->addWidget(delay);
mainLayout->addWidget(delayUnits);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{startScenes}}", startScenes},
{"{{scenes}}", scenes},
{"{{delay}}", delay},
{"{{delayUnits}}", delayUnits},
{"{{transitions}}", transitions}};
placeWidgets(obs_module_text("AdvSceneSwitcher.sceneSequenceTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
switchData = s;

View File

@@ -214,19 +214,18 @@ void AdvSceneSwitcher::setupTimeTab()
void populateTriggers(QComboBox *list)
{
list->addItem("On any day");
list->addItem("Mondays");
list->addItem("Tuesdays");
list->addItem("Wednesdays");
list->addItem("Thursdays");
list->addItem("Fridays");
list->addItem("Saturdays");
list->addItem("Sundays");
list->addItem("Atfer streaming/recording start");
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.anyDay"));
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.mondays"));
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.tuesdays"));
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.wednesdays"));
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.thursdays"));
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.fridays"));
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.saturdays"));
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.sundays"));
list->addItem(obs_module_text("AdvSceneSwitcher.timeTab.afterstart"));
list->setItemData(
8,
"The time relative to the start of streaming / recording will be used",
8, obs_module_text("AdvSceneSwitcher.timeTab.afterstart.tip"),
Qt::ToolTipRole);
}
@@ -235,10 +234,6 @@ TimeSwitchWidget::TimeSwitchWidget(TimeSwitch *s) : SwitchWidget(s)
triggers = new QComboBox();
time = new QTimeEdit();
atLabel = new QLabel("at");
switchLabel = new QLabel("switch to");
usingLabel = new QLabel("using");
QWidget::connect(triggers, SIGNAL(currentIndexChanged(int)), this,
SLOT(TriggerChanged(int)));
QWidget::connect(time, SIGNAL(timeChanged(const QTime &)), this,
@@ -255,16 +250,13 @@ TimeSwitchWidget::TimeSwitchWidget(TimeSwitch *s) : SwitchWidget(s)
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(triggers);
mainLayout->addWidget(atLabel);
mainLayout->addWidget(time);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{triggers}}", triggers},
{"{{time}}", time},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
placeWidgets(obs_module_text("AdvSceneSwitcher.timeTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
switchData = s;

View File

@@ -418,10 +418,6 @@ TransitionSwitchWidget::TransitionSwitchWidget(SceneTransition *s)
{
scenes2 = new QComboBox();
switchLabel = new QLabel("Switch from scene");
toLabel = new QLabel("to scene");
usingLabel = new QLabel("using transition");
QWidget::connect(scenes2, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(Scene2Changed(const QString &)));
@@ -434,15 +430,12 @@ TransitionSwitchWidget::TransitionSwitchWidget(SceneTransition *s)
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(toLabel);
mainLayout->addWidget(scenes2);
mainLayout->addWidget(usingLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{scenes}}", scenes},
{"{{scenes2}}", scenes2},
{"{{transitions}}", transitions}};
placeWidgets(obs_module_text("AdvSceneSwitcher.transitionTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
switchData = s;
@@ -481,20 +474,15 @@ void TransitionSwitchWidget::Scene2Changed(const QString &text)
DefTransitionSwitchWidget::DefTransitionSwitchWidget(DefaultSceneTransition *s)
: SwitchWidget(s, false)
{
whenLabel = new QLabel("When scene");
switchLabel =
new QLabel("is active change default scene transition to ");
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(whenLabel);
mainLayout->addWidget(scenes);
mainLayout->addWidget(switchLabel);
mainLayout->addWidget(transitions);
mainLayout->addStretch();
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{scenes}}", scenes}, {"{{transitions}}", transitions}};
placeWidgets(
obs_module_text(
"AdvSceneSwitcher.transitionTab.defaultTransitionEntry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
switchData = s;

View File

@@ -373,9 +373,12 @@ void AdvSceneSwitcher::setupTitleTab()
WindowSwitchWidget::WindowSwitchWidget(WindowSwitch *s) : SwitchWidget(s, false)
{
windows = new QComboBox();
fullscreen = new QCheckBox("if fullscreen");
maximized = new QCheckBox("if maximized");
focused = new QCheckBox("if focused");
fullscreen = new QCheckBox(
obs_module_text("AdvSceneSwitcher.windowTitleTab.fullscreen"));
maximized = new QCheckBox(
obs_module_text("AdvSceneSwitcher.windowTitleTab.maximized"));
focused = new QCheckBox(
obs_module_text("AdvSceneSwitcher.windowTitleTab.focused"));
QWidget::connect(windows, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(WindowChanged(const QString &)));
@@ -407,16 +410,15 @@ WindowSwitchWidget::WindowSwitchWidget(WindowSwitch *s) : SwitchWidget(s, false)
setStyleSheet("* { background-color: transparent; }");
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(windows);
mainLayout->addWidget(scenes);
mainLayout->addWidget(transitions);
mainLayout->addWidget(scenes);
mainLayout->addWidget(fullscreen);
mainLayout->addWidget(maximized);
mainLayout->addWidget(focused);
mainLayout->addStretch();
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{windows}}", windows},
{"{{scenes}}", scenes},
{"{{transitions}}", transitions},
{"{{fullscreen}}", fullscreen},
{"{{maximized}}", maximized},
{"{{focused}}", focused}};
placeWidgets(obs_module_text("AdvSceneSwitcher.windowTitleTab.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
switchData = s;