diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ef918760..fd32bfb5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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() diff --git a/CI/macos/SceneSwitcher.pkgproj b/CI/macos/SceneSwitcher.pkgproj index 7cf80900..0a5aec9e 100644 --- a/CI/macos/SceneSwitcher.pkgproj +++ b/CI/macos/SceneSwitcher.pkgproj @@ -60,6 +60,22 @@ UID 0 + + CHILDREN + + GID + 80 + PATH + ../../data + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + GID 80 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d8ae9f8..7628da73 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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() diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini new file mode 100644 index 00000000..bd32921f --- /dev/null +++ b/data/locale/en-US.ini @@ -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="

These settings only affect transitions caused by the scene switcher - Check out Transition Matrix if you want to configure this for manual scene changes.
Settings defined here take priority over transition settings configured elsewhere in the scene switcher.

" +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="

Enter either direct window titles or valid regex. You can check syntax and matches for regular expressions using RegExr

" +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" diff --git a/data/locale/zh-CN.ini b/data/locale/zh-CN.ini new file mode 100644 index 00000000..4d1f3550 --- /dev/null +++ b/data/locale/zh-CN.ini @@ -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="

这里的设定只影响由场景切换器引起的转场有效,不影响你手动的引起的转场。
在这里设定的转场特效优先级高于场景切换器其他地方设置的

" +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="

你可以直接输入窗口标题或正则表达式. 你可以使用RegExr来检查验证你的正则表达式

