Compare commits

..

25 Commits
1.17 ... 1.17.2

Author SHA1 Message Date
WarmUpTill
af188b55df Move plugins to separate folder (#400) 2022-01-29 15:47:16 +01:00
WarmUpTill
f287a1041d Add option to also check for configured volume level 2022-01-25 12:46:16 -08:00
WarmUpTill
fda9b1c3ea Fix dock location and size not saving correctly
OBS will handle the docking position / window size and position as long
as an object name is set
2022-01-25 10:33:41 -08:00
WarmUpTill
9eb7f58525 CI: Save debian build result 2022-01-25 10:33:02 -08:00
WarmUpTill
abd6fd6b7e Add sequence action (#395) 2022-01-22 18:07:26 +01:00
WarmUpTill
2909b1300e Fix empty statusControl of general tab blocking mouse input 2022-01-22 06:14:03 -08:00
WarmUpTill
d1331a60b9 Fix crash on exit caused by status dock 2022-01-22 06:14:03 -08:00
WarmUpTill
d5fc3befb8 Remove QtConcurrent dependency 2022-01-22 06:14:03 -08:00
WarmUpTill
80f9c79907 CI: Bump windows QT version to 5.15.2 2022-01-22 06:14:03 -08:00
WarmUpTill
e4bd1fc180 Reduce amount of signals emitted on repopulate 2022-01-22 06:14:03 -08:00
WarmUpTill
59c87ca027 Emphasize that a duration of 0s means using default duration 2022-01-21 09:51:00 -08:00
WarmUpTill
eda161de39 Sort condition and action selection alphabetically 2022-01-21 09:51:00 -08:00
WarmUpTill
6033426a6e Enable word wrap for macro priority warning 2022-01-21 09:51:00 -08:00
WarmUpTill
caea16c6ad Hide selected macro for run or stop action
Running a macro from within itself is not supported and stopping it from
withint itself does not seem useful either.
2022-01-21 09:51:00 -08:00
WarmUpTill
e3a39a5df7 Add label clarifying the condition's intent 2022-01-21 09:51:00 -08:00
WarmUpTill
38b7e08711 Add macro action to stop other macros 2022-01-21 09:51:00 -08:00
WarmUpTill
7349841758 Fix unexpectedly returning true for hotkey condition
The condition would return true after unpause, if a configured hotkey was pressed
during the time the macro was paused.
2022-01-21 09:50:19 -08:00
WarmUpTill
5d58269b02 Add function to access parent macro from condition or action 2022-01-21 09:50:19 -08:00
WarmUpTill
8a4aef0f50 Update bug_report.md 2022-01-19 20:22:26 +01:00
WarmUpTill
4b877d865c Add issue templates 2022-01-16 19:43:51 +01:00
WarmUpTill
82503286ea Use the same widget for main settings window and status dock 2022-01-14 09:11:36 -08:00
WarmUpTill
16ee789c82 Add option to perform macro actions only on condition change 2022-01-06 08:41:18 -08:00
WarmUpTill
d040a01016 Reintroduce checkbox to change current scene check transition behaviour 2022-01-06 08:41:18 -08:00
WarmUpTill
eb952afe58 Enable time constraints for transition condition 2022-01-06 08:41:18 -08:00
WarmUpTill
34cff925fc CI: No longer query for 32 bit OBS install path 2022-01-05 20:21:03 +01:00
94 changed files with 1799 additions and 842 deletions

35
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,35 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Logs**
Please provide a log of your issue with verbose logging enabled (See General tab of the plugin).
See [here](https://obsproject.com/forum/threads/please-post-a-log-with-your-issue-heres-how.23074/) for a description where to find the log files and how to share them.
Please share the currently used plugin settings by exporting them them to a file (See General tab of the plugin).
If applicable, add screenshots to help explain your problem.
**Version information**
- OS: [e.g. Windows 10]
- OBS Version [e.g. 27.1.3]
- Plugin Version [e.g. 1.17.1]
**Additional context**
Add any other context about the problem here.

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -46,3 +46,10 @@ jobs:
- name: build
run: |
debuild --no-lintian --no-sign
mv ../*.deb .
- name: Publish
if: success()
uses: actions/upload-artifact@v2.2.1
with:
name: "obs-scene-switcher.deb"
path: ${{ github.workspace }}/*.deb

View File

@@ -206,8 +206,9 @@ jobs:
mv ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.LIB_NAME }}.so ./${{ env.LIB_NAME }}/bin/64bit/${{ env.LIB_NAME }}.so
mv ./UI/frontend-plugins/${{ env.PLUGIN_NAME }}/data ./${{ env.LIB_NAME }}/data
# Macro modules
mkdir -p ./${{ env.LIB_NAME }}/bin/64bit/adv-ss-plugins
strip -d ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/src/external-macro-modules/opencv/advanced-scene-switcher-opencv.so
mv ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/src/external-macro-modules/opencv/advanced-scene-switcher-opencv.so ./${{ env.LIB_NAME }}/bin/64bit/
mv ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/src/external-macro-modules/opencv/advanced-scene-switcher-opencv.so ./${{ env.LIB_NAME }}/bin/64bit/adv-ss-plugins
tar -cvzf "${FILE_NAME}" ${{ env.LIB_NAME }}
- name: "Publish"
uses: actions/upload-artifact@v2.2.1
@@ -221,7 +222,7 @@ jobs:
matrix:
arch: [32, 64]
env:
QT_VERSION: 5.10.1
QT_VERSION: 5.15.2
CMAKE_GENERATOR: "Visual Studio 16 2019"
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
WINDOWS_DEPS_VERSION: "2019"
@@ -275,11 +276,11 @@ jobs:
Get-Location
if ( ${{ matrix.arch }} -eq 32 )
{
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DOpenCV_DIR="${{ github.workspace }}/UI/frontend-plugins/SceneSwitcher/deps/opencv/build/" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win32" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DOpenCV_DIR="${{ github.workspace }}/UI/frontend-plugins/SceneSwitcher/deps/opencv/build/" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win32" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2019" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
}
else
{
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DOpenCV_DIR="${{ github.workspace }}/UI/frontend-plugins/SceneSwitcher/deps/opencv/build/" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win64" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017_64" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DOpenCV_DIR="${{ github.workspace }}/UI/frontend-plugins/SceneSwitcher/deps/opencv/build/" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win64" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2019_64" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
}
- name: Build
run: |
@@ -291,9 +292,10 @@ jobs:
$env:FILE_NAME="${{ env.PLUGIN_NAME }}-${env:FILE_DATE}-${{ github.sha }}-windows"
echo "FILE_NAME=${env:FILE_NAME}" >> ${env:GITHUB_ENV}
robocopy .\build${{ matrix.arch }}\rundir\RelWithDebInfo\obs-plugins\${{ matrix.arch }}bit\ .\package\obs-plugins\${{ matrix.arch }}bit ${{ env.LIB_NAME }}* /E /XF .gitignore
robocopy .\build${{ matrix.arch }}\rundir\RelWithDebInfo\obs-plugins\${{ matrix.arch }}bit\ .\package\obs-plugins\${{ matrix.arch }}bit adv-ss-plugins /E /XF .gitignore
robocopy .\build${{ matrix.arch }}\rundir\RelWithDebInfo\data\obs-plugins\${{ env.LIB_NAME }}\ .\package\data\obs-plugins\${{ env.LIB_NAME }}\ /E /XF .gitignore
cp UI/frontend-plugins/${{ env.PLUGIN_NAME }}/deps/opencv/build/bin/Release/*dll package/obs-plugins/${{ matrix.arch }}bit
cp UI/frontend-plugins/${{ env.PLUGIN_NAME }}/deps/openvr/bin/win${{ matrix.arch }}/*dll package/obs-plugins/${{ matrix.arch }}bit
cp UI/frontend-plugins/${{ env.PLUGIN_NAME }}/deps/opencv/build/bin/Release/*dll package/obs-plugins/${{ matrix.arch }}bit/adv-ss-plugins
cp UI/frontend-plugins/${{ env.PLUGIN_NAME }}/deps/openvr/bin/win${{ matrix.arch }}/*dll package/obs-plugins/${{ matrix.arch }}bit/adv-ss-plugins
exit 0
- name: Publish zip
if: success()

View File

@@ -30,6 +30,327 @@
<dict>
<key>CHILDREN</key>
<array>
<dict>
<key>CHILDREN</key>
<array>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../../../../build/UI/frontend-plugins/SceneSwitcher/src/external-macro-modules/opencv/advanced-scene-switcher-opencv.so</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_objdetect.4.5.3.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_features2d.4.5.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_core.4.5.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_calib3d.4.5.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_calib3d.4.5.3.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_imgproc.4.5.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_features2d.4.5.3.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_core.4.5.3.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_flann.4.5.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_calib3d.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_objdetect.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_imgproc.4.5.3.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_flann.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_imgproc.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_flann.4.5.3.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_features2d.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_core.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_objdetect.4.5.dylib</string>
<key>PATH_TYPE</key>
<integer>3</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>
<key>PATH</key>
<string>adv-ss-plugins</string>
<key>PATH_TYPE</key>
<integer>0</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>2</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
@@ -46,310 +367,6 @@
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../../../../build/UI/frontend-plugins/SceneSwitcher/src/external-macro-modules/opencv/advanced-scene-switcher-opencv.so</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_objdetect.4.5.3.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_features2d.4.5.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_core.4.5.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_calib3d.4.5.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_calib3d.4.5.3.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_imgproc.4.5.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_features2d.4.5.3.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_core.4.5.3.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_flann.4.5.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_calib3d.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_objdetect.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_imgproc.4.5.3.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_flann.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_imgproc.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_flann.4.5.3.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_features2d.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_core.dylib</string>
<key>PATH_TYPE</key>
<integer>3</integer>
<key>PERMISSIONS</key>
<integer>493</integer>
<key>TYPE</key>
<integer>3</integer>
<key>UID</key>
<integer>0</integer>
</dict>
<dict>
<key>CHILDREN</key>
<array/>
<key>GID</key>
<integer>80</integer>
<key>PATH</key>
<string>../../deps/opencv/build/lib/libopencv_objdetect.4.5.dylib</string>
<key>PATH_TYPE</key>
<integer>3</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

@@ -14,7 +14,7 @@ AppVersion={#MyAppVersion}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={code:GetDirName}
DefaultDirName={code:GetDefaultDirectory}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
; Uncomment the following line to run in non administrative install mode (install for current user only.)
@@ -38,18 +38,18 @@ Source: "@ISS_PLUGIN_FILES_DIR@\*"; DestDir: "{app}"; Flags: ignoreversion recur
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"
[Code]
// credit where it's due:
// following function comes from https://github.com/Xaymar/obs-studio_amf-encoder-plugin/blob/master/%23Resources/Installer.in.iss#L45
function GetDirName(Value: string): string;
function GetDefaultDirectory(Value: String): String;
var
InstallPath: string;
sInstallPath: String;
begin
// initialize default path, which will be returned when the following registry
// key queries fail due to missing keys or for some different reason
Result := ExpandConstant('{pf}\obs-studio');
// query the first registry value; if this succeeds, return the obtained value
if RegQueryStringValue(HKLM32, 'SOFTWARE\OBS Studio', '', InstallPath) then
Result := InstallPath
sInstallPath := Value;
if (sInstallPath = '') then
RegQueryStringValue(HKLM64, 'SOFTWARE\OBS Studio', '', sInstallPath);
if (sInstallPath = '') then
RegQueryStringValue(HKCU64, 'SOFTWARE\OBS Studio', '', sInstallPath);
if (sInstallPath = '') then
sInstallPath := ExpandConstant('{commonpf}\obs-studio');
Result := sInstallPath
end;
procedure CurStepChanged(CurStep: TSetupStep);

View File

@@ -211,6 +211,7 @@ set(advanced-scene-switcher_HEADERS
src/headers/macro-action-scene-transform.hpp
src/headers/macro-action-scene-visibility.hpp
src/headers/macro-action-screenshot.hpp
src/headers/macro-action-sequence.hpp
src/headers/macro-action-source.hpp
src/headers/macro-action-streaming.hpp
src/headers/macro-action-systray.hpp
@@ -257,7 +258,7 @@ set(advanced-scene-switcher_HEADERS
src/headers/duration-control.hpp
src/headers/file-selection.hpp
src/headers/section.hpp
src/headers/status-dock.hpp
src/headers/status-control.hpp
src/headers/platform-funcs.hpp
src/headers/utility.hpp
src/headers/volume-control.hpp
@@ -310,6 +311,7 @@ set(advanced-scene-switcher_SOURCES
src/macro-action-scene-transform.cpp
src/macro-action-scene-visibility.cpp
src/macro-action-screenshot.cpp
src/macro-action-sequence.cpp
src/macro-action-source.cpp
src/macro-action-streaming.cpp
src/macro-action-systray.cpp
@@ -354,7 +356,7 @@ set(advanced-scene-switcher_SOURCES
src/transition-selection.cpp
src/name-dialog.cpp
src/duration-control.cpp
src/status-dock.cpp
src/status-control.cpp
src/section.cpp
src/utility.cpp
src/volume-control.cpp

View File

@@ -70,6 +70,7 @@ AdvSceneSwitcher.macroTab.name="Name:"
AdvSceneSwitcher.macroTab.run="Run macro"
AdvSceneSwitcher.macroTab.runFail="Running \"%1\" failed!\nEither one of the actions failed or the macro is running already."
AdvSceneSwitcher.macroTab.runInParallel="Run macro in parallel to other macros"
AdvSceneSwitcher.macroTab.onChange="Perform actions only on condition change"
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
AdvSceneSwitcher.macroTab.exists="Macro name exists already"
AdvSceneSwitcher.macroTab.copy="Create copy"
@@ -88,10 +89,13 @@ AdvSceneSwitcher.logic.not="If not"
; Macro Conditions
AdvSceneSwitcher.condition.audio="Audio"
AdvSceneSwitcher.condition.audio.state.below="below"
AdvSceneSwitcher.condition.audio.state.exact="exactly"
AdvSceneSwitcher.condition.audio.state.above="above"
AdvSceneSwitcher.condition.audio.state.mute="muted"
AdvSceneSwitcher.condition.audio.state.unmute="unmuted"
AdvSceneSwitcher.condition.audio.entry="Volume of {{audioSources}} is {{condition}} {{volume}}"
AdvSceneSwitcher.condition.audio.type.output="Output volume"
AdvSceneSwitcher.condition.audio.type.volume="Configured volume level"
AdvSceneSwitcher.condition.audio.entry="{{checkType}} of {{audioSources}} is {{condition}} {{volume}}"
AdvSceneSwitcher.condition.cursor="Cursor"
AdvSceneSwitcher.condition.cursor.type.region="is in region"
AdvSceneSwitcher.condition.cursor.type.moving="is moving"
@@ -104,8 +108,9 @@ AdvSceneSwitcher.condition.scene.type.current="Current scene is"
AdvSceneSwitcher.condition.scene.type.previous="Previous scene is"
AdvSceneSwitcher.condition.scene.type.changed="Scene changed"
AdvSceneSwitcher.condition.scene.type.notChanged="Scene has not changed"
AdvSceneSwitcher.condition.scene.waitForTransition="Wait for transition to complete"
AdvSceneSwitcher.condition.scene.entry="{{sceneType}} {{scenes}} {{waitForTransition}}"
AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour="During transition check for transition target scene"
AdvSceneSwitcher.condition.scene.entry.line1="{{sceneType}} {{scenes}}"
AdvSceneSwitcher.condition.scene.entry.line2="{{useTransitionTargetScene}}"
AdvSceneSwitcher.condition.window="Window"
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} exist and ..."
AdvSceneSwitcher.condition.window.entry.line2="... is {{fullscreen}} fullscreen {{maximized}} maximized {{focused}} focused {{windowFocusChanged}} foreground window changed"
@@ -220,7 +225,8 @@ AdvSceneSwitcher.condition.sceneOrder.entry="On{{scenes}}{{sources}}{{conditions
AdvSceneSwitcher.condition.hotkey="Hotkey"
AdvSceneSwitcher.condition.hotkey.name="Macro trigger hotkey"
AdvSceneSwitcher.condition.hotkey.tip="Note: You can configure the keybindings for this hotkey in the OBS settings window"
AdvSceneSwitcher.condition.hotkey.entry="Name: {{name}}"
AdvSceneSwitcher.condition.hotkey.entry.line1="Hotkey is pressed"
AdvSceneSwitcher.condition.hotkey.entry.line2="Name: {{name}}"
AdvSceneSwitcher.condition.replay="Replay buffer"
AdvSceneSwitcher.condition.replay.state.stopped="Replay buffer stopped"
AdvSceneSwitcher.condition.replay.state.started="Replay buffer started"
@@ -332,6 +338,7 @@ AdvSceneSwitcher.action.macro.type.pause="Pause"
AdvSceneSwitcher.action.macro.type.unpause="Unpause"
AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter"
AdvSceneSwitcher.action.macro.type.run="Run"
AdvSceneSwitcher.action.macro.type.stop="Stop"
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
AdvSceneSwitcher.action.pluginState="Plugin state"
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
@@ -394,6 +401,12 @@ AdvSceneSwitcher.action.profile.entry="Switch active profile to {{profiles}}"
AdvSceneSwitcher.action.sceneCollection="Scene collection"
AdvSceneSwitcher.action.sceneCollection.entry="Switch active scene collection to {{sceneCollections}}"
AdvSceneSwitcher.action.sceneCollection.warning="Note: Any actions following after this will not be executed as the changing scene collection will also reload the scene switcher settings.\nThe scene collection action will be ignored while the settings window is opened."
AdvSceneSwitcher.action.sequence="Sequence"
AdvSceneSwitcher.action.sequence.entry="Each time this action is performed run the next macro in the list (paused macros are ignored)"
AdvSceneSwitcher.action.sequence.status="Last executed macro: %1 - Next macro to be executed: %2"
AdvSceneSwitcher.action.sequence.status.none="none"
AdvSceneSwitcher.action.sequence.restart="Restart from beginning once end of list is reached"
AdvSceneSwitcher.action.sequence.continueFrom="Continue with selected item"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="Transition"

View File

@@ -56,10 +56,30 @@
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_2">
<layout class="QGridLayout" name="statusLayout">
<item row="4" column="1">
<widget class="QComboBox" name="autoStartEvent"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_64">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.onStartup</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="startupBehavior"/>
</item>
<item row="1" column="0">
<widget class="QWidget" name="placeholder" native="true"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.autoStart</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="checkInterval">
<property name="minimumSize">
@@ -82,6 +102,13 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.hotkeytips</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
@@ -90,66 +117,10 @@
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="toggleStartButton">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.start</string>
</property>
</widget>
<widget class="QWidget" name="placeholder2" native="true"/>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_47">
<item>
<widget class="QLabel" name="pluginRunningText">
<property name="text">
<string>AdvSceneSwitcher.status.inactive</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.hotkeytips</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_64">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.onStartup</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.currentStatus</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.autoStart</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="autoStartEvent"/>
<widget class="QWidget" name="placeholder3" native="true"/>
</item>
</layout>
</item>
@@ -550,6 +521,9 @@
<property name="text">
<string>AdvSceneSwitcher.macroTab.priorityWarning</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
@@ -729,7 +703,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_34">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0,0,0">
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="0,0,0,0,0,0">
<item>
<widget class="QLabel" name="label_20">
<property name="text">
@@ -754,6 +728,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="runMacroOnChange">
<property name="text">
<string>AdvSceneSwitcher.macroTab.onChange</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_13">
<property name="orientation">
@@ -783,7 +764,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>767</width>
<width>792</width>
<height>218</height>
</rect>
</property>
@@ -882,7 +863,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>767</width>
<width>792</width>
<height>218</height>
</rect>
</property>

View File

@@ -9,7 +9,7 @@
#include <obs-frontend-api.h>
#include "headers/advanced-scene-switcher.hpp"
#include "headers/status-dock.hpp"
#include "headers/status-control.hpp"
#include "headers/curl-helper.hpp"
#include "headers/utility.hpp"
#include "headers/version.h"
@@ -626,20 +626,28 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
void LoadPlugins()
{
QFileInfo fi(obs_get_module_binary_path(obs_current_module()));
QDirIterator it(fi.absolutePath(), QStringList() << "*.so",
QDir::Files);
QFileInfo libPath(
QString(obs_get_module_binary_path(obs_current_module())));
QString pluginDir(libPath.absolutePath() + "/adv-ss-plugins");
#ifdef _WIN32
QString libPattern = "*.dll";
SetDllDirectory(pluginDir.toStdWString().c_str());
#else
QString libPattern = "*.so";
#endif
QDirIterator it(pluginDir, QStringList() << libPattern, QDir::Files);
while (it.hasNext()) {
auto file = it.next();
if (it.fileName() == "advanced-scene-switcher.so") {
continue;
}
blog(LOG_INFO, "attempting to load \"%s\"",
file.toStdString().c_str());
auto lib = new QLibrary(file, nullptr);
if (lib->load()) {
blog(LOG_INFO, "successfully loaded \"%s\"",
file.toStdString().c_str());
} else {
blog(LOG_WARNING, "failed to load \"%s\": %s",
file.toStdString().c_str(),
lib->errorString().toStdString().c_str());
}
}
}
@@ -658,14 +666,8 @@ extern "C" void InitSceneSwitcher()
}
PlatformInit();
#if !defined(_WIN32)
// Windows does not require the plugins to be loaded manually
LoadPlugins();
#endif
dock = new StatusDock(
static_cast<QMainWindow *>(obs_frontend_get_main_window()));
obs_frontend_add_dock(dock);
SetupDock();
auto cb = []() {
if (switcher->settingsWindowOpened) {

View File

@@ -1,3 +1,57 @@
# Helper function to install plugins to correct location
function(install_advss_plugin target)
set(plugin_folder "adv-ss-plugins")
if(APPLE)
set(_bit_suffix "")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_bit_suffix "64bit/")
else()
set(_bit_suffix "32bit/")
endif()
set_target_properties(${target} PROPERTIES PREFIX "")
install(
TARGETS ${target}
LIBRARY DESTINATION "${OBS_PLUGIN_DESTINATION}/${plugin_folder}"
RUNTIME DESTINATION "${OBS_PLUGIN_DESTINATION}/${plugin_folder}")
add_custom_command(
TARGET ${target}
POST_BUILD
COMMAND
"${CMAKE_COMMAND}" -E copy "$<TARGET_FILE:${target}>"
"${OBS_OUTPUT_DIR}/$<CONFIGURATION>/obs-plugins/${_bit_suffix}/${plugin_folder}/$<TARGET_FILE_NAME:${target}>"
VERBATIM)
if(DEFINED ENV{obsInstallerTempDir})
add_custom_command(
TARGET ${target}
POST_BUILD
COMMAND
"${CMAKE_COMMAND}" -E copy "$<TARGET_FILE:${target}>"
"$ENV{obsInstallerTempDir}/${OBS_PLUGIN_DESTINATION}/${plugin_folder}/$<TARGET_FILE_NAME:${target}>"
VERBATIM)
endif()
if(MSVC)
obs_debug_copy_helper(
${target}
"${OBS_OUTPUT_DIR}/$<CONFIGURATION>/obs-plugins/${_bit_suffix}/${plugin_folder}"
)
if(DEFINED ENV{obsInstallerTempDir})
obs_debug_copy_helper(
${target}
"$ENV{obsInstallerTempDir}/${OBS_PLUGIN_DESTINATION}/${plugin_folder}")
endif()
install(
DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/pdbs/"
DESTINATION "${OBS_PLUGIN_DESTINATION}/${plugin_folder}"
CONFIGURATIONS Debug RelWithDebInfo)
endif()
endfunction()
# Add macro conditions or actions which have dependencies to external libraries
# or other components which might potentially not be fulfilled by the user and
# thus cause issues.

View File

@@ -34,8 +34,9 @@ if(BUILD_OUT_OF_TREE)
set(LIB_OUT_DIR "/lib/obs-plugins")
endif()
set_target_properties(advanced-scene-switcher-opencv PROPERTIES PREFIX "")
install(TARGETS advanced-scene-switcher-opencv
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${LIB_OUT_DIR})
install(
TARGETS advanced-scene-switcher-opencv
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${LIB_OUT_DIR}/adv-ss-plugins)
endif()
else()
target_link_libraries(
@@ -46,5 +47,5 @@ else()
Qt5::Core
Qt5::Widgets
libobs)
install_obs_plugin(advanced-scene-switcher-opencv)
install_advss_plugin(advanced-scene-switcher-opencv)
endif()

View File

@@ -32,15 +32,16 @@ constexpr int maxMinNeighbors = 6;
class MacroConditionVideo : public MacroCondition {
public:
MacroConditionVideo(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
QImage GetMatchImage() { return _matchImage; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionVideo>();
return std::make_shared<MacroConditionVideo>(m);
}
void GetScreenshot();
bool LoadImageFromFile();

View File

@@ -73,8 +73,9 @@ if(BUILD_OUT_OF_TREE)
set(LIB_OUT_DIR "/lib/obs-plugins")
endif()
set_target_properties(advanced-scene-switcher-openvr PROPERTIES PREFIX "")
install(TARGETS advanced-scene-switcher-openvr
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${LIB_OUT_DIR})
install(
TARGETS advanced-scene-switcher-openvr
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${LIB_OUT_DIR}/adv-ss-plugins)
endif()
else()
target_link_libraries(
@@ -85,5 +86,5 @@ else()
Qt5::Core
Qt5::Widgets
libobs)
install_obs_plugin(advanced-scene-switcher-openvr)
install_advss_plugin(advanced-scene-switcher-openvr)
endif()

View File

@@ -8,13 +8,14 @@
class MacroConditionOpenVR : public MacroCondition {
public:
MacroConditionOpenVR(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionOpenVR>();
return std::make_shared<MacroConditionOpenVR>(m);
}
double _minX = 0, _minY = 0, _minZ = 0, _maxX = 0, _maxY = 0, _maxZ = 0;

View File

@@ -1,13 +1,11 @@
#include "headers/advanced-scene-switcher.hpp"
#include "headers/status-dock.hpp"
#include "headers/status-control.hpp"
#include "headers/utility.hpp"
#include "headers/version.h"
#include <QFileDialog>
#include <QStandardPaths>
QMetaObject::Connection inactivePluse;
void AdvSceneSwitcher::on_close_clicked()
{
close();
@@ -147,41 +145,6 @@ void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
switcher->interval = value;
}
void AdvSceneSwitcher::SetStarted()
{
ui->toggleStartButton->setText(
obs_module_text("AdvSceneSwitcher.generalTab.status.stop"));
ui->pluginRunningText->setText(
obs_module_text("AdvSceneSwitcher.status.active"));
ui->pluginRunningText->disconnect(inactivePluse);
currentStatusActive = true;
}
void AdvSceneSwitcher::SetStopped()
{
ui->toggleStartButton->setText(
obs_module_text("AdvSceneSwitcher.generalTab.status.start"));
ui->pluginRunningText->setText(
obs_module_text("AdvSceneSwitcher.status.inactive"));
if (!switcher->disableHints) {
inactivePluse = PulseWidget(ui->pluginRunningText,
QColor(Qt::red), QColor(0, 0, 0, 0),
"QLabel ");
}
currentStatusActive = false;
}
void AdvSceneSwitcher::on_toggleStartButton_clicked()
{
if (switcher->th && switcher->th->isRunning()) {
switcher->Stop();
SetStopped();
} else {
switcher->Start();
SetStarted();
}
}
void AdvSceneSwitcher::closeEvent(QCloseEvent *)
{
if (!switcher) {
@@ -493,7 +456,6 @@ void SwitcherData::loadSettings(obs_data_t *obj)
loadSceneTriggers(obj);
loadGeneralSettings(obj);
loadHotkeys(obj);
loadDock(obj);
}
void SwitcherData::saveSettings(obs_data_t *obj)
@@ -524,7 +486,6 @@ void SwitcherData::saveSettings(obs_data_t *obj)
saveSceneTriggers(obj);
saveGeneralSettings(obj);
saveHotkeys(obj);
saveDock(obj);
saveVersion(obj, g_GIT_SHA1);
}
@@ -791,21 +752,6 @@ void populateAutoStartEventSelection(QComboBox *cb)
"AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming"));
}
void AdvSceneSwitcher::updateStatus()
{
if (switcher->th && switcher->th->isRunning()) {
if (currentStatusActive) {
return;
}
SetStarted();
} else {
if (!currentStatusActive) {
return;
}
SetStopped();
}
}
void AdvSceneSwitcher::setupGeneralTab()
{
populateSceneSelection(ui->noMatchSwitchScene, false);
@@ -926,17 +872,17 @@ void AdvSceneSwitcher::setupGeneralTab()
ui->autoStartEvent->setCurrentIndex(
static_cast<int>(switcher->autoStartEvent));
if (switcher->th && switcher->th->isRunning()) {
SetStarted();
} else {
SetStopped();
}
// Updates the UI status element if the status changed externally
// (e.g. via hotkeys)
QTimer *statusTimer = new QTimer(this);
connect(statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
statusTimer->start(1000);
// Set up status control
auto statusControl = new StatusControl(this, true);
ui->statusLayout->addWidget(statusControl->StatusPrefixLabel(), 1, 0);
auto tmp = new QHBoxLayout;
tmp->addWidget(statusControl->StatusLabel());
tmp->addStretch();
ui->statusLayout->addLayout(tmp, 1, 1);
ui->statusLayout->addWidget(statusControl->Button(), 2, 1);
// Hide the now empty invisible shell of the statusControl widget
// as otherwise it could block user input
statusControl->hide();
setWindowTitle(windowTitle() + " - " + g_GIT_TAG);
}

View File

@@ -28,7 +28,6 @@ class AdvSceneSwitcher : public QDialog {
public:
std::unique_ptr<Ui_AdvSceneSwitcher> ui;
bool loading = true;
bool currentStatusActive = false;
AdvSceneSwitcher(QWidget *parent);
~AdvSceneSwitcher();
@@ -36,9 +35,6 @@ public:
void reject() override;
void closeEvent(QCloseEvent *event) override;
void SetStarted();
void SetStopped();
void SetShowFrames();
void SetHideFrames();
void clearFrames(QListWidget *list);
@@ -109,7 +105,6 @@ public slots:
void on_autoStartEvent_currentIndexChanged(int index);
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
void on_checkInterval_valueChanged(int value);
void on_toggleStartButton_clicked();
void on_tabMoved(int from, int to);
void on_tabWidget_currentChanged(int index);
@@ -120,6 +115,7 @@ public slots:
void on_macroName_editingFinished();
void on_runMacro_clicked();
void on_runMacroInParallel_stateChanged(int value);
void on_runMacroOnChange_stateChanged(int value);
void on_macros_currentRowChanged(int idx);
void on_macros_itemChanged(QListWidgetItem *);
void on_conditionAdd_clicked();
@@ -271,7 +267,6 @@ public slots:
void on_threadPriority_currentTextChanged(const QString &text);
void updateScreenRegionCursorPos();
void updateStatus();
void on_close_clicked();

View File

@@ -42,6 +42,7 @@ public:
void SetValue(double value);
void SetUnit(DurationUnit u);
void SetDuration(Duration d);
QDoubleSpinBox *SpinBox() { return _duration; }
private slots:
void _DurationChanged(double value);

View File

@@ -15,15 +15,16 @@ enum class AudioAction {
class MacroActionAudio : public MacroAction {
public:
MacroActionAudio(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionAudio>();
return std::make_shared<MacroActionAudio>(m);
}
OBSWeakSource _audioSource;

View File

@@ -2,7 +2,7 @@
#include "macro.hpp"
struct MacroActionInfo {
using TCreateMethod = std::shared_ptr<MacroAction> (*)();
using TCreateMethod = std::shared_ptr<MacroAction> (*)(Macro *m);
using TCreateWidgetMethod = QWidget *(*)(QWidget *parent,
std::shared_ptr<MacroAction>);
TCreateMethod _createFunc = nullptr;
@@ -14,7 +14,8 @@ class MacroActionFactory {
public:
MacroActionFactory() = delete;
static bool Register(const std::string &id, MacroActionInfo);
static std::shared_ptr<MacroAction> Create(const std::string &id);
static std::shared_ptr<MacroAction> Create(const std::string &id,
Macro *m);
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
std::shared_ptr<MacroAction> action);
static auto GetActionTypes() { return _methods; }

View File

@@ -11,15 +11,16 @@ enum class FileAction {
class MacroActionFile : public MacroAction {
public:
MacroActionFile(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionFile>();
return std::make_shared<MacroActionFile>(m);
}
std::string _file = obs_module_text("AdvSceneSwitcher.enterPath");

View File

@@ -11,15 +11,16 @@ enum class FilterAction {
class MacroActionFilter : public MacroAction {
public:
MacroActionFilter(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionFilter>();
return std::make_shared<MacroActionFilter>(m);
}
OBSWeakSource _source;

View File

@@ -8,14 +8,15 @@
class MacroActionHotkey : public MacroAction {
public:
MacroActionHotkey(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionHotkey>();
return std::make_shared<MacroActionHotkey>(m);
}
OBSWeakSource _HotkeySource;

View File

@@ -9,19 +9,21 @@ enum class PerformMacroAction {
UNPAUSE,
RESET_COUNTER,
RUN,
STOP,
};
class MacroActionMacro : public MacroRefAction {
public:
MacroActionMacro(Macro *m) : MacroRefAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionMacro>();
return std::make_shared<MacroActionMacro>(m);
}
PerformMacroAction _action = PerformMacroAction::PAUSE;

View File

@@ -15,15 +15,16 @@ enum class MediaAction {
class MacroActionMedia : public MacroAction {
public:
MacroActionMedia(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionMedia>();
return std::make_shared<MacroActionMedia>(m);
}
OBSWeakSource _mediaSource;

View File

@@ -13,14 +13,15 @@ enum class PluginStateAction {
class MacroActionPluginState : public MacroAction {
public:
MacroActionPluginState(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionPluginState>();
return std::make_shared<MacroActionPluginState>(m);
}
PluginStateAction _action = PluginStateAction::STOP;

View File

@@ -4,15 +4,16 @@
class MacroActionPreviewScene : public MacroAction {
public:
MacroActionPreviewScene(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionPreviewScene>();
return std::make_shared<MacroActionPreviewScene>(m);
}
SceneSelection _scene;

View File

@@ -3,15 +3,16 @@
class MacroActionProfile : public MacroAction {
public:
MacroActionProfile(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionProfile>();
return std::make_shared<MacroActionProfile>(m);
}
std::string _profile;

View File

@@ -4,19 +4,19 @@
#include <QPushButton>
#include <QListWidget>
#include <QDialog>
#include <unordered_map>
class MacroActionRandom : public MultiMacroRefAction {
public:
MacroActionRandom(Macro *m) : MultiMacroRefAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionRandom>();
return std::make_shared<MacroActionRandom>(m);
}
// TODO: add weights to each macro ...
@@ -28,17 +28,6 @@ private:
static const std::string id;
};
class MacroDialog : public QDialog {
Q_OBJECT
public:
MacroDialog(QWidget *parent);
static bool AskForMacro(QWidget *parent, std::string &macroName);
private:
MacroSelection *_macroSelection;
};
class MacroActionRandomEdit : public QWidget {
Q_OBJECT

View File

@@ -13,14 +13,15 @@ enum class RecordAction {
class MacroActionRecord : public MacroAction {
public:
MacroActionRecord(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionRecord>();
return std::make_shared<MacroActionRecord>(m);
}
RecordAction _action = RecordAction::STOP;

View File

@@ -14,14 +14,15 @@ enum class ReplayBufferAction {
class MacroActionReplayBuffer : public MacroAction {
public:
MacroActionReplayBuffer(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionReplayBuffer>();
return std::make_shared<MacroActionReplayBuffer>(m);
}
ReplayBufferAction _action = ReplayBufferAction::STOP;

View File

@@ -9,15 +9,16 @@
class MacroActionRun : public MacroAction {
public:
MacroActionRun(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionRun>();
return std::make_shared<MacroActionRun>(m);
}
std::string _path = obs_module_text("AdvSceneSwitcher.enterPath");

View File

@@ -3,15 +3,16 @@
class MacroActionSceneCollection : public MacroAction {
public:
MacroActionSceneCollection(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSceneCollection>();
return std::make_shared<MacroActionSceneCollection>(m);
}
std::string _sceneCollection;

View File

@@ -15,15 +15,16 @@ enum class SceneOrderAction {
class MacroActionSceneOrder : public MacroAction {
public:
MacroActionSceneOrder(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSceneOrder>();
return std::make_shared<MacroActionSceneOrder>(m);
}
SceneSelection _scene;

View File

@@ -3,14 +3,15 @@
class MacroActionSceneSwap : public MacroAction {
public:
MacroActionSceneSwap(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSceneSwap>();
return std::make_shared<MacroActionSceneSwap>(m);
}
private:

View File

@@ -8,6 +8,7 @@
class MacroActionSwitchScene : public MacroAction {
public:
MacroActionSwitchScene(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
@@ -15,9 +16,9 @@ public:
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSwitchScene>();
return std::make_shared<MacroActionSwitchScene>(m);
}
SceneSelection _scene;
TransitionSelection _transition;

View File

@@ -8,15 +8,16 @@
class MacroActionSceneTransform : public MacroAction {
public:
MacroActionSceneTransform(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSceneTransform>();
return std::make_shared<MacroActionSceneTransform>(m);
}
std::string GetSettings();
void SetSettings(std::string &);

View File

@@ -17,15 +17,16 @@ enum class SceneItemSourceType {
class MacroActionSceneVisibility : public MacroAction {
public:
MacroActionSceneVisibility(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSceneVisibility>();
return std::make_shared<MacroActionSceneVisibility>(m);
}
SceneSelection _scene;

View File

@@ -3,15 +3,16 @@
class MacroActionScreenshot : public MacroAction {
public:
MacroActionScreenshot(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionScreenshot>();
return std::make_shared<MacroActionScreenshot>(m);
}
OBSWeakSource _source;

View File

@@ -0,0 +1,77 @@
#pragma once
#include "macro-action-edit.hpp"
#include "macro-selection.hpp"
#include <QPushButton>
#include <QListWidget>
#include <QCheckBox>
#include <QTimer>
class MacroActionSequence : public MultiMacroRefAction {
public:
MacroActionSequence(Macro *m) : MultiMacroRefAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
MacroRef GetNextMacro(bool advance = true);
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSequence>(m);
}
bool _restart = true;
MacroRef _lastSequenceMacro;
int _lastIdx = -1;
private:
static bool _registered;
static const std::string id;
};
class MacroActionSequenceEdit : public QWidget {
Q_OBJECT
public:
MacroActionSequenceEdit(
QWidget *parent,
std::shared_ptr<MacroActionSequence> entryData = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionSequenceEdit(
parent,
std::dynamic_pointer_cast<MacroActionSequence>(action));
}
private slots:
void MacroRemove(const QString &name);
void MacroRename(const QString &oldName, const QString &newName);
void Add();
void Remove();
void Up();
void Down();
void ContinueFromClicked();
void RestartChanged(int state);
void UpdateStatusLine();
protected:
std::shared_ptr<MacroActionSequence> _entryData;
private:
int FindEntry(const std::string &macro);
void SetMacroListSize();
QListWidget *_macroList;
QPushButton *_add;
QPushButton *_remove;
QPushButton *_up;
QPushButton *_down;
QPushButton *_continueFrom;
QCheckBox *_restart;
QLabel *_statusLine;
QTimer _statusTimer;
bool _loading = true;
};

View File

@@ -14,15 +14,16 @@ enum class SourceAction {
class MacroActionSource : public MacroAction {
public:
MacroActionSource(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSource>();
return std::make_shared<MacroActionSource>(m);
}
OBSWeakSource _source;

View File

@@ -13,14 +13,15 @@ enum class StreamAction {
class MacroActionStream : public MacroAction {
public:
MacroActionStream(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionStream>();
return std::make_shared<MacroActionStream>(m);
}
StreamAction _action = StreamAction::STOP;

View File

@@ -5,14 +5,15 @@
class MacroActionSystray : public MacroAction {
public:
MacroActionSystray(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSystray>();
return std::make_shared<MacroActionSystray>(m);
}
std::string _msg = "";

View File

@@ -15,15 +15,16 @@ enum class TimerAction {
class MacroActionTimer : public MacroRefAction {
public:
MacroActionTimer(Macro *m) : MacroRefAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionTimer>();
return std::make_shared<MacroActionTimer>(m);
}
Duration _duration;
TimerAction _actionType = TimerAction::PAUSE;

View File

@@ -8,15 +8,16 @@
class MacroActionTransition : public MacroAction {
public:
MacroActionTransition(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionTransition>();
return std::make_shared<MacroActionTransition>(m);
}
bool _setDuration = true;

View File

@@ -13,14 +13,15 @@ enum class VCamAction {
class MacroActionVCam : public MacroAction {
public:
MacroActionVCam(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionVCam>();
return std::make_shared<MacroActionVCam>(m);
}
VCamAction _action = VCamAction::STOP;

View File

@@ -12,13 +12,14 @@ enum class WaitType {
class MacroActionWait : public MacroAction {
public:
MacroActionWait(Macro *m) : MacroAction(m) {}
bool PerformAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionWait>();
return std::make_shared<MacroActionWait>(m);
}
Duration _duration;
Duration _duration2;

View File

@@ -6,24 +6,39 @@
#include <QComboBox>
#include <chrono>
enum class AudioCondition {
enum class AudioConditionCheckType {
OUTPUT_VOLUME,
CONFIGURED_VOLUME,
};
enum class AudioOutputCondition {
ABOVE,
BELOW,
// TODO: To be removed
MUTE,
UNMUTE,
};
enum class AudioVolumeCondition {
ABOVE,
EXACT,
BELOW,
MUTE,
UNMUTE,
};
class MacroConditionAudio : public MacroCondition {
public:
MacroConditionAudio(Macro *m) : MacroCondition(m) {}
~MacroConditionAudio();
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionAudio>();
return std::make_shared<MacroConditionAudio>(m);
}
static void SetVolumeLevel(void *data,
const float magnitude[MAX_AUDIO_CHANNELS],
@@ -33,10 +48,16 @@ public:
OBSWeakSource _audioSource;
int _volume = 0;
AudioCondition _condition = AudioCondition::ABOVE;
AudioConditionCheckType _checkType =
AudioConditionCheckType::OUTPUT_VOLUME;
AudioOutputCondition _outputCondition = AudioOutputCondition::ABOVE;
AudioVolumeCondition _volumeCondition = AudioVolumeCondition::ABOVE;
obs_volmeter_t *_volmeter = nullptr;
private:
bool CheckOutputCondition();
bool CheckVolumeCondition();
float _peak = -std::numeric_limits<float>::infinity();
static bool _registered;
static const std::string id;
@@ -63,10 +84,13 @@ private slots:
void SourceChanged(const QString &text);
void VolumeThresholdChanged(int vol);
void ConditionChanged(int cond);
void CheckTypeChanged(int cond);
signals:
void HeaderInfoChanged(const QString &);
protected:
QComboBox *_checkTypes;
QComboBox *_audioSources;
QComboBox *_condition;
QSpinBox *_volume;

View File

@@ -14,13 +14,14 @@ enum class CursorCondition {
class MacroConditionCursor : public MacroCondition {
public:
MacroConditionCursor(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionCursor>();
return std::make_shared<MacroConditionCursor>(m);
}
CursorCondition _condition = CursorCondition::REGION;

View File

@@ -15,14 +15,15 @@ enum class DateCondition {
class MacroConditionDate : public MacroCondition {
public:
MacroConditionDate(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionDate>();
return std::make_shared<MacroConditionDate>(m);
}
QDateTime _dateTime;

View File

@@ -2,7 +2,7 @@
#include "macro.hpp"
struct MacroConditionInfo {
using TCreateMethod = std::shared_ptr<MacroCondition> (*)();
using TCreateMethod = std::shared_ptr<MacroCondition> (*)(Macro *m);
using TCreateWidgetMethod =
QWidget *(*)(QWidget *parent, std::shared_ptr<MacroCondition>);
TCreateMethod _createFunc = nullptr;
@@ -15,7 +15,8 @@ class MacroConditionFactory {
public:
MacroConditionFactory() = delete;
static bool Register(const std::string &, MacroConditionInfo);
static std::shared_ptr<MacroCondition> Create(const std::string &);
static std::shared_ptr<MacroCondition> Create(const std::string &,
Macro *m);
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
std::shared_ptr<MacroCondition>);
static auto GetConditionTypes() { return _methods; }

View File

@@ -17,14 +17,15 @@ enum class FileType {
class MacroConditionFile : public MacroCondition {
public:
MacroConditionFile(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionFile>();
return std::make_shared<MacroConditionFile>(m);
}
std::string _file = obs_module_text("AdvSceneSwitcher.enterPath");

View File

@@ -14,14 +14,15 @@ enum class FilterCondition {
class MacroConditionFilter : public MacroCondition {
public:
MacroConditionFilter(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionFilter>();
return std::make_shared<MacroConditionFilter>(m);
}
OBSWeakSource _source;

View File

@@ -5,15 +5,15 @@
class MacroConditionHotkey : public MacroCondition {
public:
MacroConditionHotkey();
MacroConditionHotkey(Macro *m);
~MacroConditionHotkey();
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionHotkey>();
return std::make_shared<MacroConditionHotkey>(m);
}
void SetPressed() { _pressed = true; }

View File

@@ -7,13 +7,14 @@
class MacroConditionIdle : public MacroCondition {
public:
MacroConditionIdle(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionIdle>();
return std::make_shared<MacroConditionIdle>(m);
}
Duration _duration;

View File

@@ -21,14 +21,15 @@ enum class CounterCondition {
class MacroConditionMacro : public MacroRefCondition {
public:
MacroConditionMacro(Macro *m) : MacroRefCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionMacro>();
return std::make_shared<MacroConditionMacro>(m);
}
MacroConditionMacroType _type = MacroConditionMacroType::STATE;

View File

@@ -43,15 +43,16 @@ enum class MediaSourceType {
class MacroConditionMedia : public MacroCondition {
public:
MacroConditionMedia(Macro *m) : MacroCondition(m) {}
~MacroConditionMedia();
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionMedia>();
return std::make_shared<MacroConditionMedia>(m);
}
void ClearSignalHandler();
void ResetSignalHandler();

View File

@@ -10,13 +10,14 @@ enum class PluginStateCondition {
class MacroConditionPluginState : public MacroCondition {
public:
MacroConditionPluginState(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionPluginState>();
return std::make_shared<MacroConditionPluginState>(m);
}
PluginStateCondition _condition = PluginStateCondition::SCENESWITCHED;

View File

@@ -6,14 +6,15 @@
class MacroConditionProcess : public MacroCondition {
public:
MacroConditionProcess(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionProcess>();
return std::make_shared<MacroConditionProcess>(m);
}
std::string _process;

View File

@@ -11,13 +11,14 @@ enum class RecordState {
class MacroConditionRecord : public MacroCondition {
public:
MacroConditionRecord(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionRecord>();
return std::make_shared<MacroConditionRecord>(m);
}
RecordState _recordState = RecordState::STOP;

View File

@@ -13,13 +13,14 @@ enum class ReplayBufferState {
class MacroConditionReplayBuffer : public MacroCondition {
public:
MacroConditionReplayBuffer(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionReplayBuffer>();
return std::make_shared<MacroConditionReplayBuffer>(m);
}
ReplayBufferState _state = ReplayBufferState::STOP;

View File

@@ -14,14 +14,15 @@ enum class SceneOrderCondition {
class MacroConditionSceneOrder : public MacroCondition {
public:
MacroConditionSceneOrder(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionSceneOrder>();
return std::make_shared<MacroConditionSceneOrder>(m);
}
SceneSelection _scene;

View File

@@ -9,14 +9,15 @@
class MacroConditionSceneTransform : public MacroCondition {
public:
MacroConditionSceneTransform(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionSceneTransform>();
return std::make_shared<MacroConditionSceneTransform>(m);
}
SceneSelection _scene;

View File

@@ -12,14 +12,15 @@ enum class SceneVisibilityCondition {
class MacroConditionSceneVisibility : public MacroCondition {
public:
MacroConditionSceneVisibility(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionSceneVisibility>();
return std::make_shared<MacroConditionSceneVisibility>(m);
}
SceneSelection _scene;

View File

@@ -15,22 +15,23 @@ enum class SceneType {
class MacroConditionScene : public MacroCondition {
public:
MacroConditionScene(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionScene>();
return std::make_shared<MacroConditionScene>(m);
}
// This option is to be removed in a future version and be replaced by
// transition specific conditions
bool _waitForTransition = true;
SceneSelection _scene;
SceneType _type = SceneType::CURRENT;
// During a transition "current" scene could either stand for the scene
// being transitioned to or the scene still being transitioned away
// from.
bool _useTransitionTargetScene = false;
private:
std::chrono::high_resolution_clock::time_point _lastSceneChangeTime{};
@@ -57,14 +58,14 @@ public:
private slots:
void SceneChanged(const SceneSelection &);
void TypeChanged(int value);
void WaitForTransitionChanged(int state);
void UseTransitionTargetSceneChanged(int state);
signals:
void HeaderInfoChanged(const QString &);
protected:
SceneSelectionWidget *_scenes;
QComboBox *_sceneType;
QCheckBox *_waitForTransition;
QCheckBox *_useTransitionTargetScene;
std::shared_ptr<MacroConditionScene> _entryData;
private:

View File

@@ -14,14 +14,15 @@ enum class SourceCondition {
class MacroConditionSource : public MacroCondition {
public:
MacroConditionSource(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionSource>();
return std::make_shared<MacroConditionSource>(m);
}
OBSWeakSource _source = nullptr;

View File

@@ -12,13 +12,14 @@ enum class StreamState {
class MacroConditionStream : public MacroCondition {
public:
MacroConditionStream(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionStream>();
return std::make_shared<MacroConditionStream>(m);
}
StreamState _streamState = StreamState::STOP;

View File

@@ -13,14 +13,15 @@ enum class StudioModeCondition {
class MacroConditionStudioMode : public MacroCondition {
public:
MacroConditionStudioMode(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionStudioMode>();
return std::make_shared<MacroConditionStudioMode>(m);
}
StudioModeCondition _condition =

View File

@@ -17,13 +17,14 @@ enum class TimerType {
class MacroConditionTimer : public MacroCondition {
public:
MacroConditionTimer(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionTimer>();
return std::make_shared<MacroConditionTimer>(m);
}
void Pause();
void Continue();

View File

@@ -18,14 +18,15 @@ enum class TransitionCondition {
class MacroConditionTransition : public MacroCondition {
public:
MacroConditionTransition(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionTransition>();
return std::make_shared<MacroConditionTransition>(m);
}
void ConnectToTransitionSignals();
void DisconnectTransitionSignals();

View File

@@ -12,13 +12,14 @@ enum class VCamState {
class MacroConditionVCam : public MacroCondition {
public:
MacroConditionVCam(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionVCam>();
return std::make_shared<MacroConditionVCam>(m);
}
VCamState _state = VCamState::STOP;

View File

@@ -6,14 +6,15 @@
class MacroConditionWindow : public MacroCondition {
public:
MacroConditionWindow(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionWindow>();
return std::make_shared<MacroConditionWindow>(m);
}
private:

View File

@@ -2,8 +2,12 @@
#include <QWidget>
#include <obs.hpp>
class Macro;
class MacroSegment {
public:
MacroSegment(Macro *m) : _macro(m) {}
Macro *GetMacro() { return _macro; }
void SetIndex(int idx) { _idx = idx; }
int GetIndex() { return _idx; }
void SetCollapsed(bool collapsed) { _collapsed = collapsed; }
@@ -16,6 +20,9 @@ public:
protected:
int _idx = 0;
bool _collapsed = false;
private:
Macro *_macro = nullptr;
};
class Section;

View File

@@ -1,5 +1,6 @@
#pragma once
#include <QComboBox>
#include <QDialog>
class Macro;
@@ -9,9 +10,22 @@ class MacroSelection : public QComboBox {
public:
MacroSelection(QWidget *parent);
void SetCurrentMacro(Macro *);
void HideSelectedMacro(); // Macro currently being edited
void ShowAllMacros();
private slots:
void MacroAdd(const QString &name);
void MacroRemove(const QString &name);
void MacroRename(const QString &oldName, const QString &newName);
};
class MacroSelectionDialog : public QDialog {
Q_OBJECT
public:
MacroSelectionDialog(QWidget *parent);
static bool AskForMacro(QWidget *parent, std::string &macroName);
private:
MacroSelection *_macroSelection;
};

View File

@@ -39,6 +39,7 @@ struct LogicTypeInfo {
class MacroCondition : public MacroSegment {
public:
MacroCondition(Macro *m) : MacroSegment(m) {}
virtual bool CheckCondition() = 0;
virtual bool Save(obs_data_t *obj) = 0;
virtual bool Load(obs_data_t *obj) = 0;
@@ -61,6 +62,7 @@ private:
class MacroAction : public MacroSegment {
public:
MacroAction(Macro *m) : MacroSegment(m) {}
virtual bool PerformAction() = 0;
virtual bool Save(obs_data_t *obj) = 0;
virtual bool Load(obs_data_t *obj) = 0;
@@ -82,8 +84,11 @@ public:
bool RunInParallel() { return _runInParallel; }
void SetPaused(bool pause = true);
bool Paused() { return _paused; }
void SetMatchOnChange(bool onChange) { _matchOnChange = onChange; }
bool MatchOnChange() { return _matchOnChange; }
int GetCount() { return _count; };
void ResetCount() { _count = 0; };
void Stop() { _stop = true; }
std::deque<std::shared_ptr<MacroCondition>> &Conditions()
{
return _conditions;
@@ -114,12 +119,15 @@ private:
std::deque<std::shared_ptr<MacroAction>> _actions;
bool _runInParallel = false;
bool _matched = false;
bool _lastMatched = false;
bool _matchOnChange = false;
bool _paused = false;
int _count = 0;
obs_hotkey_id _pauseHotkey = OBS_INVALID_HOTKEY_ID;
obs_hotkey_id _unpauseHotkey = OBS_INVALID_HOTKEY_ID;
obs_hotkey_id _togglePauseHotkey = OBS_INVALID_HOTKEY_ID;
bool _die = false;
bool _stop = false;
bool _done = true;
std::thread _thread;
@@ -147,18 +155,21 @@ private:
class MacroRefCondition : public MacroCondition {
public:
MacroRefCondition(Macro *m) : MacroCondition(m) {}
void ResolveMacroRef();
MacroRef _macro;
};
class MacroRefAction : public MacroAction {
public:
MacroRefAction(Macro *m) : MacroAction(m) {}
void ResolveMacroRef();
MacroRef _macro;
};
class MultiMacroRefAction : public MacroAction {
public:
MultiMacroRefAction(Macro *m) : MacroAction(m) {}
void ResolveMacroRef();
std::vector<MacroRef> _macros;
};

View File

@@ -5,11 +5,14 @@
#include <QTimer>
#include <obs-data.h>
class StatusDock : public QDockWidget {
class StatusControl : public QWidget {
Q_OBJECT
public:
StatusDock(QWidget *parent = 0);
StatusControl(QWidget *parent = 0, bool noLayout = false);
QPushButton *Button() { return _button; }
QLabel *StatusLabel() { return _status; }
QLabel *StatusPrefixLabel() { return _statusPrefix; }
private slots:
void ButtonClicked();
@@ -21,10 +24,18 @@ private:
QPushButton *_button;
QLabel *_status;
QLabel *_statusPrefix;
QTimer _timer;
QMetaObject::Connection _pulse;
bool _setToStopped = true;
};
extern StatusDock *dock;
class StatusDock : public QDockWidget {
Q_OBJECT
void saveDock(obs_data_t *obj);
void loadDock(obs_data_t *obj);
public:
StatusDock(QWidget *parent = 0);
};
void SetupDock();

View File

@@ -12,6 +12,8 @@ Most of this code is based on https://github.com/Palakis/obs-websocket
#include <QtCore/QThreadPool>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <QRunnable>
#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/config/asio_no_tls.hpp>
@@ -117,3 +119,16 @@ enum class ClientStatus {
CONNECTED,
FAIL,
};
namespace Compatability {
// Reimplement QRunnable for std::function. Retrocompatability for Qt < 5.15
class StdFunctionRunnable : public QRunnable {
std::function<void()> cb;
public:
StdFunctionRunnable(std::function<void()> func);
void run() override;
};
QRunnable *CreateFunctionRunnable(std::function<void()> func);
}

View File

@@ -16,10 +16,11 @@ bool MacroActionFactory::Register(const std::string &id, MacroActionInfo info)
return false;
}
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id)
std::shared_ptr<MacroAction> MacroActionFactory::Create(const std::string &id,
Macro *m)
{
if (auto it = _methods.find(id); it != _methods.end())
return it->second._createFunc();
return it->second._createFunc(m);
return nullptr;
}
@@ -57,6 +58,7 @@ static inline void populateActionSelection(QComboBox *list)
for (auto entry : MacroActionFactory::GetActionTypes()) {
list->addItem(obs_module_text(entry.second._name.c_str()));
}
list->model()->sort(0);
}
MacroActionEdit::MacroActionEdit(QWidget *parent,
@@ -93,12 +95,13 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
}
auto idx = _entryData->get()->GetIndex();
auto macro = _entryData->get()->GetMacro();
std::string id = MacroActionFactory::GetIdByName(text);
HeaderInfoChanged("");
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->reset();
*_entryData = MacroActionFactory::Create(id);
*_entryData = MacroActionFactory::Create(id, macro);
(*_entryData)->SetIndex(idx);
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
@@ -140,12 +143,12 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
if (idx - 1 >= 0) {
id = macro->Actions().at(idx - 1)->GetId();
} else {
MacroActionSwitchScene temp;
MacroActionSwitchScene temp(nullptr);
id = temp.GetId();
}
std::lock_guard<std::mutex> lock(switcher->m);
macro->Actions().emplace(macro->Actions().begin() + idx,
MacroActionFactory::Create(id));
MacroActionFactory::Create(id, macro));
if (idx - 1 >= 0) {
auto data = obs_data_create();
macro->Actions().at(idx - 1)->Save(data);

View File

@@ -16,6 +16,7 @@ const static std::map<PerformMacroAction, std::string> actionTypes = {
{PerformMacroAction::RESET_COUNTER,
"AdvSceneSwitcher.action.macro.type.resetCounter"},
{PerformMacroAction::RUN, "AdvSceneSwitcher.action.macro.type.run"},
{PerformMacroAction::STOP, "AdvSceneSwitcher.action.macro.type.stop"},
};
bool MacroActionMacro::PerformAction()
@@ -37,6 +38,9 @@ bool MacroActionMacro::PerformAction()
case PerformMacroAction::RUN:
_macro->PerformAction();
break;
case PerformMacroAction::STOP:
_macro->Stop();
break;
default:
break;
}
@@ -63,6 +67,9 @@ void MacroActionMacro::LogAction()
vblog(LOG_INFO, "run nested macro \"%s\"",
_macro->Name().c_str());
break;
case PerformMacroAction::STOP:
vblog(LOG_INFO, "stopped macro \"%s\"", _macro->Name().c_str());
break;
default:
break;
}
@@ -137,6 +144,10 @@ void MacroActionMacroEdit::UpdateEntryData()
}
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
_macros->SetCurrentMacro(_entryData->_macro.get());
if (_entryData->_action == PerformMacroAction::RUN ||
_entryData->_action == PerformMacroAction::STOP) {
_macros->HideSelectedMacro();
}
}
void MacroActionMacroEdit::MacroChanged(const QString &text)
@@ -159,6 +170,13 @@ void MacroActionMacroEdit::ActionChanged(int value)
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_action = static_cast<PerformMacroAction>(value);
if (_entryData->_action == PerformMacroAction::RUN ||
_entryData->_action == PerformMacroAction::STOP) {
_macros->HideSelectedMacro();
} else {
_macros->ShowAllMacros();
}
}
void MacroActionMacroEdit::MacroRemove(const QString &)

View File

@@ -1,9 +1,7 @@
#include "headers/macro-action-random.hpp"
#include "headers/advanced-scene-switcher.hpp"
#include "headers/name-dialog.hpp"
#include "headers/utility.hpp"
#include <QDialogButtonBox>
#include <cstdlib>
const std::string MacroActionRandom::id = "random";
@@ -13,8 +11,8 @@ bool MacroActionRandom::_registered = MacroActionFactory::Register(
{MacroActionRandom::Create, MacroActionRandomEdit::Create,
"AdvSceneSwitcher.action.random"});
std::vector<MacroRef> getPossibleMacros(std::vector<MacroRef> &macros,
MacroRef &lastRandomMacro)
std::vector<MacroRef> getNextMacro(std::vector<MacroRef> &macros,
MacroRef &lastRandomMacro)
{
std::vector<MacroRef> res;
if (macros.size() == 1) {
@@ -40,7 +38,7 @@ bool MacroActionRandom::PerformAction()
return true;
}
auto macros = getPossibleMacros(_macros, lastRandomMacro);
auto macros = getNextMacro(_macros, lastRandomMacro);
if (macros.size() == 0) {
return true;
}
@@ -190,7 +188,7 @@ void MacroActionRandomEdit::AddMacro()
}
std::string macroName;
bool accepted = MacroDialog::AskForMacro(this, macroName);
bool accepted = MacroSelectionDialog::AskForMacro(this, macroName);
if (!accepted || macroName.empty()) {
return;
@@ -262,47 +260,3 @@ void MacroActionRandomEdit::SetMacroListSize()
setHeightToContentHeight(_macroList);
adjustSize();
}
MacroDialog::MacroDialog(QWidget *)
{
setModal(true);
setWindowModality(Qt::WindowModality::ApplicationModal);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setMinimumWidth(350);
setMinimumHeight(70);
QDialogButtonBox *buttonbox = new QDialogButtonBox(
QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
buttonbox->setCenterButtons(true);
connect(buttonbox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
_macroSelection = new MacroSelection(window());
auto *selectionLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{macroSelection}}", _macroSelection},
};
placeWidgets(obs_module_text("AdvSceneSwitcher.askForMacro"),
selectionLayout, widgetPlaceholders);
auto *layout = new QVBoxLayout();
layout->addLayout(selectionLayout);
layout->addWidget(buttonbox);
setLayout(layout);
}
bool MacroDialog::AskForMacro(QWidget *parent, std::string &macroName)
{
MacroDialog dialog(parent);
dialog.setWindowTitle(obs_module_text("AdvSceneSwitcher.windowTitle"));
if (dialog.exec() != DialogCode::Accepted) {
return false;
}
macroName = dialog._macroSelection->currentText().toUtf8().constData();
if (macroName == obs_module_text("AdvSceneSwitcher.selectMacro")) {
return false;
}
return true;
}

View File

@@ -130,6 +130,8 @@ MacroActionSwitchSceneEdit::MacroActionSwitchSceneEdit(
_blockUntilTransitionDone = new QCheckBox(obs_module_text(
"AdvSceneSwitcher.action.scene.blockUntilTransitionDone"));
_duration->SpinBox()->setSpecialValueText("-");
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_transitions,

View File

@@ -0,0 +1,382 @@
#include "headers/macro-action-sequence.hpp"
#include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
const std::string MacroActionSequence::id = "sequence";
bool MacroActionSequence::_registered = MacroActionFactory::Register(
MacroActionSequence::id,
{MacroActionSequence::Create, MacroActionSequenceEdit::Create,
"AdvSceneSwitcher.action.sequence"});
int getNextUnpausedMacroIdx(std::vector<MacroRef> &macros, int startIdx)
{
for (; macros.size() > startIdx; ++startIdx) {
if (!macros[startIdx]->Paused()) {
return startIdx;
}
}
return -1;
}
MacroRef MacroActionSequence::GetNextMacro(bool advance)
{
int idx = _lastIdx;
MacroRef res;
int nextUnpausedIdx = getNextUnpausedMacroIdx(_macros, idx + 1);
if (nextUnpausedIdx != -1) {
res = _macros[nextUnpausedIdx];
idx = nextUnpausedIdx;
} else {
if (_restart) {
idx = getNextUnpausedMacroIdx(_macros, 0);
if (idx != -1) {
res = _macros[idx];
} else {
// End of sequence reached, as all available
// macros are either paused or the macro list
// is empty
idx = _macros.size();
}
} else {
// End of sequence reached
idx = _macros.size();
}
}
if (advance) {
_lastIdx = idx;
_lastSequenceMacro = res;
}
return res;
}
bool MacroActionSequence::PerformAction()
{
if (_macros.size() == 0) {
return true;
}
auto macro = GetNextMacro();
if (!macro.get()) {
return true;
}
return macro->PerformAction();
}
void MacroActionSequence::LogAction()
{
vblog(LOG_INFO, "running macro sequence");
}
bool MacroActionSequence::Save(obs_data_t *obj)
{
MacroAction::Save(obj);
obs_data_array_t *args = obs_data_array_create();
for (auto &m : _macros) {
obs_data_t *array_obj = obs_data_create();
m.Save(array_obj);
obs_data_array_push_back(args, array_obj);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "macros", args);
obs_data_array_release(args);
obs_data_set_bool(obj, "restart", _restart);
return true;
}
bool MacroActionSequence::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
obs_data_array_t *args = obs_data_get_array(obj, "macros");
size_t count = obs_data_array_count(args);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(args, i);
MacroRef ref;
ref.Load(array_obj);
_macros.push_back(ref);
obs_data_release(array_obj);
}
obs_data_array_release(args);
_restart = obs_data_get_bool(obj, "restart");
return true;
}
MacroActionSequenceEdit::MacroActionSequenceEdit(
QWidget *parent, std::shared_ptr<MacroActionSequence> entryData)
: QWidget(parent)
{
_macroList = new QListWidget();
_add = new QPushButton();
_add->setMaximumSize(QSize(22, 22));
_add->setProperty("themeID",
QVariant(QString::fromUtf8("addIconSmall")));
_add->setFlat(true);
_remove = new QPushButton();
_remove->setMaximumSize(QSize(22, 22));
_remove->setProperty("themeID",
QVariant(QString::fromUtf8("removeIconSmall")));
_remove->setFlat(true);
_up = new QPushButton();
_up->setMaximumSize(QSize(22, 22));
_up->setProperty("themeID",
QVariant(QString::fromUtf8("upArrowIconSmall")));
_up->setFlat(true);
_down = new QPushButton();
_down->setMaximumSize(QSize(22, 22));
_down->setProperty("themeID",
QVariant(QString::fromUtf8("downArrowIconSmall")));
_down->setFlat(true);
_continueFrom = new QPushButton(obs_module_text(
"AdvSceneSwitcher.action.sequence.continueFrom"));
_restart = new QCheckBox(
obs_module_text("AdvSceneSwitcher.action.sequence.restart"));
_statusLine = new QLabel();
QWidget::connect(_add, SIGNAL(clicked()), this, SLOT(Add()));
QWidget::connect(_remove, SIGNAL(clicked()), this, SLOT(Remove()));
QWidget::connect(_up, SIGNAL(clicked()), this, SLOT(Up()));
QWidget::connect(_down, SIGNAL(clicked()), this, SLOT(Down()));
QWidget::connect(_continueFrom, SIGNAL(clicked()), this,
SLOT(ContinueFromClicked()));
QWidget::connect(_macroList, SIGNAL(currentRowChanged(int)), this,
SLOT(MacroSelectionChanged(int)));
QWidget::connect(window(),
SIGNAL(MacroRenamed(const QString &, const QString &)),
this,
SLOT(MacroRename(const QString &, const QString &)));
QWidget::connect(_restart, SIGNAL(stateChanged(int)), this,
SLOT(RestartChanged(int)));
auto *entryLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {};
placeWidgets(obs_module_text("AdvSceneSwitcher.action.sequence.entry"),
entryLayout, widgetPlaceholders);
auto *argButtonLayout = new QHBoxLayout;
argButtonLayout->addWidget(_add);
argButtonLayout->addWidget(_remove);
QFrame *line = new QFrame();
line->setFrameShape(QFrame::VLine);
line->setFrameShadow(QFrame::Sunken);
argButtonLayout->addWidget(line);
argButtonLayout->addWidget(_up);
argButtonLayout->addWidget(_down);
QFrame *line2 = new QFrame();
line2->setFrameShape(QFrame::VLine);
line2->setFrameShadow(QFrame::Sunken);
argButtonLayout->addWidget(line2);
argButtonLayout->addWidget(_continueFrom);
argButtonLayout->addStretch();
auto *mainLayout = new QVBoxLayout;
mainLayout->addLayout(entryLayout);
mainLayout->addWidget(_macroList);
mainLayout->addLayout(argButtonLayout);
mainLayout->addLayout(argButtonLayout);
mainLayout->addWidget(_restart);
mainLayout->addWidget(_statusLine);
setLayout(mainLayout);
UpdateStatusLine();
connect(&_statusTimer, SIGNAL(timeout()), this,
SLOT(UpdateStatusLine()));
_statusTimer.start(1000);
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
void MacroActionSequenceEdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
for (auto &m : _entryData->_macros) {
if (!m.get()) {
continue;
}
auto name = QString::fromStdString(m->Name());
QListWidgetItem *item = new QListWidgetItem(name, _macroList);
item->setData(Qt::UserRole, name);
}
SetMacroListSize();
_restart->setChecked(_entryData->_restart);
}
void MacroActionSequenceEdit::MacroRemove(const QString &name)
{
if (_entryData) {
auto it = _entryData->_macros.begin();
while (it != _entryData->_macros.end()) {
if (it->get()->Name() == name.toStdString()) {
it = _entryData->_macros.erase(it);
} else {
++it;
}
}
}
}
void MacroActionSequenceEdit::MacroRename(const QString &oldName,
const QString &newName)
{
auto count = _macroList->count();
for (int idx = 0; idx < count; ++idx) {
QListWidgetItem *item = _macroList->item(idx);
QString itemString = item->data(Qt::UserRole).toString();
if (oldName == itemString) {
item->setData(Qt::UserRole, newName);
item->setText(newName);
break;
}
}
}
void MacroActionSequenceEdit::Add()
{
if (_loading || !_entryData) {
return;
}
std::string macroName;
bool accepted = MacroSelectionDialog::AskForMacro(this, macroName);
if (!accepted || macroName.empty()) {
return;
}
MacroRef macro(macroName);
if (!macro.get()) {
return;
}
QVariant v = QVariant::fromValue(QString::fromStdString(macroName));
new QListWidgetItem(QString::fromStdString(macroName), _macroList);
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_macros.push_back(macro);
SetMacroListSize();
}
void MacroActionSequenceEdit::Remove()
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
auto item = _macroList->currentItem();
int idx = _macroList->currentRow();
if (!item || idx == -1) {
return;
}
_entryData->_macros.erase(std::next(_entryData->_macros.begin(), idx));
delete item;
SetMacroListSize();
}
void MacroActionSequenceEdit::Up()
{
if (_loading || !_entryData) {
return;
}
int idx = _macroList->currentRow();
if (idx != -1 && idx != 0) {
_macroList->insertItem(idx - 1, _macroList->takeItem(idx));
_macroList->setCurrentRow(idx - 1);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(_entryData->_macros[idx],
_entryData->_macros[idx - 1]);
}
}
void MacroActionSequenceEdit::Down()
{
int idx = _macroList->currentRow();
if (idx != -1 && idx != _macroList->count() - 1) {
_macroList->insertItem(idx + 1, _macroList->takeItem(idx));
_macroList->setCurrentRow(idx + 1);
std::lock_guard<std::mutex> lock(switcher->m);
std::swap(_entryData->_macros[idx],
_entryData->_macros[idx + 1]);
}
}
void MacroActionSequenceEdit::ContinueFromClicked()
{
if (_loading || !_entryData) {
return;
}
int idx = _macroList->currentRow();
if (idx == -1) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_lastIdx = idx - 1;
}
void MacroActionSequenceEdit::RestartChanged(int state)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_restart = state;
}
void MacroActionSequenceEdit::UpdateStatusLine()
{
QString lastMacroName =
obs_module_text("AdvSceneSwitcher.action.sequence.status.none");
QString nextMacroName =
obs_module_text("AdvSceneSwitcher.action.sequence.status.none");
if (_entryData) {
if (_entryData->_lastSequenceMacro.get()) {
lastMacroName = QString::fromStdString(
_entryData->_lastSequenceMacro->Name());
}
auto next = _entryData->GetNextMacro(false);
if (next.get()) {
nextMacroName = QString::fromStdString(next->Name());
}
}
QString format{
obs_module_text("AdvSceneSwitcher.action.sequence.status")};
_statusLine->setText(format.arg(lastMacroName, nextMacroName));
}
int MacroActionSequenceEdit::FindEntry(const std::string &macro)
{
int count = _macroList->count();
int idx = -1;
for (int i = 0; i < count; i++) {
QListWidgetItem *item = _macroList->item(i);
QString itemString = item->data(Qt::UserRole).toString();
if (QString::fromStdString(macro) == itemString) {
idx = i;
break;
}
}
return idx;
}
void MacroActionSequenceEdit::SetMacroListSize()
{
setHeightToContentHeight(_macroList);
adjustSize();
}

View File

@@ -10,11 +10,23 @@ bool MacroConditionAudio::_registered = MacroConditionFactory::Register(
{MacroConditionAudio::Create, MacroConditionAudioEdit::Create,
"AdvSceneSwitcher.condition.audio"});
static std::map<AudioCondition, std::string> audioConditionTypes = {
{AudioCondition::ABOVE, "AdvSceneSwitcher.condition.audio.state.above"},
{AudioCondition::BELOW, "AdvSceneSwitcher.condition.audio.state.below"},
{AudioCondition::MUTE, "AdvSceneSwitcher.condition.audio.state.mute"},
{AudioCondition::UNMUTE,
static std::map<AudioOutputCondition, std::string> audioOutputConditionTypes = {
{AudioOutputCondition::ABOVE,
"AdvSceneSwitcher.condition.audio.state.above"},
{AudioOutputCondition::BELOW,
"AdvSceneSwitcher.condition.audio.state.below"},
};
static std::map<AudioVolumeCondition, std::string> audioVolumeConditionTypes = {
{AudioVolumeCondition::ABOVE,
"AdvSceneSwitcher.condition.audio.state.above"},
{AudioVolumeCondition::EXACT,
"AdvSceneSwitcher.condition.audio.state.exact"},
{AudioVolumeCondition::BELOW,
"AdvSceneSwitcher.condition.audio.state.below"},
{AudioVolumeCondition::MUTE,
"AdvSceneSwitcher.condition.audio.state.mute"},
{AudioVolumeCondition::UNMUTE,
"AdvSceneSwitcher.condition.audio.state.unmute"},
};
@@ -24,43 +36,85 @@ MacroConditionAudio::~MacroConditionAudio()
obs_volmeter_destroy(_volmeter);
}
bool MacroConditionAudio::CheckCondition()
bool MacroConditionAudio::CheckOutputCondition()
{
bool ret = false;
auto s = obs_weak_source_get_source(_audioSource);
switch (_condition) {
case AudioCondition::ABOVE:
switch (_outputCondition) {
case AudioOutputCondition::ABOVE:
// peak will have a value from -60 db to 0 db
ret = ((double)_peak + 60) * 1.7 > _volume;
break;
case AudioCondition::BELOW:
case AudioOutputCondition::BELOW:
// peak will have a value from -60 db to 0 db
ret = ((double)_peak + 60) * 1.7 < _volume;
break;
case AudioCondition::MUTE:
ret = obs_source_muted(s);
break;
case AudioCondition::UNMUTE:
ret = !obs_source_muted(s);
break;
default:
break;
}
// Reset for next check
_peak = -std::numeric_limits<float>::infinity();
obs_source_release(s);
return ret;
}
bool MacroConditionAudio::CheckVolumeCondition()
{
bool ret = false;
auto s = obs_weak_source_get_source(_audioSource);
switch (_volumeCondition) {
case AudioVolumeCondition::ABOVE:
ret = obs_source_get_volume(s) > _volume / 100.f;
break;
case AudioVolumeCondition::EXACT:
ret = obs_source_get_volume(s) == _volume / 100.f;
break;
case AudioVolumeCondition::BELOW:
ret = obs_source_get_volume(s) < _volume / 100.f;
break;
case AudioVolumeCondition::MUTE:
ret = obs_source_muted(s);
break;
case AudioVolumeCondition::UNMUTE:
ret = !obs_source_muted(s);
break;
default:
break;
}
obs_source_release(s);
return ret;
}
bool MacroConditionAudio::CheckCondition()
{
switch (_checkType) {
case AudioConditionCheckType::OUTPUT_VOLUME:
return CheckOutputCondition();
case AudioConditionCheckType::CONFIGURED_VOLUME:
return CheckVolumeCondition();
default:
break;
}
return false;
}
bool MacroConditionAudio::Save(obs_data_t *obj)
{
MacroCondition::Save(obj);
obs_data_set_string(obj, "audioSource",
GetWeakSourceName(_audioSource).c_str());
obs_data_set_int(obj, "volume", _volume);
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
obs_data_set_int(obj, "checkType", static_cast<int>(_checkType));
obs_data_set_int(obj, "outputCondition",
static_cast<int>(_outputCondition));
obs_data_set_int(obj, "volumeCondition",
static_cast<int>(_volumeCondition));
return true;
}
@@ -81,14 +135,66 @@ obs_volmeter_t *AddVolmeterToSource(MacroConditionAudio *entry,
return volmeter;
}
// TODO: Remove in future version
static void convertOldSettingsFormat(obs_data_t *obj)
{
auto oldCond = static_cast<AudioOutputCondition>(
obs_data_get_int(obj, "condition"));
switch (oldCond) {
case AudioOutputCondition::ABOVE:
obs_data_set_int(
obj, "checkType",
static_cast<int>(
AudioConditionCheckType::OUTPUT_VOLUME));
obs_data_set_int(obj, "outputCondition",
static_cast<int>(AudioOutputCondition::ABOVE));
break;
case AudioOutputCondition::BELOW:
obs_data_set_int(
obj, "checkType",
static_cast<int>(
AudioConditionCheckType::OUTPUT_VOLUME));
obs_data_set_int(obj, "outputCondition",
static_cast<int>(AudioOutputCondition::BELOW));
break;
case AudioOutputCondition::MUTE:
obs_data_set_int(
obj, "checkType",
static_cast<int>(
AudioConditionCheckType::CONFIGURED_VOLUME));
obs_data_set_int(obj, "volumeCondition",
static_cast<int>(AudioVolumeCondition::MUTE));
break;
case AudioOutputCondition::UNMUTE:
obs_data_set_int(
obj, "checkType",
static_cast<int>(
AudioConditionCheckType::CONFIGURED_VOLUME));
obs_data_set_int(
obj, "volumeCondition",
static_cast<int>(AudioVolumeCondition::UNMUTE));
break;
default:
break;
}
}
bool MacroConditionAudio::Load(obs_data_t *obj)
{
if (!obs_data_has_user_value(obj, "checkType")) {
convertOldSettingsFormat(obj);
}
MacroCondition::Load(obj);
const char *audioSourceName = obs_data_get_string(obj, "audioSource");
_audioSource = GetWeakSourceByName(audioSourceName);
_volume = obs_data_get_int(obj, "volume");
_condition =
static_cast<AudioCondition>(obs_data_get_int(obj, "condition"));
_checkType = static_cast<AudioConditionCheckType>(
obs_data_get_int(obj, "checkType"));
_outputCondition = static_cast<AudioOutputCondition>(
obs_data_get_int(obj, "outputCondition"));
_volumeCondition = static_cast<AudioVolumeCondition>(
obs_data_get_int(obj, "volumeCondition"));
_volmeter = AddVolmeterToSource(this, _audioSource);
return true;
}
@@ -122,9 +228,26 @@ void MacroConditionAudio::ResetVolmeter()
_volmeter = AddVolmeterToSource(this, _audioSource);
}
static inline void populateConditionSelection(QComboBox *list)
static inline void populateCheckTypes(QComboBox *list)
{
for (auto entry : audioConditionTypes) {
list->addItem(obs_module_text(
"AdvSceneSwitcher.condition.audio.type.output"));
list->addItem(obs_module_text(
"AdvSceneSwitcher.condition.audio.type.volume"));
}
static inline void populateOutputConditionSelection(QComboBox *list)
{
list->clear();
for (auto entry : audioOutputConditionTypes) {
list->addItem(obs_module_text(entry.second.c_str()));
}
}
static inline void populateVolumeConditionSelection(QComboBox *list)
{
list->clear();
for (auto entry : audioVolumeConditionTypes) {
list->addItem(obs_module_text(entry.second.c_str()));
}
}
@@ -133,6 +256,7 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
QWidget *parent, std::shared_ptr<MacroConditionAudio> entryData)
: QWidget(parent)
{
_checkTypes = new QComboBox();
_audioSources = new QComboBox();
_condition = new QComboBox();
_volume = new QSpinBox();
@@ -141,6 +265,8 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
_volume->setMaximum(100);
_volume->setMinimum(0);
QWidget::connect(_checkTypes, SIGNAL(currentIndexChanged(int)), this,
SLOT(CheckTypeChanged(int)));
QWidget::connect(_volume, SIGNAL(valueChanged(int)), this,
SLOT(VolumeThresholdChanged(int)));
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
@@ -149,11 +275,12 @@ MacroConditionAudioEdit::MacroConditionAudioEdit(
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(SourceChanged(const QString &)));
populateCheckTypes(_checkTypes);
populateAudioSelection(_audioSources);
populateConditionSelection(_condition);
QHBoxLayout *switchLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{checkType}}", _checkTypes},
{"{{audioSources}}", _audioSources},
{"{{volume}}", _volume},
{"{{condition}}", _condition},
@@ -224,7 +351,31 @@ void MacroConditionAudioEdit::ConditionChanged(int cond)
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_condition = static_cast<AudioCondition>(cond);
if (_entryData->_checkType == AudioConditionCheckType::OUTPUT_VOLUME) {
_entryData->_outputCondition =
static_cast<AudioOutputCondition>(cond);
} else {
_entryData->_volumeCondition =
static_cast<AudioVolumeCondition>(cond);
}
SetWidgetVisibility();
}
void MacroConditionAudioEdit::CheckTypeChanged(int cond)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_checkType = static_cast<AudioConditionCheckType>(cond);
const QSignalBlocker b(_condition);
if (_entryData->_checkType == AudioConditionCheckType::OUTPUT_VOLUME) {
populateOutputConditionSelection(_condition);
} else {
populateVolumeConditionSelection(_condition);
}
SetWidgetVisibility();
}
@@ -237,7 +388,16 @@ void MacroConditionAudioEdit::UpdateEntryData()
_audioSources->setCurrentText(
GetWeakSourceName(_entryData->_audioSource).c_str());
_volume->setValue(_entryData->_volume);
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
_checkTypes->setCurrentIndex(static_cast<int>(_entryData->_checkType));
if (_entryData->_checkType == AudioConditionCheckType::OUTPUT_VOLUME) {
populateOutputConditionSelection(_condition);
_condition->setCurrentIndex(
static_cast<int>(_entryData->_outputCondition));
} else {
populateVolumeConditionSelection(_condition);
_condition->setCurrentIndex(
static_cast<int>(_entryData->_volumeCondition));
}
UpdateVolmeterSource();
SetWidgetVisibility();
}
@@ -248,9 +408,15 @@ void MacroConditionAudioEdit::SetWidgetVisibility()
return;
}
_volume->setVisible(_entryData->_condition == AudioCondition::ABOVE ||
_entryData->_condition == AudioCondition::BELOW);
_volMeter->setVisible(_entryData->_condition == AudioCondition::ABOVE ||
_entryData->_condition == AudioCondition::BELOW);
_volume->setVisible(
_entryData->_checkType ==
AudioConditionCheckType::OUTPUT_VOLUME ||
(_entryData->_checkType ==
AudioConditionCheckType::CONFIGURED_VOLUME &&
(_entryData->_volumeCondition == AudioVolumeCondition::ABOVE ||
_entryData->_volumeCondition == AudioVolumeCondition::EXACT ||
_entryData->_volumeCondition == AudioVolumeCondition::BELOW)));
_volMeter->setVisible(_entryData->_checkType ==
AudioConditionCheckType::OUTPUT_VOLUME);
adjustSize();
}

View File

@@ -18,10 +18,10 @@ bool MacroConditionFactory::Register(const std::string &id,
}
std::shared_ptr<MacroCondition>
MacroConditionFactory::Create(const std::string &id)
MacroConditionFactory::Create(const std::string &id, Macro *m)
{
if (auto it = _methods.find(id); it != _methods.end()) {
return it->second._createFunc();
return it->second._createFunc(m);
}
return nullptr;
}
@@ -87,6 +87,7 @@ static inline void populateConditionSelection(QComboBox *list)
for (auto entry : MacroConditionFactory::GetConditionTypes()) {
list->addItem(obs_module_text(entry.second._name.c_str()));
}
list->model()->sort(0);
}
MacroConditionEdit::MacroConditionEdit(
@@ -189,6 +190,7 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
}
auto idx = _entryData->get()->GetIndex();
auto macro = _entryData->get()->GetMacro();
std::string id = MacroConditionFactory::GetIdByName(text);
auto temp = DurationConstraint();
@@ -198,7 +200,7 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
std::lock_guard<std::mutex> lock(switcher->m);
auto logic = (*_entryData)->GetLogicType();
_entryData->reset();
*_entryData = MacroConditionFactory::Create(id);
*_entryData = MacroConditionFactory::Create(id, macro);
(*_entryData)->SetIndex(idx);
(*_entryData)->SetLogicType(logic);
auto widget =
@@ -260,14 +262,14 @@ void AdvSceneSwitcher::AddMacroCondition(int idx)
if (idx - 1 >= 0) {
id = macro->Conditions().at(idx - 1)->GetId();
} else {
MacroConditionScene temp;
MacroConditionScene temp(macro);
id = temp.GetId();
}
std::lock_guard<std::mutex> lock(switcher->m);
bool root = idx == 0;
auto cond =
macro->Conditions().emplace(macro->Conditions().begin() + idx,
MacroConditionFactory::Create(id));
auto cond = macro->Conditions().emplace(
macro->Conditions().begin() + idx,
MacroConditionFactory::Create(id, macro));
if (idx - 1 >= 0) {
auto data = obs_data_create();
macro->Conditions().at(idx - 1)->Save(data);

View File

@@ -14,13 +14,19 @@ static void hotkeyCB(void *data, obs_hotkey_id, obs_hotkey_t *, bool pressed)
{
if (pressed) {
auto c = static_cast<MacroConditionHotkey *>(data);
c->SetPressed();
auto macro = c->GetMacro();
if (!macro) {
c->SetPressed();
}
if (macro && !macro->Paused()) {
c->SetPressed();
}
}
}
static uint32_t count = 1;
MacroConditionHotkey::MacroConditionHotkey()
MacroConditionHotkey::MacroConditionHotkey(Macro *m) : MacroCondition(m)
{
if (_hotkeyID != OBS_INVALID_HOTKEY_ID) {
obs_hotkey_unregister(_hotkeyID);
@@ -76,8 +82,11 @@ MacroConditionHotkeyEdit::MacroConditionHotkeyEdit(
: QWidget(parent)
{
_name = new QLineEdit();
QLabel *line1 = new QLabel(obs_module_text(
"AdvSceneSwitcher.condition.hotkey.entry.line1"));
QLabel *hint = new QLabel(
obs_module_text("AdvSceneSwitcher.condition.hotkey.tip"));
QWidget::connect(_name, SIGNAL(editingFinished()), this,
SLOT(NameChanged()));
@@ -85,10 +94,12 @@ MacroConditionHotkeyEdit::MacroConditionHotkeyEdit(
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{name}}", _name},
};
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.hotkey.entry"),
placeWidgets(obs_module_text(
"AdvSceneSwitcher.condition.hotkey.entry.line2"),
switchLayout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(line1);
mainLayout->addLayout(switchLayout);
mainLayout->addWidget(hint);
setLayout(mainLayout);

View File

@@ -28,7 +28,7 @@ bool MacroConditionScene::CheckCondition()
switch (_type) {
case SceneType::CURRENT:
if (_waitForTransition) {
if (!_useTransitionTargetScene) {
return switcher->currentScene == _scene.GetScene(false);
} else {
@@ -58,7 +58,8 @@ bool MacroConditionScene::Save(obs_data_t *obj)
MacroCondition::Save(obj);
_scene.Save(obj);
obs_data_set_int(obj, "type", static_cast<int>(_type));
obs_data_set_bool(obj, "waitForTransition", _waitForTransition);
obs_data_set_bool(obj, "useTransitionTargetScene",
_useTransitionTargetScene);
return true;
}
@@ -67,11 +68,12 @@ bool MacroConditionScene::Load(obs_data_t *obj)
MacroCondition::Load(obj);
_scene.Load(obj);
_type = static_cast<SceneType>(obs_data_get_int(obj, "type"));
if (!obs_data_has_user_value(obj, "waitForTransition")) {
_waitForTransition = true;
if (obs_data_has_user_value(obj, "waitForTransition")) {
_useTransitionTargetScene =
!obs_data_get_bool(obj, "waitForTransition");
} else {
_waitForTransition =
obs_data_get_bool(obj, "waitForTransition");
_useTransitionTargetScene =
obs_data_get_bool(obj, "useTransitionTargetScene");
}
return true;
}
@@ -94,26 +96,34 @@ MacroConditionSceneEdit::MacroConditionSceneEdit(
{
_scenes = new SceneSelectionWidget(window(), false, false, false);
_sceneType = new QComboBox();
_waitForTransition = new QCheckBox(obs_module_text(
"AdvSceneSwitcher.condition.scene.waitForTransition"));
_useTransitionTargetScene = new QCheckBox(obs_module_text(
"AdvSceneSwitcher.condition.scene.currentSceneTransitionBehaviour"));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sceneType, SIGNAL(currentIndexChanged(int)), this,
SLOT(TypeChanged(int)));
QWidget::connect(_waitForTransition, SIGNAL(stateChanged(int)), this,
SLOT(WaitForTransitionChanged(int)));
QWidget::connect(_useTransitionTargetScene, SIGNAL(stateChanged(int)),
this, SLOT(UseTransitionTargetSceneChanged(int)));
populateTypeSelection(_sceneType);
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{scenes}}", _scenes},
{"{{sceneType}}", _sceneType},
{"{{waitForTransition}}", _waitForTransition},
{"{{useTransitionTargetScene}}", _useTransitionTargetScene},
};
placeWidgets(obs_module_text("AdvSceneSwitcher.condition.scene.entry"),
mainLayout, widgetPlaceholders);
QHBoxLayout *line1Layout = new QHBoxLayout;
placeWidgets(
obs_module_text("AdvSceneSwitcher.condition.scene.entry.line1"),
line1Layout, widgetPlaceholders);
QHBoxLayout *line2Layout = new QHBoxLayout;
placeWidgets(
obs_module_text("AdvSceneSwitcher.condition.scene.entry.line2"),
line2Layout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(line1Layout);
mainLayout->addLayout(line2Layout);
setLayout(mainLayout);
_entryData = entryData;
@@ -144,26 +154,23 @@ void MacroConditionSceneEdit::TypeChanged(int value)
SetWidgetVisibility();
}
void MacroConditionSceneEdit::WaitForTransitionChanged(int state)
void MacroConditionSceneEdit::UseTransitionTargetSceneChanged(int state)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_waitForTransition = state;
_entryData->_useTransitionTargetScene = state;
}
void MacroConditionSceneEdit::SetWidgetVisibility()
{
_scenes->setVisible(_entryData->_type == SceneType::CURRENT ||
_entryData->_type == SceneType::PREVIOUS);
// The waitForTransition option shall be slowly faded out over time and
// be replaced by the transition source and target scene checks
_waitForTransition->setVisible(_entryData->_type ==
SceneType::CURRENT &&
!_entryData->_waitForTransition);
_useTransitionTargetScene->setVisible(_entryData->_type ==
SceneType::CURRENT);
adjustSize();
}
void MacroConditionSceneEdit::UpdateEntryData()
@@ -174,6 +181,7 @@ void MacroConditionSceneEdit::UpdateEntryData()
_scenes->SetScene(_entryData->_scene);
_sceneType->setCurrentIndex(static_cast<int>(_entryData->_type));
_waitForTransition->setChecked(_entryData->_waitForTransition);
_useTransitionTargetScene->setChecked(
_entryData->_useTransitionTargetScene);
SetWidgetVisibility();
}

View File

@@ -8,7 +8,7 @@ const std::string MacroConditionTransition::id = "transition";
bool MacroConditionTransition::_registered = MacroConditionFactory::Register(
MacroConditionTransition::id,
{MacroConditionTransition::Create, MacroConditionTransitionEdit::Create,
"AdvSceneSwitcher.condition.transition", false});
"AdvSceneSwitcher.condition.transition"});
static std::map<TransitionCondition, std::string> filterConditionTypes = {
{TransitionCondition::CURRENT,

View File

@@ -1,7 +1,9 @@
#include "headers/macro-selection.hpp"
#include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
#include <QStandardItemModel>
#include <QDialogButtonBox>
MacroSelection::MacroSelection(QWidget *parent) : QComboBox(parent)
{
@@ -43,6 +45,28 @@ void MacroSelection::SetCurrentMacro(Macro *m)
}
}
void MacroSelection::HideSelectedMacro()
{
auto ssWindow = static_cast<AdvSceneSwitcher *>(window());
if (!ssWindow) {
return;
}
int idx = ssWindow->ui->macros->currentRow();
if (idx == -1) {
return;
}
// +1 for "select macro" entry
qobject_cast<QListView *>(view())->setRowHidden(idx + 1, true);
}
void MacroSelection::ShowAllMacros()
{
auto v = qobject_cast<QListView *>(view());
for (int i = count(); i > 0; i--) {
v->setRowHidden(i, false);
}
}
void MacroSelection::MacroRemove(const QString &name)
{
int idx = findText(name);
@@ -66,3 +90,47 @@ void MacroSelection::MacroRename(const QString &oldName, const QString &newName)
setCurrentIndex(findText(newName));
}
}
MacroSelectionDialog::MacroSelectionDialog(QWidget *)
{
setModal(true);
setWindowModality(Qt::WindowModality::ApplicationModal);
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
setMinimumWidth(350);
setMinimumHeight(70);
QDialogButtonBox *buttonbox = new QDialogButtonBox(
QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
buttonbox->setCenterButtons(true);
connect(buttonbox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
_macroSelection = new MacroSelection(window());
auto *selectionLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{macroSelection}}", _macroSelection},
};
placeWidgets(obs_module_text("AdvSceneSwitcher.askForMacro"),
selectionLayout, widgetPlaceholders);
auto *layout = new QVBoxLayout();
layout->addLayout(selectionLayout);
layout->addWidget(buttonbox);
setLayout(layout);
}
bool MacroSelectionDialog::AskForMacro(QWidget *parent, std::string &macroName)
{
MacroSelectionDialog dialog(parent);
dialog.setWindowTitle(obs_module_text("AdvSceneSwitcher.windowTitle"));
if (dialog.exec() != DialogCode::Accepted) {
return false;
}
macroName = dialog._macroSelection->currentText().toUtf8().constData();
if (macroName == obs_module_text("AdvSceneSwitcher.selectMacro")) {
return false;
}
return true;
}

View File

@@ -198,6 +198,16 @@ void AdvSceneSwitcher::on_runMacroInParallel_stateChanged(int value)
macro->SetRunInParallel(value);
}
void AdvSceneSwitcher::on_runMacroOnChange_stateChanged(int value)
{
Macro *macro = getSelectedMacro();
if (!macro) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
macro->SetMatchOnChange(value);
}
void AdvSceneSwitcher::PopulateMacroActions(Macro &m, uint32_t afterIdx)
{
auto &actions = m.Actions();
@@ -232,8 +242,10 @@ void AdvSceneSwitcher::SetEditMacro(Macro &m)
{
const QSignalBlocker b1(ui->macroName);
const QSignalBlocker b2(ui->runMacroInParallel);
const QSignalBlocker b3(ui->runMacroOnChange);
ui->macroName->setText(m.Name().c_str());
ui->runMacroInParallel->setChecked(m.RunInParallel());
ui->runMacroOnChange->setChecked(m.MatchOnChange());
}
clearLayout(ui->macroEditConditionLayout);
clearLayout(ui->macroEditActionLayout);

View File

@@ -29,7 +29,7 @@ Macro::Macro(const std::string &name)
Macro::~Macro()
{
_stop = true;
_die = true;
if (_thread.joinable()) {
_thread.join();
}
@@ -95,9 +95,16 @@ bool Macro::CeckMatch()
vblog(LOG_INFO, "condition %s returned %d", c->GetId().c_str(),
cond);
}
vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched);
bool newLastMatched = _matched;
if (_matched && _matchOnChange && _lastMatched == _matched) {
vblog(LOG_INFO, "ignore match for Macro %s (on change)",
_name.c_str());
_matched = false;
}
_lastMatched = newLastMatched;
// TODO: Move back to PerformAction() once new scene collection frontend
// events are available - see:
// https://github.com/obsproject/obs-studio/commit/feda1aaa283e8a99f6ba1159cfe6b9c1f2934a61
@@ -114,9 +121,9 @@ bool Macro::PerformAction(bool forceParallel, bool ignorePause)
vblog(LOG_INFO, "macro %s already running", _name.c_str());
return !forceParallel;
}
bool ret = true;
_stop = false;
_done = false;
bool ret = true;
if (_runInParallel || forceParallel) {
if (_thread.joinable()) {
_thread.join();
@@ -148,7 +155,7 @@ void Macro::RunActions(bool &retVal, bool ignorePause)
for (auto &a : _actions) {
a->LogAction();
ret = ret && a->PerformAction();
if (!ret || _stop || (_paused && !ignorePause)) {
if (!ret || (_paused && !ignorePause) || _stop || _die) {
retVal = ret;
_done = true;
return;
@@ -194,6 +201,7 @@ bool Macro::Save(obs_data_t *obj)
obs_data_set_string(obj, "name", _name.c_str());
obs_data_set_bool(obj, "pause", _paused);
obs_data_set_bool(obj, "parallel", _runInParallel);
obs_data_set_bool(obj, "onChange", _matchOnChange);
obs_data_array_t *pauseHotkey = obs_hotkey_save(_pauseHotkey);
obs_data_set_array(obj, "pauseHotkey", pauseHotkey);
@@ -272,6 +280,7 @@ bool Macro::Load(obs_data_t *obj)
_name = obs_data_get_string(obj, "name");
_paused = obs_data_get_bool(obj, "pause");
_runInParallel = obs_data_get_bool(obj, "parallel");
_matchOnChange = obs_data_get_bool(obj, "onChange");
obs_data_array_t *pauseHotkey = obs_data_get_array(obj, "pauseHotkey");
obs_hotkey_load(_pauseHotkey, pauseHotkey);
@@ -296,7 +305,7 @@ bool Macro::Load(obs_data_t *obj)
std::string id = obs_data_get_string(array_obj, "id");
auto newEntry = MacroConditionFactory::Create(id);
auto newEntry = MacroConditionFactory::Create(id, this);
if (newEntry) {
_conditions.emplace_back(newEntry);
auto c = _conditions.back().get();
@@ -322,7 +331,7 @@ bool Macro::Load(obs_data_t *obj)
std::string id = obs_data_get_string(array_obj, "id");
auto newEntry = MacroActionFactory::Create(id);
auto newEntry = MacroActionFactory::Create(id, this);
if (newEntry) {
_actions.emplace_back(newEntry);
_actions.back()->Load(array_obj);
@@ -363,7 +372,7 @@ void Macro::ResolveMacroRef()
bool Macro::SwitchesScene()
{
MacroActionSwitchScene temp;
MacroActionSwitchScene temp(nullptr);
auto sceneSwitchId = temp.GetId();
for (auto &a : _actions) {
if (a->GetId() == sceneSwitchId) {

119
src/status-control.cpp Normal file
View File

@@ -0,0 +1,119 @@
#include "headers/status-control.hpp"
#include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
#include <obs-module.h>
#include <QMainWindow>
#include <QLayout>
#include <QAction>
StatusDock *dock = nullptr;
StatusControl::StatusControl(QWidget *parent, bool noLayout) : QWidget(parent)
{
_button = new QPushButton("-", this);
_status = new QLabel("-", this);
_statusPrefix = new QLabel(
obs_module_text(
"AdvSceneSwitcher.generalTab.status.currentStatus"),
this);
QWidget::connect(_button, SIGNAL(clicked()), this,
SLOT(ButtonClicked()));
if (!noLayout) {
QHBoxLayout *statusLayout = new QHBoxLayout();
statusLayout->addWidget(_statusPrefix);
statusLayout->addWidget(_status);
statusLayout->addStretch();
QVBoxLayout *layout = new QVBoxLayout();
layout->addLayout(statusLayout);
layout->addWidget(_button);
setLayout(layout);
}
if (switcher->stop) {
SetStopped();
} else {
SetStarted();
}
connect(&_timer, SIGNAL(timeout()), this, SLOT(UpdateStatus()));
_timer.start(1000);
}
void StatusControl::ButtonClicked()
{
if (switcher->th && switcher->th->isRunning()) {
switcher->Stop();
SetStopped();
} else {
switcher->Start();
SetStarted();
}
}
void StatusControl::UpdateStatus()
{
if (!switcher) {
return;
}
if (switcher->th && switcher->th->isRunning()) {
if (!_setToStopped) {
return;
}
SetStarted();
} else {
if (_setToStopped) {
return;
}
SetStopped();
}
}
void StatusControl::SetStarted()
{
_button->setText(
obs_module_text("AdvSceneSwitcher.generalTab.status.stop"));
_status->setText(obs_module_text("AdvSceneSwitcher.status.active"));
_status->disconnect(_pulse);
_setToStopped = false;
}
void StatusControl::SetStopped()
{
_button->setText(
obs_module_text("AdvSceneSwitcher.generalTab.status.start"));
_status->setText(obs_module_text("AdvSceneSwitcher.status.inactive"));
if (!switcher->disableHints) {
_pulse = PulseWidget(_status, QColor(Qt::red),
QColor(0, 0, 0, 0), "QLabel ");
}
_setToStopped = true;
}
StatusDock::StatusDock(QWidget *parent)
: QDockWidget(obs_module_text("AdvSceneSwitcher.windowTitle"), parent)
{
setFloating(true);
// Setting a fixed object name is crucial for OBS to be able to restore
// the docks position, if the dock is not floating
setObjectName("Adv-ss-dock");
// Not sure why an extra QWidget wrapper is necessary...
// without it the dock widget seems to be partially transparent.
QWidget *tmp = new QWidget;
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(new StatusControl(this));
tmp->setLayout(layout);
setWidget(tmp);
}
void SetupDock()
{
dock = new StatusDock(
static_cast<QMainWindow *>(obs_frontend_get_main_window()));
// Added for cosmetic reasons to avoid brief flash of dock window on startup
dock->setVisible(false);
static_cast<QAction *>(obs_frontend_add_dock(dock));
}

View File

@@ -1,91 +0,0 @@
#include "headers/status-dock.hpp"
#include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
#include <obs-module.h>
#include <QMainWindow>
#include <QLayout>
StatusDock *dock = nullptr;
StatusDock::StatusDock(QWidget *parent)
: QDockWidget(obs_module_text("AdvSceneSwitcher.windowTitle"), parent)
{
_button = new QPushButton(
obs_module_text("AdvSceneSwitcher.generalTab.status.start"));
_status =
new QLabel(obs_module_text("AdvSceneSwitcher.status.inactive"));
QWidget::connect(_button, SIGNAL(clicked()), this,
SLOT(ButtonClicked()));
QHBoxLayout *statusLayout = new QHBoxLayout;
statusLayout->addWidget(new QLabel(obs_module_text(
"AdvSceneSwitcher.generalTab.status.currentStatus")));
statusLayout->addWidget(_status);
QVBoxLayout *layout = new QVBoxLayout;
layout->addLayout(statusLayout);
layout->addWidget(_button);
layout->addStretch();
QWidget *tmp = new QWidget;
tmp->setLayout(layout);
setWidget(tmp);
connect(&_timer, SIGNAL(timeout()), this, SLOT(UpdateStatus()));
_timer.start(1000);
}
void StatusDock::ButtonClicked()
{
if (switcher->th && switcher->th->isRunning()) {
switcher->Stop();
SetStopped();
} else {
switcher->Start();
SetStarted();
}
}
void StatusDock::UpdateStatus()
{
if (switcher->th && switcher->th->isRunning()) {
SetStopped();
} else {
SetStarted();
}
}
void StatusDock::SetStopped()
{
_button->setText(
obs_module_text("AdvSceneSwitcher.generalTab.status.stop"));
_status->setText(obs_module_text("AdvSceneSwitcher.status.active"));
}
void StatusDock::SetStarted()
{
_button->setText(
obs_module_text("AdvSceneSwitcher.generalTab.status.start"));
_status->setText(obs_module_text("AdvSceneSwitcher.status.inactive"));
}
void saveDock(obs_data_t *obj)
{
obs_data_set_bool(obj, "statusDockVisible", dock->isVisible());
obs_data_set_bool(obj, "statusDockFloating", dock->isFloating());
obs_data_set_int(obj, "statusDockPosX", dock->pos().x());
obs_data_set_int(obj, "statusDockPosY", dock->pos().y());
obs_data_set_int(obj, "statusDockPosWidth", dock->width());
obs_data_set_int(obj, "statusDockPosHeight", dock->height());
}
void loadDock(obs_data_t *obj)
{
dock->setVisible(obs_data_get_bool(obj, "statusDockVisible"));
dock->setFloating(obs_data_get_bool(obj, "statusDockFloating"));
QPoint pos = {
static_cast<int>(obs_data_get_int(obj, "statusDockPosX")),
static_cast<int>(obs_data_get_int(obj, "statusDockPosY"))};
if (windowPosValid(pos)) {
dock->resize(obs_data_get_int(obj, "statusDockPosWidth"),
obs_data_get_int(obj, "statusDockPosHeight"));
dock->move(pos);
}
}

View File

@@ -3,7 +3,6 @@ Most of this code is based on https://github.com/Palakis/obs-websocket
*/
#include <QtWidgets/QMainWindow>
#include <QtConcurrent/QtConcurrent>
#include <QTime>
#include <QMessageBox>
@@ -188,11 +187,11 @@ void WSServer::start(quint16 port, bool lockToIPv4)
_server.start_accept();
QtConcurrent::run([=]() {
_threadPool.start(Compatability::CreateFunctionRunnable([=]() {
blog(LOG_INFO, "WSServer::start: io thread started");
_server.run();
blog(LOG_INFO, "WSServer::start: io thread exited");
});
}));
switcher->serverStatus = ServerStatus::RUNNING;
blog(LOG_INFO,
@@ -320,12 +319,12 @@ void WSServer::onMessage(connection_hdl, server::message_ptr message)
return;
}
QtConcurrent::run(&_threadPool, [=]() {
_threadPool.start(Compatability::CreateFunctionRunnable([=]() {
if (message->get_payload() != "message ok") {
blog(LOG_WARNING, "received response: %s",
message->get_payload().c_str());
}
});
}));
}
void WSServer::onClose(connection_hdl hdl)
@@ -693,3 +692,19 @@ void AdvSceneSwitcher::updateClientStatus()
break;
}
}
void Compatability::StdFunctionRunnable::run()
{
cb();
}
QRunnable *Compatability::CreateFunctionRunnable(std::function<void()> func)
{
return new Compatability::StdFunctionRunnable(std::move(func));
}
Compatability::StdFunctionRunnable::StdFunctionRunnable(
std::function<void()> func)
: cb(std::move(func))
{
}

View File

@@ -68,7 +68,6 @@ TransitionSelectionWidget::TransitionSelectionWidget(QWidget *parent,
bool current, bool any)
: QComboBox(parent)
{
// For the rare occasion of a name conflict with current / previous
setDuplicatesEnabled(true);
populateTransitionSelection(this, current, any);
@@ -81,7 +80,6 @@ void TransitionSelectionWidget::SetTransition(TransitionSelection &t)
// Order of entries
// 1. Any transition
// 2. Current transition
// 3. Previous transition
// 4. Transitions
int idx;
@@ -112,9 +110,12 @@ void TransitionSelectionWidget::SetTransition(TransitionSelection &t)
void TransitionSelectionWidget::Repopulate(bool current, bool any)
{
this->clear();
populateTransitionSelection(this, current, any);
setCurrentIndex(0);
{
const QSignalBlocker blocker(this);
clear();
populateTransitionSelection(this, current, any);
setCurrentIndex(0);
}
TransitionSelection t;
emit TransitionChanged(t);
}