" +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="小时" + diff --git a/forms/advanced-scene-switcher.ui b/forms/advanced-scene-switcher.ui index 959cd287..1ee2f512 100644 --- a/forms/advanced-scene-switcher.ui +++ b/forms/advanced-scene-switcher.ui @@ -23,7 +23,7 @@ - Advanced Scene Switcher + AdvSceneSwitcher.windowTitle true @@ -42,7 +42,7 @@ - General + AdvSceneSwitcher.generalTab.title @@ -52,7 +52,7 @@ - Status + AdvSceneSwitcher.generalTab.status @@ -60,28 +60,28 @@ - Hotkeys can be defined in the OBS settings + AdvSceneSwitcher.generalTab.status.hotkeytips - Advanced Scene Switcher is: + AdvSceneSwitcher.generalTab.status.currentStatus - On startup: + AdvSceneSwitcher.generalTab.status.onStartup - Start + AdvSceneSwitcher.generalTab.status.start @@ -113,7 +113,7 @@ - Check switch conditions every + AdvSceneSwitcher.generalTab.status.checkInterval @@ -122,7 +122,7 @@ - Not Active + AdvSceneSwitcher.status.inactive @@ -149,7 +149,7 @@ - General behavior + AdvSceneSwitcher.generalTab.generalBehavior @@ -157,7 +157,7 @@ - Automatically start + AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart1 @@ -180,7 +180,7 @@ - on scene + AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStart2 @@ -222,7 +222,7 @@ - Don't switch + AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch true @@ -236,7 +236,7 @@ - Switch to any scene in Random tab + AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom @@ -259,7 +259,7 @@ - Switch to: + AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo @@ -289,7 +289,7 @@ - If no switch condition is met for + AdvSceneSwitcher.generalTab.generalBehavior.onNoMet Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -315,7 +315,7 @@ - Enable verbose logging + AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging @@ -339,7 +339,7 @@ - Automatically stop streaming/recording on scene + AdvSceneSwitcher.generalTab.generalBehavior.automaticallyStop @@ -386,7 +386,7 @@ - Disable UI hints + AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints @@ -415,13 +415,13 @@ - Priority + AdvSceneSwitcher.generalTab.priority - Switching methods priority (Highest priority is at the top) + AdvSceneSwitcher.generalTab.priority.description @@ -524,7 +524,7 @@ - Use thread priority + AdvSceneSwitcher.generalTab.priority.threadPriority @@ -562,7 +562,7 @@ - (Raising the priority above "Normal" is not recommended) + AdvSceneSwitcher.generalTab.priority.threadPriorityNotice @@ -572,20 +572,20 @@ - Save / load settings + AdvSceneSwitcher.generalTab.saveOrLoadsettings - Export + AdvSceneSwitcher.generalTab.saveOrLoadsettings.export - Import + AdvSceneSwitcher.generalTab.saveOrLoadsettings.import @@ -600,13 +600,13 @@ - Transition + AdvSceneSwitcher.transitionTab.title - Scene transitions defined in the scene switcher take priority over Transition Overrides defined per scene + AdvSceneSwitcher.transitionTab.transitionOverride @@ -620,13 +620,13 @@ - Use transition for automated scene switch from scene A to scene B + AdvSceneSwitcher.transitionTab.transitionForAToB - <html><head/><body><p><span style=" font-style:italic;">Only</span> transitions caused by the scene switcher and not the ones you are causing manually are affected by these settings. <br/>Settings defined here take priority over transition settings configured elsewhere in the scene switcher.</p></body></html> + AdvSceneSwitcher.transitionTab.transitionForAToB.description true @@ -789,7 +789,7 @@ - Change transition if scene is active + AdvSceneSwitcher.transitionTab.defaultTransition @@ -946,7 +946,7 @@ - Pause + AdvSceneSwitcher.pauseScenesTab.title @@ -954,7 +954,7 @@ - Pause the Scene Switcher on scene + AdvSceneSwitcher.pauseScenesTab.pauseOnScene @@ -1066,7 +1066,7 @@ - Pause the Scene Switcher when + AdvSceneSwitcher.pauseScenesTab.pauseInFocus1 @@ -1092,7 +1092,7 @@ - is in focus + AdvSceneSwitcher.pauseScenesTab.pauseInFocus2 @@ -1177,7 +1177,7 @@ - Title + AdvSceneSwitcher.windowTitleTab.title @@ -1186,7 +1186,7 @@ - <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.regexrDescription Qt::AutoText @@ -1358,7 +1358,7 @@ - Stay on the currently selected scene when + AdvSceneSwitcher.windowTitleTab.stayInFocus1 @@ -1384,7 +1384,7 @@ - is focused + AdvSceneSwitcher.windowTitleTab.stayInFocus2 @@ -1475,7 +1475,7 @@ ArrowCursor - Executable + AdvSceneSwitcher.executableTab.title @@ -1623,7 +1623,7 @@ - Implemented by dasOven + AdvSceneSwitcher.executableTab.implemented @@ -1633,7 +1633,7 @@ - Region + AdvSceneSwitcher.screenRegionTab.title @@ -1641,7 +1641,7 @@ - Cursor is currently at: + AdvSceneSwitcher.screenRegionTab.currentPosition @@ -1688,7 +1688,7 @@ - Show guide frames + AdvSceneSwitcher.screenRegionTab.showGuideFrames @@ -1858,7 +1858,7 @@ - Media + AdvSceneSwitcher.mediaTab.title @@ -2006,7 +2006,7 @@ - Implemented by Exeldro + AdvSceneSwitcher.mediaTab.implemented @@ -2016,406 +2016,274 @@ - File + AdvSceneSwitcher.fileTab.title - + - - - - - Write the name of the current scene to this file: - - - - - - - - - - Browse - - - - - - - - - Qt::Horizontal + + + AdvSceneSwitcher.fileTab.readWriteSceneFile + + + + + + + AdvSceneSwitcher.fileTab.currentSceneOutputFile + + + + + + + + + + AdvSceneSwitcher.browse + + + + + + + + + + + AdvSceneSwitcher.fileTab.switchSceneBaseOnFile + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + AdvSceneSwitcher.fileTab.switchSceneNameInputFile + + + + + + + + + + AdvSceneSwitcher.browse + + + + + + - - - - - Enable switching of scenes based on file input - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Read scene name to be switched to from this file: - - - - - - - - - - Browse - - - - - - - - - Qt::Horizontal + + + AdvSceneSwitcher.fileTab.switchSceneBaseOnFileContent + + + + + AdvSceneSwitcher.fileTab.remoteFileWarning + + + + + + + true + + + + 75 + true + + + + AdvSceneSwitcher.fileTab.libcurlWarning + + + + + + + + 0 + 0 + + + + false + + + + + + + + + + 22 + 22 + + + + true + + + addIconSmall + + + + + + + + 22 + 22 + + + + true + + + removeIconSmall + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + Qt::Vertical + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 5 + 20 + + + + + + + + + 22 + 22 + + + + + + + + ../../../forms/images/up.svg../../../forms/images/up.svg + + + true + + + upArrowIconSmall + + + + + + + + 22 + 22 + + + + + + + + ../../../forms/images/down.svg../../../forms/images/down.svg + + + true + + + downArrowIconSmall + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + - - - - Switch scene based on file contents: - - - - - - - - - If the - - - - - - - - - - file - - - - - - - - - - Browse - - - - - - - contains: - - - - - - - - - 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! - - - - - - - true - - - - 75 - true - - - - Failed to load libcurl! Accesssing remote files will not be possible! - - - - - - - - - - - - Use regular expression (pattern matching) - - - - - - - Only check contents if modification date changed - - - - - - - Only match if content changed - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - switch to - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - - - - using - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 0 - 0 - - - - false - - - - - - - - - - 22 - 22 - - - - true - - - addIconSmall - - - - - - - - 22 - 22 - - - - true - - - removeIconSmall - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - - - - Qt::Vertical - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 5 - 20 - - - - - - - - - 22 - 22 - - - - - - - - ../../../forms/images/up.svg../../../forms/images/up.svg - - - true - - - upArrowIconSmall - - - - - - - - 22 - 22 - - - - - - - - ../../../forms/images/down.svg../../../forms/images/down.svg - - - true - - - downArrowIconSmall - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - Random + AdvSceneSwitcher.randomTab.title - Functionality disabled - To activate select "If no switch condition is met switch to any scene in Random tab" on General tab + AdvSceneSwitcher.randomTab.randomDisabledWarning @@ -2485,7 +2353,7 @@ - Time + AdvSceneSwitcher.timeTab.title @@ -2636,13 +2504,13 @@ - Idle + AdvSceneSwitcher.idleTab.title - Enable Idle Detection + AdvSceneSwitcher.idleTab.enable @@ -2651,7 +2519,7 @@ - After + AdvSceneSwitcher.idleTab.condition1 @@ -2674,14 +2542,14 @@ - of no keyboard or mouse inputs + AdvSceneSwitcher.idleTab.condition2 - switch to scene + AdvSceneSwitcher.idleTab.switchToScene @@ -2704,7 +2572,7 @@ - using the + AdvSceneSwitcher.idleTab.usingTransition1 @@ -2714,7 +2582,7 @@ - transition + AdvSceneSwitcher.idleTab.usingTransition2 @@ -2738,7 +2606,7 @@ - Do not switch if + AdvSceneSwitcher.idleTab.dontSwitchIfFocus1 @@ -2755,7 +2623,7 @@ - is in focus + AdvSceneSwitcher.idleTab.dontSwitchIfFocus2 @@ -2840,13 +2708,13 @@ - Sequence + AdvSceneSwitcher.sceneSequenceTab.title - 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.description @@ -3002,14 +2870,14 @@ - Save Round Trips to file + AdvSceneSwitcher.sceneSequenceTab.save - Load Round Trips from file + AdvSceneSwitcher.sceneSequenceTab.load @@ -3032,7 +2900,7 @@ - Audio + AdvSceneSwitcher.audioTab.title @@ -3189,7 +3057,7 @@ - Close + AdvSceneSwitcher.close diff --git a/src/advanced-scene-switcher-module.c b/src/advanced-scene-switcher-module.c index 8835c04d..ff4e7145 100644 --- a/src/advanced-scene-switcher-module.c +++ b/src/advanced-scene-switcher-module.c @@ -1,12 +1,15 @@ #include +#include 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; } diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp index 86976add..e3ecb0bc 100644 --- a/src/advanced-scene-switcher.cpp +++ b/src/advanced-scene-switcher.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -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 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 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; diff --git a/src/general.cpp b/src/general.cpp index 696dc277..0a6dcf4c 100644 --- a/src/general.cpp +++ b/src/general.cpp @@ -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); diff --git a/src/headers/advanced-scene-switcher.hpp b/src/headers/advanced-scene-switcher.hpp index 7110d011..8f1a262f 100644 --- a/src/headers/advanced-scene-switcher.hpp +++ b/src/headers/advanced-scene-switcher.hpp @@ -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(); diff --git a/src/headers/switch-audio.hpp b/src/headers/switch-audio.hpp index 431fd266..408717e9 100644 --- a/src/headers/switch-audio.hpp +++ b/src/headers/switch-audio.hpp @@ -53,13 +53,7 @@ private slots: private: QComboBox *audioSources; QSpinBox *audioVolumeThreshold; - VolControl *volMeter; - QLabel *whenLabel; - QLabel *aboveLabel; - QLabel *switchLabel; - QLabel *usingLabel; - AudioSwitch *switchData; }; diff --git a/src/headers/switch-executable.hpp b/src/headers/switch-executable.hpp index 644c05e4..71a3f2ed 100644 --- a/src/headers/switch-executable.hpp +++ b/src/headers/switch-executable.hpp @@ -40,9 +40,5 @@ private: QComboBox *processes; QCheckBox *requiresFocus; - QLabel *whenLabel; - QLabel *switchLabel; - QLabel *usingLabel; - ExecutableSwitch *switchData; }; diff --git a/src/headers/switch-file.hpp b/src/headers/switch-file.hpp index aa08e58a..f98b2152 100644 --- a/src/headers/switch-file.hpp +++ b/src/headers/switch-file.hpp @@ -1,12 +1,19 @@ #pragma once #include "switch-generic.hpp" +#include +#include 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; diff --git a/src/headers/switch-media.hpp b/src/headers/switch-media.hpp index 34a9a334..e5542f20 100644 --- a/src/headers/switch-media.hpp +++ b/src/headers/switch-media.hpp @@ -75,11 +75,5 @@ private: QComboBox *timeRestrictions; QSpinBox *time; - QLabel *whenLabel; - QLabel *stateLabel; - QLabel *andLabel; - QLabel *switchLabel; - QLabel *usingLabel; - MediaSwitch *switchData; }; diff --git a/src/headers/switch-random.hpp b/src/headers/switch-random.hpp index 9f9d64d6..a277d8af 100644 --- a/src/headers/switch-random.hpp +++ b/src/headers/switch-random.hpp @@ -31,9 +31,5 @@ private slots: private: QDoubleSpinBox *delay; - QLabel *switchLabel; - QLabel *usingLabel; - QLabel *forLabel; - RandomSwitch *switchData; }; diff --git a/src/headers/switch-screen-region.hpp b/src/headers/switch-screen-region.hpp index 7ed5b3bf..880ef7d8 100644 --- a/src/headers/switch-screen-region.hpp +++ b/src/headers/switch-screen-region.hpp @@ -51,11 +51,6 @@ private: QFrame helperFrame; - QLabel *cursorLabel; - QLabel *xLabel; - QLabel *switchLabel; - QLabel *usingLabel; - ScreenRegionSwitch *switchData; void drawFrame(); diff --git a/src/headers/switch-sequence.hpp b/src/headers/switch-sequence.hpp index 9c8aa1ef..7f1c8108 100644 --- a/src/headers/switch-sequence.hpp +++ b/src/headers/switch-sequence.hpp @@ -55,10 +55,5 @@ private: QComboBox *delayUnits; QComboBox *startScenes; - QLabel *whenLabel; - QLabel *switchLabel; - QLabel *afterLabel; - QLabel *usingLabel; - SceneSequenceSwitch *switchData; }; diff --git a/src/headers/switch-time.hpp b/src/headers/switch-time.hpp index ae8d4ae0..b9692bad 100644 --- a/src/headers/switch-time.hpp +++ b/src/headers/switch-time.hpp @@ -53,9 +53,5 @@ private: QComboBox *triggers; QTimeEdit *time; - QLabel *atLabel; - QLabel *switchLabel; - QLabel *usingLabel; - TimeSwitch *switchData; }; diff --git a/src/headers/switch-transitions.hpp b/src/headers/switch-transitions.hpp index 97be9652..b835c02b 100644 --- a/src/headers/switch-transitions.hpp +++ b/src/headers/switch-transitions.hpp @@ -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; }; diff --git a/src/headers/switcher-data-structs.hpp b/src/headers/switcher-data-structs.hpp index 322c629f..159882cc 100644 --- a/src/headers/switcher-data-structs.hpp +++ b/src/headers/switcher-data-structs.hpp @@ -86,7 +86,7 @@ struct SwitcherData { IdleData idleData; FileIOData fileIO; - std::vector fileSwitches; + std::deque fileSwitches; CURL *curl = nullptr; std::deque executableSwitches; @@ -156,6 +156,7 @@ struct SwitcherData { bool sceneChangedDuringWait(); bool prioFuncsValid(); void writeSceneInfoToFile(); + void writeToStatusFile(QString status); void autoStopStreamAndRecording(); void autoStartStreamRecording(); bool checkPause(); diff --git a/src/headers/utility.hpp b/src/headers/utility.hpp index 6e8ff410..5196e028 100644 --- a/src/headers/utility.hpp +++ b/src/headers/utility.hpp @@ -1,6 +1,12 @@ #pragma once -#include + #include +#include +#include +#include + +#include +#include #include 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 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 placeholders, + bool addStretch = true) +{ + std::vector> 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(); +} diff --git a/src/hotkey.cpp b/src/hotkey.cpp index e293e583..8b1e94a1 100644 --- a/src/hotkey.cpp +++ b/src/hotkey.cpp @@ -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; diff --git a/src/switch-audio.cpp b/src/switch-audio.cpp index 28c2362d..ae4eebe2 100644 --- a/src/switch-audio.cpp +++ b/src/switch-audio.cpp @@ -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 widgetPlaceholders = { + {"{{audioSources}}", audioSources}, + {"{{volumeWidget}}", audioVolumeThreshold}, + {"{{scenes}}", scenes}, + {"{{transitions}}", transitions}}; + placeWidgets(obs_module_text("AdvSceneSwitcher.audioTab.entry"), + switchLayout, widgetPlaceholders); QVBoxLayout *mainLayout = new QVBoxLayout; diff --git a/src/switch-executable.cpp b/src/switch-executable.cpp index df414929..894fb61c 100644 --- a/src/switch-executable.cpp +++ b/src/switch-executable.cpp @@ -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 widgetPlaceholders = { + {"{{processes}}", processes}, + {"{{requiresFocus}}", requiresFocus}, + {"{{scenes}}", scenes}, + {"{{transitions}}", transitions}}; + placeWidgets(obs_module_text("AdvSceneSwitcher.executableTab.entry"), + mainLayout, widgetPlaceholders); setLayout(mainLayout); switchData = s; diff --git a/src/switch-file.cpp b/src/switch-file.cpp index 3f5dffac..c26cde38 100644 --- a/src/switch-file.cpp +++ b/src/switch-file.cpp @@ -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 strHash; +static QMetaObject::Connection addPulse; +static std::hash 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 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 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 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 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 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 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 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 lock(switcher->m); + switchData->remote = (file_type)index == REMOTE; +} + +void FileSwitchWidget::FilePathChanged() +{ + if (loading || !switchData) + return; + std::lock_guard 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 lock(switcher->m); + switchData->text = matchText->toPlainText().toUtf8().constData(); +} + +void FileSwitchWidget::UseRegexChanged(int state) +{ + if (loading || !switchData) + return; + std::lock_guard lock(switcher->m); + switchData->useRegex = state; +} + +void FileSwitchWidget::CheckModificationDateChanged(int state) +{ + if (loading || !switchData) + return; + std::lock_guard lock(switcher->m); + switchData->useTime = state; +} + +void FileSwitchWidget::CheckFileContentChanged(int state) +{ + if (loading || !switchData) + return; + std::lock_guard lock(switcher->m); + switchData->onlyMatchIfChanged = state; } diff --git a/src/switch-media.cpp b/src/switch-media.cpp index a6ea9b47..72274d82 100644 --- a/src/switch-media.cpp +++ b/src/switch-media.cpp @@ -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 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; diff --git a/src/switch-random.cpp b/src/switch-random.cpp index 9ad84f1f..06ea806d 100644 --- a/src/switch-random.cpp +++ b/src/switch-random.cpp @@ -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 widgetPlaceholders = { + {"{{scenes}}", scenes}, + {"{{transitions}}", transitions}, + {"{{delay}}", delay}}; + placeWidgets(obs_module_text("AdvSceneSwitcher.randomTab.entry"), + mainLayout, widgetPlaceholders); setLayout(mainLayout); switchData = s; diff --git a/src/switch-screen-region.cpp b/src/switch-screen-region.cpp index 6677381d..f44ef755 100644 --- a/src/switch-screen-region.cpp +++ b/src/switch-screen-region.cpp @@ -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 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; diff --git a/src/switch-sequence.cpp b/src/switch-sequence.cpp index b1f35934..328a6660 100644 --- a/src/switch-sequence.cpp +++ b/src/switch-sequence.cpp @@ -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 widgetPlaceholders = { + {"{{startScenes}}", startScenes}, + {"{{scenes}}", scenes}, + {"{{delay}}", delay}, + {"{{delayUnits}}", delayUnits}, + {"{{transitions}}", transitions}}; + placeWidgets(obs_module_text("AdvSceneSwitcher.sceneSequenceTab.entry"), + mainLayout, widgetPlaceholders); setLayout(mainLayout); switchData = s; diff --git a/src/switch-time.cpp b/src/switch-time.cpp index b4067722..4b64a542 100644 --- a/src/switch-time.cpp +++ b/src/switch-time.cpp @@ -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 widgetPlaceholders = { + {"{{triggers}}", triggers}, + {"{{time}}", time}, + {"{{scenes}}", scenes}, + {"{{transitions}}", transitions}}; + placeWidgets(obs_module_text("AdvSceneSwitcher.timeTab.entry"), + mainLayout, widgetPlaceholders); setLayout(mainLayout); switchData = s; diff --git a/src/switch-transitions.cpp b/src/switch-transitions.cpp index 778fee1e..9c357524 100644 --- a/src/switch-transitions.cpp +++ b/src/switch-transitions.cpp @@ -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 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 widgetPlaceholders = { + {"{{scenes}}", scenes}, {"{{transitions}}", transitions}}; + placeWidgets( + obs_module_text( + "AdvSceneSwitcher.transitionTab.defaultTransitionEntry"), + mainLayout, widgetPlaceholders); setLayout(mainLayout); switchData = s; diff --git a/src/switch-window.cpp b/src/switch-window.cpp index 40112adc..38cbd716 100644 --- a/src/switch-window.cpp +++ b/src/switch-window.cpp @@ -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 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;