Compare commits

...

29 Commits

Author SHA1 Message Date
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
WarmUpTill
016d963598 Fix volume not changing when selecting fade with a duration of 0s 2022-01-04 19:32:53 -08:00
WarmUpTill
d31ae77176 Run macros even if they are paused when pressing "Run Macro" 2022-01-04 19:32:53 -08:00
WarmUpTill
2c1b97e5cd Abort macro early if it was paused 2022-01-05 03:39:37 +01:00
WarmUpTill
c498d1509a Adjust locale 2022-01-05 02:54:39 +01:00
WarmUpTill
2d61189655 Display message on first boot 2022-01-04 17:16:38 -08:00
WarmUpTill
82c20b871b Don't ask to backup settings if there is nothing to backup 2022-01-04 17:16:38 -08:00
WarmUpTill
bd52ef8e84 Don't abort build if OpenVR cannot be found 2022-01-04 15:50:26 -08:00
WarmUpTill
59e1ddd31e Add openvr condition 2022-01-04 15:50:26 -08:00
WarmUpTill
a320d78a08 Separate OpenCV dependency into its own lib
This should avoid issues of the whole plugin not loading if OpenCV is
not available.
This approach should also work for possible future external
dependencies.
2022-01-03 18:22:02 -08:00
WarmUpTill
ce5730428c Remove unnecessary uses of UNUSED_PARAMETER macro 2022-01-03 13:48:21 -08:00
WarmUpTill
f7b9795014 Add option to check if source is muted 2022-01-03 13:48:21 -08:00
WarmUpTill
3417fc5407 Add status dock 2022-01-03 11:32:22 -08:00
WarmUpTill
2649efe8b3 Adjust to SceneItemSelection and SceneItemSelectionWidget 2022-01-03 08:52:32 -08:00
WarmUpTill
3af5897427 Rename function 2022-01-03 08:52:32 -08:00
WarmUpTill
92877a6b30 Add SceneItemSelection and SceneItemSelectionWidget
Allows selecting individual scene items if there are duplicate entries
for the same source.
2022-01-03 08:52:32 -08:00
WarmUpTill
fbdaffcbf6 Clean up formatJsonString() 2022-01-03 08:52:32 -08:00
WarmUpTill
ba111c6caa Add action to import settings from file 2022-01-01 18:26:40 -08:00
WarmUpTill
5c8760ac0a Add action to switch scene collection 2022-01-01 18:26:40 -08:00
WarmUpTill
e0cca2a0d4 Add action to switch profile 2022-01-01 18:26:40 -08:00
WarmUpTill
d69aba8ab7 Remove dependency to SceneSwitcherEntry and SwitchWidget 2021-12-28 05:07:37 -08:00
WarmUpTill
a2ba7adc56 Add option to wait for transition to complete 2021-12-28 05:07:37 -08:00
WarmUpTill
0881146a25 Fix startup behavior not loading correctly 2021-12-22 13:12:41 -08:00
WarmUpTill
5224d6589e Reduce log output when running macro in background 2021-12-22 13:12:27 -08:00
WarmUpTill
15eeec8ebf Add condition "Studio Mode"
Can be used to check whether or not studio mode is active or to check
the current preview scene
2021-12-22 13:12:27 -08:00
WarmUpTill
ed7f375d64 Fix crash when reordering macros 2021-12-22 13:12:27 -08:00
64 changed files with 2628 additions and 692 deletions

View File

@@ -4,46 +4,45 @@ on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: check_libobs_revision
run: |
sudo apt update
sudo apt install libobs-dev
mkdir source
cd source
dpkg -l libobs-dev | tr -s " "| grep libobs | cut -d" " -f3 > libobs.rev
- name: install_frontend_header
run: |
[ -e /usr/include/obs/obs-frontend-api.h ] && { echo "ERROR: obs-frontend-api.h already in system. Maybe the package libobs-dev is installing it."; exit 1; }
cd source
LIBOBSREV=$(cat libobs.rev)
sudo apt update
sudo apt install devscripts
dget -u http://archive.ubuntu.com/ubuntu/pool/universe/o/obs-studio/obs-studio_$LIBOBSREV.dsc
cd ..
sudo find -name obs-frontend-api.h -exec cp {} /usr/include/obs/ \;
egrep '#include <obs.h>' /usr/include/obs/obs-frontend-api.h || { echo "ERROR: check if the sed commands are needed from now."; exit 1; }
sudo sed -i 's/#include <obs.h>/#include <obs\/obs.h>/' /usr/include/obs/obs-frontend-api.h
sudo sed -i 's/#include <util\/darray.h>/#include <obs\/util\/darray.h>/' /usr/include/obs/obs-frontend-api.h
- name: create_tarball
run: |
cd ..
tar --exclude=.git -cvzf obs-scene-switcher_0.1+testonly.orig.tar.gz SceneSwitcher
- name: create_debian_dir
run: |
cp -a CI/linux/debian .
- name: install_dependencies
run: |
# devscripts and libobs-dev are needed but they were already installed
# from check_libobs_revision and install_frontend_header sections.
sudo apt update
sudo apt install cmake debhelper libcurl4-openssl-dev libxss-dev libxtst-dev qtbase5-dev libopencv-dev libprocps-dev
- name: build
run: |
debuild --no-lintian --no-sign
- uses: actions/checkout@v2
with:
submodules: "recursive"
- name: check_libobs_revision
run: |
sudo apt update
sudo apt install libobs-dev
mkdir source
cd source
dpkg -l libobs-dev | tr -s " "| grep libobs | cut -d" " -f3 > libobs.rev
- name: install_frontend_header
run: |
[ -e /usr/include/obs/obs-frontend-api.h ] && { echo "ERROR: obs-frontend-api.h already in system. Maybe the package libobs-dev is installing it."; exit 1; }
cd source
LIBOBSREV=$(cat libobs.rev)
sudo apt update
sudo apt install devscripts
dget -u http://archive.ubuntu.com/ubuntu/pool/universe/o/obs-studio/obs-studio_$LIBOBSREV.dsc
cd ..
sudo find -name obs-frontend-api.h -exec cp {} /usr/include/obs/ \;
egrep '#include <obs.h>' /usr/include/obs/obs-frontend-api.h || { echo "ERROR: check if the sed commands are needed from now."; exit 1; }
sudo sed -i 's/#include <obs.h>/#include <obs\/obs.h>/' /usr/include/obs/obs-frontend-api.h
sudo sed -i 's/#include <util\/darray.h>/#include <obs\/util\/darray.h>/' /usr/include/obs/obs-frontend-api.h
- name: create_tarball
run: |
cd ..
tar --exclude=.git -cvzf obs-scene-switcher_0.1+testonly.orig.tar.gz SceneSwitcher
- name: create_debian_dir
run: |
cp -a CI/linux/debian .
- name: install_dependencies
run: |
# devscripts and libobs-dev are needed but they were already installed
# from check_libobs_revision and install_frontend_header sections.
sudo apt update
sudo apt install cmake debhelper libcurl4-openssl-dev libxss-dev libxtst-dev qtbase5-dev libopencv-dev libprocps-dev
- name: build
run: |
debuild --no-lintian --no-sign

View File

@@ -12,25 +12,25 @@ jobs:
name: "macOS 64-bit"
runs-on: [macos-latest]
env:
QT_VERSION: '5.15.2'
MACOS_DEPS_VERSION: '2020-12-11'
QT_VERSION: "5.15.2"
MACOS_DEPS_VERSION: "2020-12-11"
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
with:
repository: obsproject/obs-studio
submodules: 'recursive'
ref: 'refs/tags/${{ env.OBS_TAG }}'
submodules: "recursive"
ref: "refs/tags/${{ env.OBS_TAG }}"
- name: "Checkout plugin"
uses: actions/checkout@v2.3.4
with:
path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
submodules: 'recursive'
submodules: "recursive"
- name: Fetch Git Tags
run: |
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}
git fetch --prune --tags --unshallow
- name: 'Install prerequisites (Homebrew)'
- name: "Install prerequisites (Homebrew)"
shell: bash
run: |
if [ -d /usr/local/opt/openssl@1.0.2t ]; then
@@ -42,20 +42,20 @@ jobs:
brew untap local/python2
fi
brew bundle --file ./CI/scripts/macos/Brewfile
- name: 'Install prerequisite: Pre-built dependencies'
- name: "Install prerequisite: Pre-built dependencies"
if: steps.deps-cache.outputs.cache-hit != 'true'
shell: bash
run: |
curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.MACOS_DEPS_VERSION }}/macos-deps-${{ env.MACOS_DEPS_VERSION }}.tar.gz
tar -xf ./macos-deps-${{ env.MACOS_DEPS_VERSION }}.tar.gz -C "/tmp"
- name: 'Install prerequisite: Pre-built dependency Qt'
- name: "Install prerequisite: Pre-built dependency Qt"
if: steps.deps-qt-cache.outputs.cache-hit != 'true'
shell: bash
run: |
curl -L -O https://github.com/obsproject/obs-deps/releases/download/${{ env.MACOS_DEPS_VERSION }}/macos-qt-${{ env.QT_VERSION }}-${{ env.MACOS_DEPS_VERSION }}.tar.gz
tar -xf ./macos-qt-${{ env.QT_VERSION }}-${{ env.MACOS_DEPS_VERSION }}.tar.gz -C "/tmp"
xattr -r -d com.apple.quarantine /tmp/obsdeps
- name: 'Build prerequisite: OpenCV'
- name: "Build prerequisite: OpenCV"
shell: bash
run: |
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}/deps/opencv
@@ -79,7 +79,7 @@ jobs:
cd ./build
make -j4
cd -
- name: 'Install prerequisite: Packages app'
- name: "Install prerequisite: Packages app"
if: success()
shell: bash
run: |
@@ -90,12 +90,16 @@ jobs:
if: success()
shell: bash
run: |
fix_linker_paths() {
install_name_tool -change @rpath/libobs-frontend-api.dylib @executable_path/../Frameworks/libobs-frontend-api.dylib $1
install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib $1
install_name_tool -change /tmp/obsdeps/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets $1
install_name_tool -change /tmp/obsdeps/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui $1
install_name_tool -change /tmp/obsdeps/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore $1
}
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}
install_name_tool -change @rpath/libobs-frontend-api.dylib @executable_path/../Frameworks/libobs-frontend-api.dylib ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /tmp/obsdeps/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /tmp/obsdeps/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /tmp/obsdeps/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
fix_linker_paths ../../../build/UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
fix_linker_paths ../../../build/UI/frontend-plugins/SceneSwitcher/src/external-macro-modules/opencv/advanced-scene-switcher-opencv.so
FILE_DATE=$(date +%Y-%m-%d)
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-macos.pkg
echo "FILE_NAME=${FILE_NAME}" >> $GITHUB_ENV
@@ -107,23 +111,23 @@ jobs:
if: success()
uses: actions/upload-artifact@v2.2.1
with:
name: '${{ env.FILE_NAME }}'
name: "${{ env.FILE_NAME }}"
path: ./nightly/*.pkg
ubuntu64:
name: 'Linux/Ubuntu 64-bit'
name: "Linux/Ubuntu 64-bit"
runs-on: [ubuntu-latest]
steps:
- name: Checkout
uses: actions/checkout@v2.3.4
with:
repository: obsproject/obs-studio
submodules: 'recursive'
ref: 'refs/tags/${{ env.OBS_TAG }}'
submodules: "recursive"
ref: "refs/tags/${{ env.OBS_TAG }}"
- name: "Checkout plugin"
uses: actions/checkout@v2.3.4
with:
path: UI/frontend-plugins/${{ env.PLUGIN_NAME }}
submodules: 'recursive'
submodules: "recursive"
- name: Add plugin to obs cmake
shell: bash
run: echo "add_subdirectory(${{ env.PLUGIN_NAME }})" >> UI/frontend-plugins/CMakeLists.txt
@@ -181,17 +185,17 @@ jobs:
libxcb-xfixes0-dev \
libopencv-dev \
libprocps-dev
- name: 'Configure'
- name: "Configure"
shell: bash
run: |
mkdir ./build
cd ./build
cmake -DENABLE_PIPEWIRE=OFF -DUNIX_STRUCTURE=0 -DCMAKE_INSTALL_PREFIX="${{ github.workspace }}/obs-studio-portable" -DWITH_RTMPS=OFF -DBUILD_BROWSER=OFF ..
- name: 'Build'
- name: "Build"
shell: bash
working-directory: ${{ github.workspace }}/build
run: make -j4
- name: 'Package'
- name: "Package"
shell: bash
run: |
FILE_DATE=$(date +%Y-%m-%d)
@@ -201,12 +205,15 @@ jobs:
strip -d ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/${{ env.LIB_NAME }}.so
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
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/
tar -cvzf "${FILE_NAME}" ${{ env.LIB_NAME }}
- name: 'Publish'
- name: "Publish"
uses: actions/upload-artifact@v2.2.1
with:
name: '${{ env.FILE_NAME }}'
path: '*.tar.gz'
name: "${{ env.FILE_NAME }}"
path: "*.tar.gz"
windows:
name: Windows
runs-on: [windows-latest]
@@ -217,7 +224,7 @@ jobs:
QT_VERSION: 5.10.1
CMAKE_GENERATOR: "Visual Studio 16 2019"
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
WINDOWS_DEPS_VERSION: '2019'
WINDOWS_DEPS_VERSION: "2019"
steps:
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.0.2
@@ -225,27 +232,27 @@ jobs:
uses: actions/checkout@v2.3.4
with:
repository: obsproject/obs-studio
submodules: 'recursive'
ref: 'refs/tags/${{ env.OBS_TAG }}'
submodules: "recursive"
ref: "refs/tags/${{ env.OBS_TAG }}"
- name: Checkout plugin
uses: actions/checkout@v2.3.4
with:
path: UI/frontend-plugins/${{ env.PLUGIN_NAME}}
submodules: 'recursive'
submodules: "recursive"
- name: Add plugin to obs cmake
shell: cmd
run: echo add_subdirectory(${{ env.PLUGIN_NAME }}) >> UI/frontend-plugins/CMakeLists.txt
- name: Fetch Git Tags
run: git fetch --prune --tags --unshallow
- name: 'Install prerequisite: QT'
- name: "Install prerequisite: QT"
run: |
curl -kLO https://cdn-fastly.obsproject.com/downloads/Qt_${{ env.QT_VERSION }}.7z -f --retry 5 -C -
7z x Qt_${{ env.QT_VERSION }}.7z -o"${{ github.workspace }}/cmbuild/QT"
- name: 'Install prerequisite: Pre-built dependencies'
- name: "Install prerequisite: Pre-built dependencies"
run: |
curl -kLO https://cdn-fastly.obsproject.com/downloads/dependencies${{ env.WINDOWS_DEPS_VERSION }}.zip -f --retry 5 -C -
7z x dependencies${{ env.WINDOWS_DEPS_VERSION }}.zip -o"${{ github.workspace }}/cmbuild/deps"
- name: 'Build prerequisite: OpenCV'
- name: "Build prerequisite: OpenCV"
run: |
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}/deps/opencv
mkdir build
@@ -283,19 +290,20 @@ jobs:
$env:FILE_DATE=(Get-Date -UFormat "%F")
$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 ${{ env.LIB_NAME }}* /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
exit 0
- name: Publish zip
if: success()
uses: actions/upload-artifact@v2.2.1
with:
name: '${{ env.FILE_NAME }}-${{ matrix.arch }}bit'
name: "${{ env.FILE_NAME }}-${{ matrix.arch }}bit"
path: package/*
windows-installer:
needs: [windows]
name: 'Create Windows Installer'
name: "Create Windows Installer"
runs-on: [windows-latest]
steps:
- name: "Checkout plugin"
@@ -332,12 +340,12 @@ jobs:
if: success()
uses: actions/upload-artifact@v2.2.0
with:
name: '${{ env.FILE_NAME }}-installer'
name: "${{ env.FILE_NAME }}-installer"
path: build/CI/windows/Output/*.exe
release:
needs: [macos64, ubuntu64, windows, windows-installer]
name: 'Create Release'
runs-on: [ubuntu-18.04]
name: "Create Release"
runs-on: [ubuntu-latest]
steps:
- name: "Checkout plugin"
uses: actions/checkout@v2.3.4
@@ -347,7 +355,7 @@ jobs:
uses: actions/download-artifact@v2
with:
path: artifacts
- name: 'Package'
- name: "Package"
shell: bash
run: |
mkdir -p ${{ env.PLUGIN_NAME }}/Linux ${{ env.PLUGIN_NAME }}/MacOs ${{ env.PLUGIN_NAME }}/Windows
@@ -366,4 +374,4 @@ jobs:
uses: actions/upload-artifact@v2.2.1
with:
name: "Release"
path: '*.zip'
path: "*.zip"

3
.gitmodules vendored
View File

@@ -7,3 +7,6 @@
[submodule "deps/opencv"]
path = deps/opencv
url = https://github.com/opencv/opencv.git
[submodule "deps/openvr"]
path = deps/openvr
url = https://github.com/ValveSoftware/openvr.git

View File

@@ -46,6 +46,22 @@
<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/>

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

@@ -8,6 +8,7 @@ endif()
# Compiler settings
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED YES)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
if(CMAKE_COMPILER_IS_GNUCC
OR CMAKE_COMPILER_IS_GNUCXX
@@ -110,6 +111,7 @@ endif()
# Platform specific settings
if(APPLE)
set(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
find_library(COCOA Cocoa)
if(BUILD_OUT_OF_TREE)
find_package(Qt5MacExtras REQUIRED)
@@ -197,10 +199,12 @@ set(advanced-scene-switcher_HEADERS
src/headers/macro-action-media.hpp
src/headers/macro-action-plugin-state.hpp
src/headers/macro-action-preview-scene.hpp
src/headers/macro-action-profile.hpp
src/headers/macro-action-random.hpp
src/headers/macro-action-recording.hpp
src/headers/macro-action-replay-buffer.hpp
src/headers/macro-action-run.hpp
src/headers/macro-action-scene-collection.hpp
src/headers/macro-action-scene-order.hpp
src/headers/macro-action-scene-swap.hpp
src/headers/macro-action-scene-switch.hpp
@@ -234,9 +238,9 @@ set(advanced-scene-switcher_HEADERS
src/headers/macro-condition-scene.hpp
src/headers/macro-condition-source.hpp
src/headers/macro-condition-streaming.hpp
src/headers/macro-condition-studio-mode.hpp
src/headers/macro-condition-timer.hpp
src/headers/macro-condition-transition.hpp
src/headers/macro-condition-video.hpp
src/headers/macro-condition-virtual-cam.hpp
src/headers/macro-condition-window.hpp
src/headers/macro.hpp
@@ -245,6 +249,7 @@ set(advanced-scene-switcher_HEADERS
src/headers/macro-selection.hpp
src/headers/curl-helper.hpp
src/headers/hotkey.hpp
src/headers/scene-item-selection.hpp
src/headers/scene-selection.hpp
src/headers/screenshot-helper.hpp
src/headers/transition-selection.hpp
@@ -252,6 +257,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/platform-funcs.hpp
src/headers/utility.hpp
src/headers/volume-control.hpp
@@ -292,10 +298,12 @@ set(advanced-scene-switcher_SOURCES
src/macro-action-media.cpp
src/macro-action-plugin-state.cpp
src/macro-action-preview-scene.cpp
src/macro-action-profile.cpp
src/macro-action-random.cpp
src/macro-action-recording.cpp
src/macro-action-replay-buffer.cpp
src/macro-action-run.cpp
src/macro-action-scene-collection.cpp
src/macro-action-scene-order.cpp
src/macro-action-scene-swap.cpp
src/macro-action-scene-switch.cpp
@@ -329,9 +337,9 @@ set(advanced-scene-switcher_SOURCES
src/macro-condition-scene.cpp
src/macro-condition-source.cpp
src/macro-condition-streaming.cpp
src/macro-condition-studio-mode.cpp
src/macro-condition-timer.cpp
src/macro-condition-transition.cpp
src/macro-condition-video.cpp
src/macro-condition-virtual-cam.cpp
src/macro-condition-window.cpp
src/macro.cpp
@@ -340,32 +348,18 @@ set(advanced-scene-switcher_SOURCES
src/macro-selection.cpp
src/macro-tab.cpp
src/curl-helper.cpp
src/scene-item-selection.cpp
src/scene-selection.cpp
src/screenshot-helper.cpp
src/transition-selection.cpp
src/name-dialog.cpp
src/duration-control.cpp
src/status-dock.cpp
src/section.cpp
src/utility.cpp
src/volume-control.cpp
src/version.cpp)
# opencv
find_package(OpenCV)
if(OpenCV_FOUND)
include_directories("${OpenCV_INCLUDE_DIRS}")
else()
set(OpenCV_LIBRARIES "")
message(
WARNING
"OpenCV not found! Functionality relying on OpenCV will be disabled!\nOpenCV sources are available under: ${CMAKE_CURRENT_SOURCE_DIR}/deps/opencv"
)
list(REMOVE_ITEM advanced-scene-switcher_SOURCES
src/macro-condition-video.cpp)
list(REMOVE_ITEM advanced-scene-switcher_HEADERS
src/headers/macro-condition-video.hpp)
endif()
# Backwards compatability checks with older OBS versions
if(DEFINED LibObs_VERSION_MAJOR)
if(LibObs_VERSION_MAJOR GREATER_EQUAL 27)
@@ -391,7 +385,7 @@ if(DEFINED LibObs_VERSION_MAJOR)
endif()
add_library(
advanced-scene-switcher MODULE
advanced-scene-switcher SHARED
${advanced-scene-switcher_HEADERS}
${advanced-scene-switcher_SOURCES}
${advanced-scene-switcher_UI_HEADERS}
@@ -401,13 +395,8 @@ add_library(
# Out of tree build
if(BUILD_OUT_OF_TREE)
target_link_libraries(
advanced-scene-switcher
${advanced-scene-switcher_PLATFORM_LIBS}
${OpenCV_LIBRARIES}
${LIBOBS_LIB}
${LIBOBS_FRONTEND_API_LIB}
Qt5::Core
Qt5::Widgets)
advanced-scene-switcher ${advanced-scene-switcher_PLATFORM_LIBS}
${LIBOBS_LIB} ${LIBOBS_FRONTEND_API_LIB} Qt5::Core Qt5::Widgets)
# Additional commands to install the module in the correct place. Find all the
# translation files so we can copy them to the correct place later on.
@@ -438,6 +427,8 @@ else()
# In tree build
target_link_libraries(
advanced-scene-switcher ${advanced-scene-switcher_PLATFORM_LIBS}
${OpenCV_LIBRARIES} obs-frontend-api Qt5::Widgets libobs)
obs-frontend-api Qt5::Widgets libobs)
install_obs_plugin_with_data(advanced-scene-switcher data)
endif()
add_subdirectory(src/external-macro-modules)

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"
@@ -87,8 +88,10 @@ AdvSceneSwitcher.logic.not="If not"
; Macro Conditions
AdvSceneSwitcher.condition.audio="Audio"
AdvSceneSwitcher.condition.audio.state.below="Below"
AdvSceneSwitcher.condition.audio.state.above="Above"
AdvSceneSwitcher.condition.audio.state.below="below"
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.cursor="Cursor"
AdvSceneSwitcher.condition.cursor.type.region="is in region"
@@ -102,8 +105,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"
@@ -214,7 +218,7 @@ AdvSceneSwitcher.condition.sceneOrder.type.above="Is above"
AdvSceneSwitcher.condition.sceneOrder.type.below="Is below"
AdvSceneSwitcher.condition.sceneOrder.type.position="Is at position"
AdvSceneSwitcher.condition.sceneOrder.positionInfo="The position value starts at the bottom with 0 and increases by one for each scene item including the ones in scene groups"
AdvSceneSwitcher.condition.sceneOrder.entry="On {{scenes}} {{sources}} {{conditions}} {{sources2}} {{position}}"
AdvSceneSwitcher.condition.sceneOrder.entry="On{{scenes}}{{sources}}{{conditions}}{{sources2}}{{position}}"
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"
@@ -234,7 +238,7 @@ AdvSceneSwitcher.condition.date.entry.line2="{{repeat}} Repeat every {{duration}
AdvSceneSwitcher.condition.sceneTransform="Scene item transform"
AdvSceneSwitcher.condition.sceneTransform.getTransform="Get transform"
AdvSceneSwitcher.condition.sceneTransform.regex="Use regular expressions"
AdvSceneSwitcher.condition.sceneTransform.entry.line1="On {{scenes}} {{sources}} matches transform"
AdvSceneSwitcher.condition.sceneTransform.entry.line1="On{{scenes}}{{sources}}matches transform"
AdvSceneSwitcher.condition.sceneTransform.entry.line2="{{settings}}"
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}} {{getSettings}}"
AdvSceneSwitcher.condition.transition="Transition"
@@ -249,11 +253,22 @@ AdvSceneSwitcher.condition.transition.entry="{{conditions}}{{transitions}}{{scen
AdvSceneSwitcher.condition.sceneVisibility="Scene item visibility"
AdvSceneSwitcher.condition.sceneVisibility.type.shown="Shown"
AdvSceneSwitcher.condition.sceneVisibility.type.hidden="Hidden"
AdvSceneSwitcher.condition.sceneVisibility.entry="On {{scenes}} {{sources}} is {{conditions}} "
AdvSceneSwitcher.condition.sceneVisibility.entry="On{{scenes}}{{sources}}is{{conditions}}"
AdvSceneSwitcher.condition.studioMode="Studio mode"
AdvSceneSwitcher.condition.studioMode.state.active="Studio mode is active"
AdvSceneSwitcher.condition.studioMode.state.notActive="Studio mode is not active"
AdvSceneSwitcher.condition.studioMode.state.previewScene="Preview scene is"
AdvSceneSwitcher.condition.studioMode.entry="{{conditions}}{{scenes}}"
AdvSceneSwitcher.condition.openvr="OpenVR"
AdvSceneSwitcher.condition.errorStatus="OpenVR error: "
AdvSceneSwitcher.condition.openvr.entry.line1="HMD is in ..."
AdvSceneSwitcher.condition.openvr.entry.line2="{{controls}}"
AdvSceneSwitcher.condition.openvr.entry.line3="HMD is currently at {{xPos}} x {{yPos}} x {{zPos}}"
; Macro Actions
AdvSceneSwitcher.action.switchScene="Switch scene"
AdvSceneSwitcher.action.scene.entry="Switch to scene {{scenes}} using {{transitions}} with a duration of {{duration}} seconds"
AdvSceneSwitcher.action.scene.blockUntilTransitionDone="Wait until transition to target scene is complete"
AdvSceneSwitcher.action.wait="Wait"
AdvSceneSwitcher.action.wait.type.fixed="fixed"
AdvSceneSwitcher.action.wait.type.random="random"
@@ -292,7 +307,7 @@ AdvSceneSwitcher.action.sceneVisibility.type.show="Show"
AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Any"
AdvSceneSwitcher.action.sceneVisibility.entry="On {{scenes}} {{actions}} {{sourceTypes}} {{sources}}"
AdvSceneSwitcher.action.sceneVisibility.entry="On{{scenes}}{{actions}}{{sourceTypes}}{{sources}}{{sourceGroups}}"
AdvSceneSwitcher.action.filter="Filter"
AdvSceneSwitcher.action.filter.type.enable="Enable"
AdvSceneSwitcher.action.filter.type.disable="Disable"
@@ -323,7 +338,9 @@ AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
AdvSceneSwitcher.action.pluginState="Plugin state"
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
AdvSceneSwitcher.action.pluginState.type.noMatch="Change the no-match behaviour:"
AdvSceneSwitcher.action.pluginState.entry="{{actions}} {{values}} {{scenes}}"
AdvSceneSwitcher.action.pluginState.type.import="Import settings from"
AdvSceneSwitcher.action.pluginState.importWarning="Note: Action will be ignored while settings window is opened."
AdvSceneSwitcher.action.pluginState.entry="{{actions}}{{values}}{{scenes}}{{settings}}{{settingsWarning}}"
AdvSceneSwitcher.action.virtualCamera="Virtual camera"
AdvSceneSwitcher.action.virtualCamera.type.stop="Stop virtual camera"
AdvSceneSwitcher.action.virtualCamera.type.start="Start virtual camera"
@@ -346,10 +363,10 @@ AdvSceneSwitcher.action.sceneOrder.type.moveDown="Move down"
AdvSceneSwitcher.action.sceneOrder.type.moveTop="Move to top"
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="Move to bottom"
AdvSceneSwitcher.action.sceneOrder.type.movePosition="Move to position"
AdvSceneSwitcher.action.sceneOrder.entry="On {{scenes}} {{actions}} {{sources}} {{position}}"
AdvSceneSwitcher.action.sceneOrder.entry="On{{scenes}}{{actions}}{{sources}}{{position}}"
AdvSceneSwitcher.action.sceneTransform="Scene item transform"
AdvSceneSwitcher.action.sceneTransform.getTransform="Get transform"
AdvSceneSwitcher.action.sceneTransform.entry="On {{scenes}} transform {{sources}}"
AdvSceneSwitcher.action.sceneTransform.entry="On{{scenes}}transform{{sources}}"
AdvSceneSwitcher.action.file="File"
AdvSceneSwitcher.action.file.type.write="Write"
AdvSceneSwitcher.action.file.type.append="Append"
@@ -374,6 +391,11 @@ AdvSceneSwitcher.action.systray.entry="Show notification: {{message}}"
AdvSceneSwitcher.action.screenshot="Screenshot"
AdvSceneSwitcher.action.screenshot.mainOutput="OBS's main output"
AdvSceneSwitcher.action.screenshot.entry="Screenshot {{sources}}"
AdvSceneSwitcher.action.profile="Profile"
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."
; Transition Tab
AdvSceneSwitcher.transitionTab.title="Transition"
@@ -643,16 +665,22 @@ AdvSceneSwitcher.selectProcess="--select process--"
AdvSceneSwitcher.selectFilter="--select filter--"
AdvSceneSwitcher.selectMacro="--select macro--"
AdvSceneSwitcher.selectItem="--select item--"
AdvSceneSwitcher.selectProfile="--select profile--"
AdvSceneSwitcher.selectSceneCollection="--select scene collection--"
AdvSceneSwitcher.enterPath="--enter path--"
AdvSceneSwitcher.enterText="--enter text--"
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="invalid entries will not be saved"
AdvSceneSwitcher.selectWindowTip="Use \"OBS\" to specify OBS window\nUse \"Task Switching\"to specify ALT + TAB"
AdvSceneSwitcher.sceneItemSelection.all="All"
AdvSceneSwitcher.sceneItemSelection.any="Any"
AdvSceneSwitcher.status.active="Active"
AdvSceneSwitcher.status.inactive="Inactive"
AdvSceneSwitcher.running="Plugin running"
AdvSceneSwitcher.stopped="Plugin stopped"
AdvSceneSwitcher.firstBootMessage="<html><head/><body><p>This seems to be the first time the Advanced Scene Switcher was started.<br>Please have a look at the <a href=\"https://github.com/WarmUpTill/SceneSwitcher/wiki\"><span style=\" text-decoration: underline; color:#268bd2;\">Wiki</span></a> for a list of guides and examples.<br>Do not hesitate to ask questions in the plugin's <a href=\"https://obsproject.com/forum/threads/advanced-scene-switcher.48264\"><span style=\" text-decoration: underline; color:#268bd2;\">thread</span></a> on the OBS forums!</p></body></html>"
AdvSceneSwitcher.unit.milliseconds="milliseconds"
AdvSceneSwitcher.unit.secends="seconds"
AdvSceneSwitcher.unit.minutes="minutes"

1
deps/openvr vendored Submodule

Submodule deps/openvr added at 4c85abcb7f

View File

@@ -729,7 +729,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 +754,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 +790,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>767</width>
<width>792</width>
<height>218</height>
</rect>
</property>
@@ -882,7 +889,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>767</width>
<width>792</width>
<height>218</height>
</rect>
</property>

View File

@@ -1,6 +1,7 @@
#include <QMainWindow>
#include <QAction>
#include <QFileDialog>
#include <QDirIterator>
#include <regex>
#include <filesystem>
@@ -8,11 +9,16 @@
#include <obs-frontend-api.h>
#include "headers/advanced-scene-switcher.hpp"
#include "headers/status-dock.hpp"
#include "headers/curl-helper.hpp"
#include "headers/utility.hpp"
#include "headers/version.h"
SwitcherData *switcher = nullptr;
SwitcherData *GetSwitcher()
{
return switcher;
}
/******************************************************************************
* Create the Advanced Scene Switcher settings window
@@ -81,6 +87,7 @@ void AdvSceneSwitcher::loadUI()
setTabOrder();
restoreWindowGeo();
checkFirstTimeSetup();
loading = false;
}
@@ -100,7 +107,6 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
} else {
// Stop the scene switcher at least once to
// avoid scene duplication issues with scene collection changes
bool start = !switcher->stop;
switcher->Stop();
switcher->m.lock();
@@ -116,7 +122,7 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
obs_data_release(obj);
switcher->m.unlock();
if (start) {
if (!switcher->stop) {
switcher->Start();
}
}
@@ -414,6 +420,7 @@ void SwitcherData::Stop()
cv.notify_all();
abortMacroWait = true;
macroWaitCv.notify_all();
macroTransitionCv.notify_all();
th->wait();
delete th;
th = nullptr;
@@ -552,6 +559,7 @@ void setTranstionEnd()
{
switcher->lastTransitionEndTime =
std::chrono::high_resolution_clock::now();
switcher->macroTransitionCv.notify_all();
}
void setStreamStarting()
@@ -616,6 +624,26 @@ 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);
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());
}
}
}
AdvSceneSwitcher *ssWindow;
extern "C" void InitSceneSwitcher()
@@ -623,9 +651,6 @@ extern "C" void InitSceneSwitcher()
blog(LOG_INFO, "version: %s", g_GIT_TAG);
blog(LOG_INFO, "version: %s", g_GIT_SHA1);
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
obs_module_text("AdvSceneSwitcher.pluginName"));
switcher = new SwitcherData;
if (loadCurl() && f_curl_init) {
@@ -633,6 +658,14 @@ 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);
auto cb = []() {
if (switcher->settingsWindowOpened) {
@@ -640,8 +673,9 @@ extern "C" void InitSceneSwitcher()
ssWindow->raise();
ssWindow->activateWindow();
} else {
ssWindow = new AdvSceneSwitcher(
(QMainWindow *)obs_frontend_get_main_window());
ssWindow =
new AdvSceneSwitcher(static_cast<QMainWindow *>(
obs_frontend_get_main_window()));
ssWindow->setAttribute(Qt::WA_DeleteOnClose);
ssWindow->show();
}
@@ -650,5 +684,7 @@ extern "C" void InitSceneSwitcher()
obs_frontend_add_save_callback(SaveSceneSwitcher, nullptr);
obs_frontend_add_event_callback(OBSEvent, switcher);
QAction *action = (QAction *)obs_frontend_add_tools_menu_qaction(
obs_module_text("AdvSceneSwitcher.pluginName"));
action->connect(action, &QAction::triggered, cb);
}

View File

@@ -0,0 +1,5 @@
# 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.
add_subdirectory(opencv)
add_subdirectory(openvr)

View File

@@ -0,0 +1,50 @@
cmake_minimum_required(VERSION 3.14)
project(advanced-scene-switcher-opencv)
add_definitions(-DADVSS_MODULE)
find_package(OpenCV)
if(OpenCV_FOUND)
include_directories("${OpenCV_INCLUDE_DIRS}")
else()
set(OpenCV_LIBRARIES "")
message(
WARNING
"OpenCV not found! Functionality relying on OpenCV will be disabled!\nOpenCV sources are available under: ${CMAKE_CURRENT_SOURCE_DIR}/deps/opencv"
)
return()
endif()
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../headers")
set(module_SOURCES macro-condition-video.cpp macro-condition-video.hpp)
add_library(advanced-scene-switcher-opencv MODULE ${module_SOURCES})
if(BUILD_OUT_OF_TREE)
target_link_libraries(
advanced-scene-switcher-opencv
advanced-scene-switcher
${LIBOBS_LIB}
${LIBOBS_FRONTEND_API_LIB}
${OpenCV_LIBRARIES}
Qt5::Core
Qt5::Widgets)
if(UNIX AND NOT APPLE)
if(NOT LIB_OUT_DIR)
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})
endif()
else()
target_link_libraries(
advanced-scene-switcher-opencv
advanced-scene-switcher
obs-frontend-api
${OpenCV_LIBRARIES}
Qt5::Core
Qt5::Widgets
libobs)
install_obs_plugin(advanced-scene-switcher-opencv)
endif()

View File

@@ -1,7 +1,9 @@
#include "headers/macro-condition-edit.hpp"
#include "headers/macro-condition-video.hpp"
#include "headers/utility.hpp"
#include "headers/advanced-scene-switcher.hpp"
#include "macro-condition-video.hpp"
#include <advanced-scene-switcher.hpp>
#include <macro-condition-edit.hpp>
#include <switcher-data-structs.hpp>
#include <utility.hpp>
#include <QFileDialog>
#include <QBuffer>
@@ -450,9 +452,9 @@ MacroConditionVideoEdit::MacroConditionVideoEdit(
_throttleEnable = new QCheckBox();
_throttleCount = new QSpinBox();
_throttleCount->setMinimum(1 * switcher->interval);
_throttleCount->setMaximum(10 * switcher->interval);
_throttleCount->setSingleStep(switcher->interval);
_throttleCount->setMinimum(1 * GetSwitcher()->interval);
_throttleCount->setMaximum(10 * GetSwitcher()->interval);
_throttleCount->setSingleStep(GetSwitcher()->interval);
_showMatch = new QPushButton(
obs_module_text("AdvSceneSwitcher.condition.video.showMatch"));
@@ -595,7 +597,7 @@ void MacroConditionVideoEdit::SourceChanged(const QString &text)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_videoSource = GetWeakSourceByQString(text);
_entryData->ResetLastMatch();
emit HeaderInfoChanged(
@@ -608,7 +610,7 @@ void MacroConditionVideoEdit::ConditionChanged(int cond)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_condition = static_cast<VideoCondition>(cond);
_entryData->ResetLastMatch();
SetWidgetVisibility();
@@ -634,7 +636,7 @@ void MacroConditionVideoEdit::ImagePathChanged(const QString &text)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_file = text.toUtf8().constData();
_entryData->ResetLastMatch();
if (_entryData->LoadImageFromFile()) {
@@ -712,7 +714,7 @@ void MacroConditionVideoEdit::UsePatternForChangedCheckChanged(int value)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_usePatternForChangedCheck = value;
_patternThreshold->setVisible(value);
adjustSize();
@@ -724,7 +726,7 @@ void MacroConditionVideoEdit::PatternThresholdChanged(double value)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_patternThreshold = value;
}
@@ -734,7 +736,7 @@ void MacroConditionVideoEdit::UseAlphaAsMaskChanged(int value)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_useAlphaAsMask = value;
_entryData->LoadImageFromFile();
}
@@ -745,7 +747,7 @@ void MacroConditionVideoEdit::ObjectScaleThresholdChanged(double value)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_scaleFactor = value;
}
@@ -755,7 +757,7 @@ void MacroConditionVideoEdit::MinNeighborsChanged(int value)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_minNeighbors = value;
}
@@ -765,7 +767,7 @@ void MacroConditionVideoEdit::MinSizeXChanged(int value)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_minSizeX = value;
}
@@ -775,7 +777,7 @@ void MacroConditionVideoEdit::MinSizeYChanged(int value)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_minSizeY = value;
}
@@ -785,7 +787,7 @@ void MacroConditionVideoEdit::MaxSizeXChanged(int value)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_maxSizeX = value;
}
@@ -795,7 +797,7 @@ void MacroConditionVideoEdit::MaxSizeYChanged(int value)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_maxSizeY = value;
}
@@ -805,7 +807,7 @@ void MacroConditionVideoEdit::ThrottleEnableChanged(int value)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_throttleEnabled = value;
_throttleCount->setEnabled(value);
}
@@ -816,8 +818,8 @@ void MacroConditionVideoEdit::ThrottleCountChanged(int value)
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_throttleCount = value / switcher->interval;
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_throttleCount = value / GetSwitcher()->interval;
}
QImage markPatterns(cv::Mat &matchResult, QImage &image, QImage &pattern)
@@ -907,7 +909,7 @@ void MacroConditionVideoEdit::ModelPathChanged(const QString &text)
bool dataLoaded = false;
{
std::lock_guard<std::mutex> lock(switcher->m);
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
std::string path = text.toStdString();
dataLoaded = _entryData->LoadModelData(path);
}
@@ -1003,6 +1005,6 @@ void MacroConditionVideoEdit::UpdateEntryData()
_maxSizeY->setValue(_entryData->_maxSizeY);
_throttleEnable->setChecked(_entryData->_throttleEnabled);
_throttleCount->setValue(_entryData->_throttleCount *
switcher->interval);
GetSwitcher()->interval);
SetWidgetVisibility();
}

View File

@@ -1,7 +1,7 @@
#pragma once
#include "macro.hpp"
#include "screenshot-helper.hpp"
#include "file-selection.hpp"
#include <macro.hpp>
#include <screenshot-helper.hpp>
#include <file-selection.hpp>
#include <QWidget>
#include <QComboBox>

View File

@@ -0,0 +1,89 @@
cmake_minimum_required(VERSION 3.14)
project(advanced-scene-switcher-openvr)
if(NOT WIN32)
message(
WARNING "OpenVR condition is only supported on Windows builds for now.")
return()
endif(NOT WIN32)
add_definitions(-DADVSS_MODULE)
# openvr
if(NOT OpenVR_DIR)
set(OpenVR_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../deps/openvr)
endif()
if(EXISTS ${OpenVR_DIR})
set(SIZEOF_VOIDP ${CMAKE_SIZEOF_VOID_P})
if((NOT APPLE) AND (CMAKE_SIZEOF_VOID_P EQUAL 8))
set(PROCESSOR_ARCH "64")
else()
set(PROCESSOR_ARCH "32")
endif()
if(WIN32)
set(PLATFORM_NAME "win")
elseif(UNIX AND NOT APPLE)
if(CMAKE_SYSTEM_NAME MATCHES ".*Linux")
set(PLATFORM_NAME "linux")
endif()
elseif(APPLE)
if(CMAKE_SYSTEM_NAME MATCHES ".*Darwin.*" OR CMAKE_SYSTEM_NAME MATCHES
".*MacOS.*")
set(PLATFORM_NAME "osx")
endif()
endif()
set(OpenVR_INCLUDE_DIRS ${OpenVR_DIR}/headers)
set(OpenVR_BINARIES
${OpenVR_DIR}/bin/${PLATFORM_NAME}${PROCESSOR_ARCH}/${CMAKE_SHARED_LIBRARY_PREFIX}openvr_api${CMAKE_SHARED_LIBRARY_SUFFIX}
)
set(OpenVR_LIBRARIES
${OpenVR_DIR}/lib/${PLATFORM_NAME}${PROCESSOR_ARCH}/${CMAKE_SHARED_LIBRARY_PREFIX}openvr_api${CMAKE_IMPORT_LIBRARY_SUFFIX}
)
set(OpenVR_FOUND TRUE)
endif()
if(OpenVR_FOUND)
include_directories("${OpenVR_INCLUDE_DIRS}")
else()
set(OpenVR_LIBRARIES "")
message(
WARNING
"OpenVR not found! Functionality relying on OpenVR will be disabled!\nOpenVR sources are available under: ${CMAKE_CURRENT_SOURCE_DIR}/deps/openvr"
return
())
endif()
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/../../headers")
set(module_SOURCES macro-condition-openvr.cpp macro-condition-openvr.hpp)
add_library(advanced-scene-switcher-openvr MODULE ${module_SOURCES})
if(BUILD_OUT_OF_TREE)
target_link_libraries(
advanced-scene-switcher-openvr
advanced-scene-switcher
${LIBOBS_LIB}
${LIBOBS_FRONTEND_API_LIB}
${OpenVR_LIBRARIES}
Qt5::Core
Qt5::Widgets)
if(UNIX AND NOT APPLE)
if(NOT LIB_OUT_DIR)
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})
endif()
else()
target_link_libraries(
advanced-scene-switcher-openvr
advanced-scene-switcher
obs-frontend-api
${OpenVR_LIBRARIES}
Qt5::Core
Qt5::Widgets
libobs)
install_obs_plugin(advanced-scene-switcher-openvr)
endif()

View File

@@ -0,0 +1,297 @@
#include "macro-condition-openvr.hpp"
#include <macro-condition-edit.hpp>
#include <utility.hpp>
#include <advanced-scene-switcher.hpp>
#include <openvr.h>
const std::string MacroConditionOpenVR::id = "openvr";
bool MacroConditionOpenVR::_registered = MacroConditionFactory::Register(
MacroConditionOpenVR::id,
{MacroConditionOpenVR::Create, MacroConditionOpenVREdit::Create,
"AdvSceneSwitcher.condition.openvr"});
static vr::IVRSystem *openvrSystem;
std::mutex openvrMutex;
std::condition_variable openvrCV;
void processOpenVREvents()
{
std::unique_lock<std::mutex> lock(openvrMutex);
vr::VREvent_t event;
while (true) {
if (openvrSystem->PollNextEvent(&event, sizeof(event)) &&
event.eventType == vr::VREvent_Quit) {
openvrSystem->AcknowledgeQuit_Exiting();
vr::VR_Shutdown();
openvrSystem = nullptr;
break;
}
openvrCV.wait_for(lock, std::chrono::milliseconds(100));
}
blog(LOG_INFO, "stop handling openVR events");
}
void initOpenVR(vr::EVRInitError &err)
{
openvrSystem = vr::VR_Init(&err, vr::VRApplication_Background);
if (openvrSystem) {
// Don't kill OBS if SteamVR is exiting
std::thread t(processOpenVREvents);
t.detach();
}
}
struct TrackingData {
float x, y, z;
bool valid = false;
};
TrackingData getOpenVRPos(vr::EVRInitError &err)
{
TrackingData data;
std::unique_lock<std::mutex> lock(openvrMutex);
if (!openvrSystem) {
initOpenVR(err);
}
if (openvrSystem && vr::VRCompositor() &&
openvrSystem->IsTrackedDeviceConnected(0)) {
vr::TrackedDevicePose_t poses[vr::k_unMaxTrackedDeviceCount];
openvrSystem->GetDeviceToAbsoluteTrackingPose(
vr::TrackingUniverseStanding, 0.0, poses,
vr::k_unMaxTrackedDeviceCount);
auto hmdPose = poses[vr::k_unTrackedDeviceIndex_Hmd];
auto mat = hmdPose.mDeviceToAbsoluteTracking.m;
data.x = mat[0][3];
data.y = mat[1][3];
data.z = mat[2][3];
data.valid = true;
}
return data;
}
bool MacroConditionOpenVR::CheckCondition()
{
vr::EVRInitError err;
TrackingData data = getOpenVRPos(err);
if (!data.valid) {
return false;
}
return data.x >= _minX && data.y >= _minY && data.z >= _minZ &&
data.x <= _maxX && data.y <= _maxY && data.z <= _maxZ;
}
bool MacroConditionOpenVR::Save(obs_data_t *obj)
{
MacroCondition::Save(obj);
obs_data_set_double(obj, "minX", _minX);
obs_data_set_double(obj, "minY", _minY);
obs_data_set_double(obj, "minZ", _minZ);
obs_data_set_double(obj, "maxX", _maxX);
obs_data_set_double(obj, "maxY", _maxY);
obs_data_set_double(obj, "maxZ", _maxZ);
return true;
}
bool MacroConditionOpenVR::Load(obs_data_t *obj)
{
MacroCondition::Load(obj);
_minX = obs_data_get_double(obj, "minX");
_minY = obs_data_get_double(obj, "minY");
_minZ = obs_data_get_double(obj, "minZ");
_maxX = obs_data_get_double(obj, "maxX");
_maxY = obs_data_get_double(obj, "maxY");
_maxZ = obs_data_get_double(obj, "maxZ");
return true;
}
MacroConditionOpenVREdit::MacroConditionOpenVREdit(
QWidget *parent, std::shared_ptr<MacroConditionOpenVR> entryData)
: QWidget(parent)
{
_minX = new QDoubleSpinBox();
_minY = new QDoubleSpinBox();
_minZ = new QDoubleSpinBox();
_maxX = new QDoubleSpinBox();
_maxY = new QDoubleSpinBox();
_maxZ = new QDoubleSpinBox();
_xPos = new QLabel("-");
_yPos = new QLabel("-");
_zPos = new QLabel("-");
_errLabel = new QLabel();
_errLabel->setVisible(false);
_minX->setPrefix("Min X: ");
_minY->setPrefix("Min Y: ");
_minZ->setPrefix("Min Z: ");
_maxX->setPrefix("Max X: ");
_maxY->setPrefix("Max Y: ");
_maxZ->setPrefix("Max Z: ");
_minX->setMinimum(-99);
_minY->setMinimum(-99);
_minZ->setMinimum(-99);
_maxX->setMinimum(-99);
_maxY->setMinimum(-99);
_maxZ->setMinimum(-99);
_minX->setMaximum(99);
_minY->setMaximum(99);
_minZ->setMaximum(99);
_maxX->setMaximum(99);
_maxY->setMaximum(99);
_maxZ->setMaximum(99);
QWidget::connect(_minX, SIGNAL(valueChanged(double)), this,
SLOT(MinXChanged(double)));
QWidget::connect(_minY, SIGNAL(valueChanged(double)), this,
SLOT(MinYChanged(double)));
QWidget::connect(_minZ, SIGNAL(valueChanged(double)), this,
SLOT(MinZChanged(double)));
QWidget::connect(_maxX, SIGNAL(valueChanged(double)), this,
SLOT(MaxXChanged(double)));
QWidget::connect(_maxY, SIGNAL(valueChanged(double)), this,
SLOT(MaxYChanged(double)));
QWidget::connect(_maxZ, SIGNAL(valueChanged(double)), this,
SLOT(MaxZChanged(double)));
QGridLayout *controlsLayout = new QGridLayout;
controlsLayout->addWidget(_minX, 0, 0);
controlsLayout->addWidget(_minY, 0, 1);
controlsLayout->addWidget(_minZ, 0, 2);
controlsLayout->addWidget(_maxX, 1, 0);
controlsLayout->addWidget(_maxY, 1, 1);
controlsLayout->addWidget(_maxZ, 1, 2);
QWidget *controls = new QWidget;
controls->setLayout(controlsLayout);
controls->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{controls}}", controls},
{"{{xPos}}", _xPos},
{"{{yPos}}", _yPos},
{"{{zPos}}", _zPos},
};
QHBoxLayout *line1 = new QHBoxLayout;
placeWidgets(obs_module_text(
"AdvSceneSwitcher.condition.openvr.entry.line1"),
line1, widgetPlaceholders);
QHBoxLayout *line2 = new QHBoxLayout;
placeWidgets(obs_module_text(
"AdvSceneSwitcher.condition.openvr.entry.line2"),
line2, widgetPlaceholders);
QHBoxLayout *line3 = new QHBoxLayout;
placeWidgets(obs_module_text(
"AdvSceneSwitcher.condition.openvr.entry.line3"),
line3, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(line1);
mainLayout->addLayout(line2);
mainLayout->addLayout(line3);
mainLayout->addWidget(_errLabel);
setLayout(mainLayout);
connect(&_timer, &QTimer::timeout, this,
&MacroConditionOpenVREdit::UpdateOpenVRPos);
_timer.start(1000);
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
void MacroConditionOpenVREdit::MinXChanged(double pos)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_minX = pos;
}
void MacroConditionOpenVREdit::MinYChanged(double pos)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_minY = pos;
}
void MacroConditionOpenVREdit::MinZChanged(double pos)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_minZ = pos;
}
void MacroConditionOpenVREdit::MaxXChanged(double pos)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_maxX = pos;
}
void MacroConditionOpenVREdit::MaxYChanged(double pos)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_maxY = pos;
}
void MacroConditionOpenVREdit::MaxZChanged(double pos)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(GetSwitcher()->m);
_entryData->_maxZ = pos;
}
void MacroConditionOpenVREdit::UpdateOpenVRPos()
{
vr::EVRInitError err;
TrackingData data = getOpenVRPos(err);
if (data.valid) {
_xPos->setText(QString::number(data.x));
_yPos->setText(QString::number(data.y));
_zPos->setText(QString::number(data.z));
} else {
_xPos->setText("-");
_yPos->setText("-");
_zPos->setText("-");
_errLabel->setText(
QString(obs_module_text(
"AdvSceneSwitcher.condition.errorStatus")) +
QString(vr::VR_GetVRInitErrorAsEnglishDescription(err)));
}
_errLabel->setVisible(!data.valid);
adjustSize();
}
void MacroConditionOpenVREdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
_minX->setValue(_entryData->_minX);
_minY->setValue(_entryData->_minY);
_maxX->setValue(_entryData->_maxX);
_maxY->setValue(_entryData->_maxY);
}

View File

@@ -0,0 +1,68 @@
#pragma once
#include <macro.hpp>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QPushButton>
#include <QTimer>
class MacroConditionOpenVR : public MacroCondition {
public:
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()
{
return std::make_shared<MacroConditionOpenVR>();
}
double _minX = 0, _minY = 0, _minZ = 0, _maxX = 0, _maxY = 0, _maxZ = 0;
private:
static bool _registered;
static const std::string id;
};
class MacroConditionOpenVREdit : public QWidget {
Q_OBJECT
public:
MacroConditionOpenVREdit(
QWidget *parent,
std::shared_ptr<MacroConditionOpenVR> cond = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroCondition> cond)
{
return new MacroConditionOpenVREdit(
parent,
std::dynamic_pointer_cast<MacroConditionOpenVR>(cond));
}
private slots:
void MinXChanged(double pos);
void MinYChanged(double pos);
void MinZChanged(double pos);
void MaxXChanged(double pos);
void MaxYChanged(double pos);
void MaxZChanged(double pos);
void UpdateOpenVRPos();
protected:
QDoubleSpinBox *_minX;
QDoubleSpinBox *_minY;
QDoubleSpinBox *_minZ;
QDoubleSpinBox *_maxX;
QDoubleSpinBox *_maxY;
QDoubleSpinBox *_maxZ;
QLabel *_xPos;
QLabel *_yPos;
QLabel *_zPos;
QLabel *_errLabel;
std::shared_ptr<MacroConditionOpenVR> _entryData;
private:
QTimer _timer;
bool _loading = true;
};

View File

@@ -1,9 +1,9 @@
#include "headers/advanced-scene-switcher.hpp"
#include "headers/status-dock.hpp"
#include "headers/utility.hpp"
#include "headers/version.h"
#include <QFileDialog>
#include <QGuiApplication>
#include <QStandardPaths>
QMetaObject::Connection inactivePluse;
@@ -436,11 +436,6 @@ void AdvSceneSwitcher::setTabOrder()
connect(bar, &QTabBar::tabMoved, this, &AdvSceneSwitcher::on_tabMoved);
}
bool windowPosValid(QPoint pos)
{
return !!QGuiApplication::screenAt(pos);
}
void AdvSceneSwitcher::restoreWindowGeo()
{
if (switcher->saveWindowGeo && windowPosValid(switcher->windowPos)) {
@@ -449,6 +444,14 @@ void AdvSceneSwitcher::restoreWindowGeo()
}
}
void AdvSceneSwitcher::checkFirstTimeSetup()
{
if (switcher->firstBoot && !switcher->disableHints) {
DisplayMessage(
obs_module_text("AdvSceneSwitcher.firstBootMessage"));
}
}
void AdvSceneSwitcher::on_tabMoved(int from, int to)
{
if (loading) {
@@ -458,10 +461,8 @@ void AdvSceneSwitcher::on_tabMoved(int from, int to)
std::swap(switcher->tabOrder[from], switcher->tabOrder[to]);
}
void AdvSceneSwitcher::on_tabWidget_currentChanged(int index)
void AdvSceneSwitcher::on_tabWidget_currentChanged(int)
{
UNUSED_PARAMETER(index);
switcher->showFrame = false;
clearFrames(ui->screenRegionSwitches);
SetShowFrames();
@@ -492,6 +493,7 @@ void SwitcherData::loadSettings(obs_data_t *obj)
loadSceneTriggers(obj);
loadGeneralSettings(obj);
loadHotkeys(obj);
loadDock(obj);
}
void SwitcherData::saveSettings(obs_data_t *obj)
@@ -522,6 +524,7 @@ void SwitcherData::saveSettings(obs_data_t *obj)
saveSceneTriggers(obj);
saveGeneralSettings(obj);
saveHotkeys(obj);
saveDock(obj);
saveVersion(obj, g_GIT_SHA1);
}

View File

@@ -1,6 +1,8 @@
#pragma once
#ifdef BUILD_OUT_OF_TREE
#include "../../forms/ui_advanced-scene-switcher.h"
#elif defined ADVSS_MODULE
#include "../../../ui_advanced-scene-switcher.h"
#else
#include "ui_advanced-scene-switcher.h"
#endif
@@ -81,6 +83,7 @@ public:
void setupMacroTab();
void setTabOrder();
void restoreWindowGeo();
void checkFirstTimeSetup();
signals:
void MacroAdded(const QString &name);
@@ -117,6 +120,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();
@@ -297,3 +301,4 @@ void AskForBackup(obs_data_t *obj);
******************************************************************************/
struct SwitcherData;
extern SwitcherData *switcher;
SwitcherData *GetSwitcher();

View File

@@ -1,12 +1,14 @@
#pragma once
#include "macro-action-edit.hpp"
#include "file-selection.hpp"
#include <QDoubleSpinBox>
#include <QHBoxLayout>
#include <QLabel>
enum class PluginStateAction {
STOP,
NO_MATCH_BEHAVIOUR,
IMPORT_SETTINGS,
};
class MacroActionPluginState : public MacroAction {
@@ -23,6 +25,7 @@ public:
PluginStateAction _action = PluginStateAction::STOP;
int _value = 0;
std::string _settingsPath;
OBSWeakSource _scene;
private:
@@ -51,15 +54,17 @@ private slots:
void ActionChanged(int value);
void ValueChanged(int value);
void SceneChanged(const QString &text);
void PathChanged(const QString &text);
protected:
QComboBox *_actions;
QComboBox *_values;
QComboBox *_scenes;
FileSelection *_settings;
QLabel *_settingsWarning;
std::shared_ptr<MacroActionPluginState> _entryData;
private:
void SetWidgetVisibility(PluginStateAction, int);
QHBoxLayout *_mainLayout;
void SetWidgetVisibility();
bool _loading = true;
};

View File

@@ -0,0 +1,51 @@
#pragma once
#include "macro-action-edit.hpp"
class MacroActionProfile : public MacroAction {
public:
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()
{
return std::make_shared<MacroActionProfile>();
}
std::string _profile;
private:
static bool _registered;
static const std::string id;
};
class MacroActionProfileEdit : public QWidget {
Q_OBJECT
public:
MacroActionProfileEdit(
QWidget *parent,
std::shared_ptr<MacroActionProfile> entryData = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionProfileEdit(
parent,
std::dynamic_pointer_cast<MacroActionProfile>(action));
}
private slots:
void ProfileChanged(const QString &text);
signals:
void HeaderInfoChanged(const QString &);
protected:
QComboBox *_profiles;
std::shared_ptr<MacroActionProfile> _entryData;
private:
bool _loading = true;
};

View File

@@ -0,0 +1,52 @@
#pragma once
#include "macro-action-edit.hpp"
class MacroActionSceneCollection : public MacroAction {
public:
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()
{
return std::make_shared<MacroActionSceneCollection>();
}
std::string _sceneCollection;
private:
static bool _registered;
static const std::string id;
};
class MacroActionSceneCollectionEdit : public QWidget {
Q_OBJECT
public:
MacroActionSceneCollectionEdit(
QWidget *parent,
std::shared_ptr<MacroActionSceneCollection> entryData = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionSceneCollectionEdit(
parent,
std::dynamic_pointer_cast<MacroActionSceneCollection>(
action));
}
private slots:
void SceneCollectionChanged(const QString &text);
signals:
void HeaderInfoChanged(const QString &);
protected:
QComboBox *_sceneCollections;
std::shared_ptr<MacroActionSceneCollection> _entryData;
private:
bool _loading = true;
};

View File

@@ -1,7 +1,9 @@
#pragma once
#include <QSpinBox>
#include "macro-action-edit.hpp"
#include "scene-selection.hpp"
#include "scene-item-selection.hpp"
#include <QSpinBox>
enum class SceneOrderAction {
MOVE_UP,
@@ -25,7 +27,7 @@ public:
}
SceneSelection _scene;
OBSWeakSource _source;
SceneItemSelection _source;
SceneOrderAction _action = SceneOrderAction::MOVE_UP;
int _position = 0;
@@ -53,7 +55,7 @@ public:
private slots:
void SceneChanged(const SceneSelection &);
void SourceChanged(const QString &text);
void SourceChanged(const SceneItemSelection &);
void ActionChanged(int value);
void PositionChanged(int value);
signals:
@@ -61,7 +63,7 @@ signals:
protected:
SceneSelectionWidget *_scenes;
QComboBox *_sources;
SceneItemSelectionWidget *_sources;
QComboBox *_actions;
QSpinBox *_position;
std::shared_ptr<MacroActionSceneOrder> _entryData;

View File

@@ -1,11 +1,12 @@
#pragma once
#include "macro-action-edit.hpp"
#include "switch-generic.hpp"
#include "scene-selection.hpp"
#include "transition-selection.hpp"
#include "duration-control.hpp"
// TODO: Switch to using SceneSelection class and widget instead
#include <QCheckBox>
class MacroActionSwitchScene : public MacroAction, public SceneSwitcherEntry {
class MacroActionSwitchScene : public MacroAction {
public:
bool PerformAction();
void LogAction();
@@ -18,7 +19,10 @@ public:
{
return std::make_shared<MacroActionSwitchScene>();
}
SceneSelection _scene;
TransitionSelection _transition;
Duration _duration;
bool _blockUntilTransitionDone = true;
private:
const char *getType() { return "MacroActionSwitchScene"; }
@@ -27,7 +31,7 @@ private:
static const std::string id;
};
class MacroActionSwitchSceneEdit : public SwitchWidget {
class MacroActionSwitchSceneEdit : public QWidget {
Q_OBJECT
public:
@@ -44,12 +48,21 @@ public:
}
private slots:
void SceneChanged(const SceneSelection &);
void TransitionChanged(const TransitionSelection &);
void DurationChanged(double seconds);
void ChangeHeaderInfo(const QString &);
void BlockUntilTransitionDoneChanged(int state);
signals:
void HeaderInfoChanged(const QString &);
protected:
SceneSelectionWidget *_scenes;
TransitionSelectionWidget *_transitions;
DurationSelection *_duration;
QCheckBox *_blockUntilTransitionDone;
std::shared_ptr<MacroActionSwitchScene> _entryData;
private:
bool _loading = true;
};

View File

@@ -1,8 +1,10 @@
#pragma once
#include <QSpinBox>
#include <QPlainTextEdit>
#include "macro-action-edit.hpp"
#include "scene-selection.hpp"
#include "scene-item-selection.hpp"
#include <QSpinBox>
#include <QPlainTextEdit>
class MacroActionSceneTransform : public MacroAction {
public:
@@ -20,7 +22,7 @@ public:
void SetSettings(std::string &);
SceneSelection _scene;
OBSWeakSource _source;
SceneItemSelection _source;
struct obs_transform_info _info = {};
struct obs_sceneitem_crop _crop = {};
@@ -48,7 +50,7 @@ public:
private slots:
void SceneChanged(const SceneSelection &);
void SourceChanged(const QString &text);
void SourceChanged(const SceneItemSelection &);
void GetSettingsClicked();
void SettingsChanged();
signals:
@@ -56,7 +58,7 @@ signals:
protected:
SceneSelectionWidget *_scenes;
QComboBox *_sources;
SceneItemSelectionWidget *_sources;
QPushButton *_getSettings;
QPlainTextEdit *_settings;
std::shared_ptr<MacroActionSceneTransform> _entryData;

View File

@@ -1,7 +1,9 @@
#pragma once
#include <QSpinBox>
#include "macro-action-edit.hpp"
#include "scene-selection.hpp"
#include "scene-item-selection.hpp"
#include <QSpinBox>
enum class SceneVisibilityAction {
SHOW,
@@ -28,7 +30,7 @@ public:
SceneSelection _scene;
SceneItemSourceType _sourceType = SceneItemSourceType::SOURCE;
OBSWeakSource _source;
SceneItemSelection _source;
std::string _sourceGroup = "";
SceneVisibilityAction _action = SceneVisibilityAction::SHOW;
@@ -57,7 +59,8 @@ public:
private slots:
void SceneChanged(const SceneSelection &);
void SourceTypeChanged(int value);
void SourceChanged(const QString &text);
void SourceChanged(const SceneItemSelection &);
void SourceGroupChanged(const QString &text);
void ActionChanged(int value);
signals:
void HeaderInfoChanged(const QString &);
@@ -65,11 +68,14 @@ signals:
protected:
SceneSelectionWidget *_scenes;
QComboBox *_sourceTypes;
QComboBox *_sources;
SceneItemSelectionWidget *_sources;
QComboBox *_sourceGroups;
QComboBox *_actions;
std::shared_ptr<MacroActionSceneVisibility> _entryData;
private:
void SetWidgetVisibility();
QHBoxLayout *_mainLayout;
bool _loading = true;
};

View File

@@ -9,6 +9,8 @@
enum class AudioCondition {
ABOVE,
BELOW,
MUTE,
UNMUTE,
};
class MacroConditionAudio : public MacroCondition {
@@ -72,5 +74,7 @@ protected:
std::shared_ptr<MacroConditionAudio> _entryData;
private:
void SetWidgetVisibility();
bool _loading = true;
};

View File

@@ -1,6 +1,7 @@
#pragma once
#include "macro.hpp"
#include "scene-selection.hpp"
#include "scene-item-selection.hpp"
#include <QWidget>
#include <QComboBox>
@@ -24,8 +25,8 @@ public:
}
SceneSelection _scene;
OBSWeakSource _source;
OBSWeakSource _source2;
SceneItemSelection _source;
SceneItemSelection _source2;
int _position = 0;
SceneOrderCondition _condition = SceneOrderCondition::ABOVE;
@@ -53,8 +54,8 @@ public:
private slots:
void SceneChanged(const SceneSelection &);
void SourceChanged(const QString &text);
void Source2Changed(const QString &text);
void SourceChanged(const SceneItemSelection &);
void Source2Changed(const SceneItemSelection &);
void ConditionChanged(int cond);
void PositionChanged(int cond);
signals:
@@ -63,8 +64,8 @@ signals:
protected:
SceneSelectionWidget *_scenes;
QComboBox *_conditions;
QComboBox *_sources;
QComboBox *_sources2;
SceneItemSelectionWidget *_sources;
SceneItemSelectionWidget *_sources2;
QSpinBox *_position;
QLabel *_posInfo;

View File

@@ -1,6 +1,7 @@
#pragma once
#include "macro.hpp"
#include "scene-selection.hpp"
#include "scene-item-selection.hpp"
#include <QSpinBox>
#include <QPlainTextEdit>
@@ -19,7 +20,7 @@ public:
}
SceneSelection _scene;
OBSWeakSource _source;
SceneItemSelection _source;
bool _regex = false;
std::string _settings = "";
@@ -48,7 +49,7 @@ public:
private slots:
void SceneChanged(const SceneSelection &);
void SourceChanged(const QString &text);
void SourceChanged(const SceneItemSelection &);
void GetSettingsClicked();
void SettingsChanged();
void RegexChanged(int);
@@ -57,7 +58,7 @@ signals:
protected:
SceneSelectionWidget *_scenes;
QComboBox *_sources;
SceneItemSelectionWidget *_sources;
QPushButton *_getSettings;
QPlainTextEdit *_settings;
QCheckBox *_regex;

View File

@@ -1,6 +1,7 @@
#pragma once
#include "macro.hpp"
#include "scene-selection.hpp"
#include "scene-item-selection.hpp"
#include <QComboBox>
@@ -22,7 +23,7 @@ public:
}
SceneSelection _scene;
OBSWeakSource _source;
SceneItemSelection _source;
SceneVisibilityCondition _condition = SceneVisibilityCondition::SHOWN;
private:
@@ -49,14 +50,14 @@ public:
private slots:
void SceneChanged(const SceneSelection &);
void SourceChanged(const QString &text);
void SourceChanged(const SceneItemSelection &);
void ConditionChanged(int cond);
signals:
void HeaderInfoChanged(const QString &);
protected:
SceneSelectionWidget *_scenes;
QComboBox *_sources;
SceneItemSelectionWidget *_sources;
QComboBox *_conditions;
std::shared_ptr<MacroConditionSceneVisibility> _entryData;

View File

@@ -25,12 +25,12 @@ public:
return std::make_shared<MacroConditionScene>();
}
// 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 +57,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

@@ -0,0 +1,65 @@
#pragma once
#include "macro.hpp"
#include "scene-selection.hpp"
#include <QWidget>
#include <QComboBox>
enum class StudioModeCondition {
STUDIO_MODE_ACTIVE,
STUDIO_MODE_NOT_ACTIVE,
PREVIEW_SCENE,
};
class MacroConditionStudioMode : public MacroCondition {
public:
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()
{
return std::make_shared<MacroConditionStudioMode>();
}
StudioModeCondition _condition =
StudioModeCondition::STUDIO_MODE_ACTIVE;
SceneSelection _scene;
private:
static bool _registered;
static const std::string id;
};
class MacroConditionStudioModeEdit : public QWidget {
Q_OBJECT
public:
MacroConditionStudioModeEdit(
QWidget *parent,
std::shared_ptr<MacroConditionStudioMode> cond = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroCondition> cond)
{
return new MacroConditionStudioModeEdit(
parent,
std::dynamic_pointer_cast<MacroConditionStudioMode>(
cond));
}
private slots:
void ConditionChanged(int cond);
void SceneChanged(const SceneSelection &);
signals:
void HeaderInfoChanged(const QString &);
protected:
QComboBox *_condition;
SceneSelectionWidget *_scenes;
std::shared_ptr<MacroConditionStudioMode> _entryData;
private:
void SetWidgetVisibility();
bool _loading = true;
};

View File

@@ -73,7 +73,8 @@ public:
virtual ~Macro();
bool CeckMatch();
bool PerformAction(bool forceParallel = false);
bool PerformAction(bool forceParallel = false,
bool ignorePause = false);
bool Matched() { return _matched; }
std::string Name() { return _name; }
void SetName(const std::string &name);
@@ -81,6 +82,8 @@ 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; };
std::deque<std::shared_ptr<MacroCondition>> &Conditions()
@@ -105,14 +108,16 @@ private:
void ClearHotkeys();
void SetHotkeysDesc();
void ResetTimers();
void RunActions(bool &ret);
void RunActions();
void RunActions(bool &ret, bool ignorePause);
void RunActions(bool ignorePause);
std::string _name = "";
std::deque<std::shared_ptr<MacroCondition>> _conditions;
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;

View File

@@ -0,0 +1,59 @@
#pragma once
#include <QComboBox>
#include <obs-data.h>
#include "scene-selection.hpp"
#include "utility.hpp"
class SceneItemSelection {
public:
void Save(obs_data_t *obj, const char *name = "sceneItem",
const char *targetName = "sceneItemTarget",
const char *idxName = "sceneItemIdx");
void Load(obs_data_t *obj, const char *name = "sceneItem",
const char *targetName = "sceneItemTarget",
const char *idxName = "sceneItemIdx");
enum class Target { ALL, ANY, INDIVIDUAL };
Target GetType() { return _target; }
std::vector<obs_scene_item *> GetSceneItems(SceneSelection &s);
std::string ToString();
private:
OBSWeakSource _sceneItem;
Target _target = Target::ALL;
int _idx = 0;
friend class SceneItemSelectionWidget;
};
class SceneItemSelectionWidget : public QWidget {
Q_OBJECT
public:
enum class AllSelectionType { ALL, ANY };
SceneItemSelectionWidget(
QWidget *parent, bool allSelection = true,
AllSelectionType allType = AllSelectionType::ALL);
void SetSceneItem(const SceneItemSelection &);
void SetScene(const SceneSelection &);
void SetShowAll(bool);
void SetShowAllSelectionType(AllSelectionType t);
signals:
void SceneItemChanged(const SceneItemSelection &);
private slots:
void SceneChanged(const SceneSelection &);
void SelectionChanged(const QString &name);
void IdxChanged(int);
private:
void SetupIdxSelection(int);
QComboBox *_sceneItems;
QComboBox *_idx;
SceneSelection _scene;
OBSWeakSource _sceneItem;
bool _showAll = false;
AllSelectionType _allType = AllSelectionType::ALL;
};

View File

@@ -0,0 +1,30 @@
#pragma once
#include <QDockWidget>
#include <QPushButton>
#include <QLabel>
#include <QTimer>
#include <obs-data.h>
class StatusDock : public QDockWidget {
Q_OBJECT
public:
StatusDock(QWidget *parent = 0);
private slots:
void ButtonClicked();
void UpdateStatus();
private:
void SetStopped();
void SetStarted();
QPushButton *_button;
QLabel *_status;
QTimer _timer;
};
extern StatusDock *dock;
void saveDock(obs_data_t *obj);
void loadDock(obs_data_t *obj);

View File

@@ -77,6 +77,7 @@ struct SwitcherData {
SwitcherThread *th = nullptr;
bool settingsWindowOpened = false;
bool firstBoot = true;
std::condition_variable cv;
std::mutex m;
@@ -117,6 +118,7 @@ struct SwitcherData {
std::deque<std::shared_ptr<Macro>> macros;
std::condition_variable macroWaitCv;
std::atomic_bool abortMacroWait = {false};
std::condition_variable macroTransitionCv;
bool macroSceneSwitched = false;
bool replayBufferSaved = false;

View File

@@ -27,13 +27,13 @@ std::string getSourceSettings(OBSWeakSource ws);
void setSourceSettings(obs_source_t *s, const std::string &settings);
bool compareSourceSettings(const OBSWeakSource &source,
const std::string &settings, bool regex);
std::vector<obs_scene_item *> getSceneItemsWithName(OBSScene scene,
std::vector<obs_scene_item *> getSceneItemsWithName(obs_scene_t *scene,
std::string &name);
std::string getDataFilePath(const std::string &file);
bool matchJson(const std::string &json1, const std::string &json2,
bool useRegex);
QString formatJsonString(std::string);
QString formatJsonString(const char *);
QString formatJsonString(QString);
QString escapeForRegex(QString &s);
void loadTransformState(obs_data_t *obj, struct obs_transform_info &info,
struct obs_sceneitem_crop &crop);
@@ -81,4 +81,5 @@ void populateFilterSelection(QComboBox *list,
void populateSceneItemSelection(QComboBox *list,
OBSWeakSource sceneWeakSource = nullptr);
void populateSceneItemSelection(QComboBox *list, SceneSelection &s);
void populateSourceTypeSelection(QComboBox *list);
void populateSourceGroupSelection(QComboBox *list);
bool windowPosValid(QPoint pos);

View File

@@ -4,13 +4,8 @@
#include <fstream>
#include <regex>
void startHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
bool pressed)
void startHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
{
UNUSED_PARAMETER(id);
UNUSED_PARAMETER(data);
UNUSED_PARAMETER(hotkey);
if (pressed) {
if (!(switcher->th && switcher->th->isRunning())) {
switcher->Start();
@@ -18,13 +13,8 @@ void startHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
}
}
void stopHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
bool pressed)
void stopHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *, bool pressed)
{
UNUSED_PARAMETER(id);
UNUSED_PARAMETER(data);
UNUSED_PARAMETER(hotkey);
if (pressed) {
if (switcher->th && switcher->th->isRunning()) {
switcher->Stop();
@@ -32,13 +22,9 @@ void stopHotkeyFunc(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
}
}
void startStopToggleHotkeyFunc(void *data, obs_hotkey_id id,
obs_hotkey_t *hotkey, bool pressed)
void startStopToggleHotkeyFunc(void *, obs_hotkey_id, obs_hotkey_t *,
bool pressed)
{
UNUSED_PARAMETER(id);
UNUSED_PARAMETER(data);
UNUSED_PARAMETER(hotkey);
if (pressed) {
if (switcher->th && switcher->th->isRunning()) {
switcher->Stop();

View File

@@ -117,7 +117,7 @@ bool MacroActionAudio::PerformAction()
obs_source_set_muted(s, false);
break;
case AudioAction::SOURCE_VOLUME:
if (_fade) {
if (_fade && _duration.seconds != 0) {
startSourceFade(_duration, (float)_volume / 100.0f,
_audioSource);
} else {
@@ -125,7 +125,7 @@ bool MacroActionAudio::PerformAction()
}
break;
case AudioAction::MASTER_VOLUME:
if (_fade) {
if (_fade && _duration.seconds != 0) {
startMasterFade(_duration, (float)_volume / 100.0f);
} else {
obs_set_master_volume((float)_volume / 100.0f);
@@ -259,6 +259,7 @@ void MacroActionAudioEdit::SetWidgetVisibility()
setLayoutVisible(_fadeLayout, hasVolumeControl(_entryData->_action));
adjustSize();
}
void MacroActionAudioEdit::UpdateEntryData()
{
if (!_entryData) {

View File

@@ -161,9 +161,8 @@ void MacroActionMacroEdit::ActionChanged(int value)
_entryData->_action = static_cast<PerformMacroAction>(value);
}
void MacroActionMacroEdit::MacroRemove(const QString &name)
void MacroActionMacroEdit::MacroRemove(const QString &)
{
UNUSED_PARAMETER(name);
if (_entryData) {
_entryData->_macro.UpdateRef();
}

View File

@@ -16,6 +16,8 @@ const static std::map<PluginStateAction, std::string> actionTypes = {
"AdvSceneSwitcher.action.pluginState.type.stop"},
{PluginStateAction::NO_MATCH_BEHAVIOUR,
"AdvSceneSwitcher.action.pluginState.type.noMatch"},
{PluginStateAction::IMPORT_SETTINGS,
"AdvSceneSwitcher.action.pluginState.type.import"},
};
const static std::map<NoMatch, std::string> noMatchValues = {
@@ -33,6 +35,19 @@ void stopPlugin()
t.detach();
}
void importSettings(const std::string &path)
{
if (switcher->settingsWindowOpened) {
return;
}
obs_data_t *obj = obs_data_create_from_json_file(path.c_str());
if (!obj) {
return;
}
switcher->loadSettings(obj);
obs_data_release(obj);
}
void setNoMatchBehaviour(int value, OBSWeakSource &scene)
{
switcher->switchIfNotMatching = static_cast<NoMatch>(value);
@@ -50,6 +65,11 @@ bool MacroActionPluginState::PerformAction()
case PluginStateAction::NO_MATCH_BEHAVIOUR:
setNoMatchBehaviour(_value, _scene);
break;
case PluginStateAction::IMPORT_SETTINGS:
importSettings(_settingsPath);
// There is no point in continuing
// The settings will be invalid
return false;
default:
break;
}
@@ -62,6 +82,13 @@ void MacroActionPluginState::LogAction()
case PluginStateAction::STOP:
blog(LOG_INFO, "stop() called by macro");
break;
case PluginStateAction::NO_MATCH_BEHAVIOUR:
vblog(LOG_INFO, "setting no match to %d", _value);
break;
case PluginStateAction::IMPORT_SETTINGS:
vblog(LOG_INFO, "importing settings from %s",
_settingsPath.c_str());
break;
default:
blog(LOG_WARNING, "ignored unknown pluginState action %d",
static_cast<int>(_action));
@@ -75,6 +102,7 @@ bool MacroActionPluginState::Save(obs_data_t *obj)
obs_data_set_int(obj, "action", static_cast<int>(_action));
obs_data_set_int(obj, "value", _value);
obs_data_set_string(obj, "scene", GetWeakSourceName(_scene).c_str());
obs_data_set_string(obj, "settingsPath", _settingsPath.c_str());
return true;
}
@@ -86,6 +114,7 @@ bool MacroActionPluginState::Load(obs_data_t *obj)
_value = obs_data_get_int(obj, "value");
const char *sceneName = obs_data_get_string(obj, "scene");
_scene = GetWeakSourceByName(sceneName);
_settingsPath = obs_data_get_string(obj, "settingsPath");
return true;
}
@@ -113,6 +142,9 @@ MacroActionPluginStateEdit::MacroActionPluginStateEdit(
_actions = new QComboBox();
_values = new QComboBox();
_scenes = new QComboBox();
_settings = new FileSelection();
_settingsWarning = new QLabel(obs_module_text(
"AdvSceneSwitcher.action.pluginState.importWarning"));
populateActionSelection(_actions);
populateSceneSelection(_scenes);
@@ -123,12 +155,16 @@ MacroActionPluginStateEdit::MacroActionPluginStateEdit(
SLOT(ValueChanged(int)));
QWidget::connect(_scenes, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(SceneChanged(const QString &)));
QWidget::connect(_settings, SIGNAL(PathChanged(const QString &)), this,
SLOT(PathChanged(const QString &)));
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{actions}}", _actions},
{"{{values}}", _values},
{"{{scenes}}", _scenes},
{"{{settings}}", _settings},
{"{{settingsWarning}}", _settingsWarning},
};
placeWidgets(
obs_module_text("AdvSceneSwitcher.action.pluginState.entry"),
@@ -149,7 +185,8 @@ void MacroActionPluginStateEdit::UpdateEntryData()
populateValueSelection(_values, _entryData->_action);
_values->setCurrentIndex(_entryData->_value);
_scenes->setCurrentText(GetWeakSourceName(_entryData->_scene).c_str());
SetWidgetVisibility(_entryData->_action, _entryData->_value);
_settings->SetPath(QString::fromStdString(_entryData->_settingsPath));
SetWidgetVisibility();
}
void MacroActionPluginStateEdit::ActionChanged(int value)
@@ -161,7 +198,7 @@ void MacroActionPluginStateEdit::ActionChanged(int value)
{
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_action = static_cast<PluginStateAction>(value);
SetWidgetVisibility(_entryData->_action, _entryData->_value);
SetWidgetVisibility();
}
_values->clear();
@@ -176,7 +213,7 @@ void MacroActionPluginStateEdit::ValueChanged(int value)
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_value = value;
SetWidgetVisibility(_entryData->_action, _entryData->_value);
SetWidgetVisibility();
}
void MacroActionPluginStateEdit::SceneChanged(const QString &text)
@@ -189,15 +226,40 @@ void MacroActionPluginStateEdit::SceneChanged(const QString &text)
_entryData->_scene = GetWeakSourceByQString(text);
}
void MacroActionPluginStateEdit::SetWidgetVisibility(PluginStateAction action,
int value)
void MacroActionPluginStateEdit::PathChanged(const QString &text)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_settingsPath = text.toStdString();
}
void MacroActionPluginStateEdit::SetWidgetVisibility()
{
if (!_entryData) {
return;
}
_values->hide();
_scenes->hide();
if (action == PluginStateAction::NO_MATCH_BEHAVIOUR) {
_settings->hide();
_settingsWarning->hide();
switch (_entryData->_action) {
case PluginStateAction::STOP:
break;
case PluginStateAction::NO_MATCH_BEHAVIOUR:
_values->show();
if ((NoMatch)value == SWITCH) {
if ((NoMatch)_entryData->_value == SWITCH) {
_scenes->show();
}
break;
case PluginStateAction::IMPORT_SETTINGS:
_settings->show();
_settingsWarning->show();
break;
default:
break;
}
}

View File

@@ -0,0 +1,99 @@
#include "headers/macro-action-profile.hpp"
#include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
const std::string MacroActionProfile::id = "profile";
bool MacroActionProfile::_registered = MacroActionFactory::Register(
MacroActionProfile::id,
{MacroActionProfile::Create, MacroActionProfileEdit::Create,
"AdvSceneSwitcher.action.profile"});
bool MacroActionProfile::PerformAction()
{
obs_frontend_set_current_profile(_profile.c_str());
return true;
}
void MacroActionProfile::LogAction()
{
vblog(LOG_INFO, "set profile type to \"%s\"", _profile.c_str());
}
bool MacroActionProfile::Save(obs_data_t *obj)
{
MacroAction::Save(obj);
obs_data_set_string(obj, "profile", _profile.c_str());
return true;
}
bool MacroActionProfile::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_profile = obs_data_get_string(obj, "profile");
return true;
}
std::string MacroActionProfile::GetShortDesc()
{
return _profile;
}
void populateProfileSelection(QComboBox *box)
{
auto profiles = obs_frontend_get_profiles();
char **temp = profiles;
while (*temp) {
const char *name = *temp;
box->addItem(name);
temp++;
}
bfree(profiles);
box->model()->sort(0);
addSelectionEntry(
box, obs_module_text("AdvSceneSwitcher.selectProfile"), false);
box->setCurrentIndex(0);
}
MacroActionProfileEdit::MacroActionProfileEdit(
QWidget *parent, std::shared_ptr<MacroActionProfile> entryData)
: QWidget(parent)
{
_profiles = new QComboBox();
populateProfileSelection(_profiles);
QWidget::connect(_profiles, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(ProfileChanged(const QString &)));
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{profiles}}", _profiles},
};
placeWidgets(obs_module_text("AdvSceneSwitcher.action.profile.entry"),
mainLayout, widgetPlaceholders);
setLayout(mainLayout);
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
void MacroActionProfileEdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
_profiles->setCurrentText(QString::fromStdString(_entryData->_profile));
}
void MacroActionProfileEdit::ProfileChanged(const QString &text)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_profile = text.toStdString();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}

View File

@@ -0,0 +1,117 @@
#include "headers/macro-action-scene-collection.hpp"
#include "headers/advanced-scene-switcher.hpp"
#include "headers/utility.hpp"
const std::string MacroActionSceneCollection::id = "scene_collection";
bool MacroActionSceneCollection::_registered = MacroActionFactory::Register(
MacroActionSceneCollection::id,
{MacroActionSceneCollection::Create,
MacroActionSceneCollectionEdit::Create,
"AdvSceneSwitcher.action.sceneCollection"});
bool MacroActionSceneCollection::PerformAction()
{
// Changing the scene collection will also reload the settings of the
// scene switcher, so to avoid issues of not being able to change
// settings ignore this action if the settings dialog is opened.
if (switcher->settingsWindowOpened) {
return false;
}
obs_frontend_set_current_scene_collection(_sceneCollection.c_str());
// It does not make sense to continue as the current settings will be
// invalid after switching scene collection.
return false;
}
void MacroActionSceneCollection::LogAction()
{
vblog(LOG_INFO, "set scene collection type to \"%s\"",
_sceneCollection.c_str());
}
bool MacroActionSceneCollection::Save(obs_data_t *obj)
{
MacroAction::Save(obj);
obs_data_set_string(obj, "sceneCollection", _sceneCollection.c_str());
return true;
}
bool MacroActionSceneCollection::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_sceneCollection = obs_data_get_string(obj, "sceneCollection");
return true;
}
std::string MacroActionSceneCollection::GetShortDesc()
{
return _sceneCollection;
}
void populateSceneCollectionSelection(QComboBox *box)
{
auto sceneCollections = obs_frontend_get_scene_collections();
char **temp = sceneCollections;
while (*temp) {
const char *name = *temp;
box->addItem(name);
temp++;
}
bfree(sceneCollections);
box->model()->sort(0);
addSelectionEntry(
box, obs_module_text("AdvSceneSwitcher.selectSceneCollection"),
false);
box->setCurrentIndex(0);
}
MacroActionSceneCollectionEdit::MacroActionSceneCollectionEdit(
QWidget *parent, std::shared_ptr<MacroActionSceneCollection> entryData)
: QWidget(parent)
{
_sceneCollections = new QComboBox();
populateSceneCollectionSelection(_sceneCollections);
QWidget::connect(_sceneCollections,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(SceneCollectionChanged(const QString &)));
QHBoxLayout *entryLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{sceneCollections}}", _sceneCollections},
};
placeWidgets(obs_module_text(
"AdvSceneSwitcher.action.sceneCollection.entry"),
entryLayout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(entryLayout);
mainLayout->addWidget(new QLabel(obs_module_text(
"AdvSceneSwitcher.action.sceneCollection.warning")));
setLayout(mainLayout);
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
void MacroActionSceneCollectionEdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
_sceneCollections->setCurrentText(
QString::fromStdString(_entryData->_sceneCollection));
}
void MacroActionSceneCollectionEdit::SceneCollectionChanged(const QString &text)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_sceneCollection = text.toStdString();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}

View File

@@ -22,37 +22,77 @@ const static std::map<SceneOrderAction, std::string> actionTypes = {
"AdvSceneSwitcher.action.sceneOrder.type.movePosition"},
};
bool MacroActionSceneOrder::PerformAction()
void moveSceneItemsUp(std::vector<obs_scene_item *> &items)
{
auto s = obs_weak_source_get_source(_scene.GetScene());
auto scene = obs_scene_from_source(s);
auto name = GetWeakSourceName(_source);
auto items = getSceneItemsWithName(scene, name);
// In the case of the same source being in two sequential positions
// moving the sources up will cause the sources to swap positions due to
// the order scene items are being iterated over, which is most likely
// not the desired effect.
// Instead we reverse the order of the scene items so all scene items
// will be moved up.
std::reverse(items.begin(), items.end());
for (auto &i : items) {
switch (_action) {
case SceneOrderAction::MOVE_UP:
obs_sceneitem_set_order(i, OBS_ORDER_MOVE_UP);
break;
case SceneOrderAction::MOVE_DOWN:
obs_sceneitem_set_order(i, OBS_ORDER_MOVE_DOWN);
break;
case SceneOrderAction::MOVE_TOP:
obs_sceneitem_set_order(i, OBS_ORDER_MOVE_TOP);
break;
case SceneOrderAction::MOVE_BOTTOM:
obs_sceneitem_set_order(i, OBS_ORDER_MOVE_BOTTOM);
break;
case SceneOrderAction::POSITION:
obs_sceneitem_set_order_position(i, _position);
break;
default:
break;
}
obs_sceneitem_set_order(i, OBS_ORDER_MOVE_UP);
obs_sceneitem_release(i);
}
}
obs_source_release(s);
void moveSceneItemsDown(std::vector<obs_scene_item *> &items)
{
for (auto &i : items) {
obs_sceneitem_set_order(i, OBS_ORDER_MOVE_DOWN);
obs_sceneitem_release(i);
}
}
void moveSceneItemsTop(std::vector<obs_scene_item *> &items)
{
for (auto &i : items) {
obs_sceneitem_set_order(i, OBS_ORDER_MOVE_TOP);
obs_sceneitem_release(i);
}
}
void moveSceneItemsBottom(std::vector<obs_scene_item *> &items)
{
for (auto &i : items) {
obs_sceneitem_set_order(i, OBS_ORDER_MOVE_BOTTOM);
obs_sceneitem_release(i);
}
}
void moveSceneItemsPos(std::vector<obs_scene_item *> &items, int pos)
{
for (auto &i : items) {
obs_sceneitem_set_order_position(i, pos);
obs_sceneitem_release(i);
}
}
bool MacroActionSceneOrder::PerformAction()
{
auto items = _source.GetSceneItems(_scene);
switch (_action) {
case SceneOrderAction::MOVE_UP:
moveSceneItemsUp(items);
break;
case SceneOrderAction::MOVE_DOWN:
moveSceneItemsDown(items);
break;
case SceneOrderAction::MOVE_TOP:
moveSceneItemsTop(items);
break;
case SceneOrderAction::MOVE_BOTTOM:
moveSceneItemsBottom(items);
break;
case SceneOrderAction::POSITION:
moveSceneItemsPos(items, _position);
break;
default:
break;
}
return true;
}
@@ -62,7 +102,7 @@ void MacroActionSceneOrder::LogAction()
if (it != actionTypes.end()) {
vblog(LOG_INFO,
"performed order action \"%s\" for source \"%s\" on scene \"%s\"",
it->second.c_str(), GetWeakSourceName(_source).c_str(),
it->second.c_str(), _source.ToString().c_str(),
_scene.ToString().c_str());
} else {
blog(LOG_WARNING, "ignored unknown scene order action %d",
@@ -74,7 +114,7 @@ bool MacroActionSceneOrder::Save(obs_data_t *obj)
{
MacroAction::Save(obj);
_scene.Save(obj);
obs_data_set_string(obj, "source", GetWeakSourceName(_source).c_str());
_source.Save(obj);
obs_data_set_int(obj, "action", static_cast<int>(_action));
obs_data_set_int(obj, "position", _position);
return true;
@@ -82,10 +122,16 @@ bool MacroActionSceneOrder::Save(obs_data_t *obj)
bool MacroActionSceneOrder::Load(obs_data_t *obj)
{
// Convert old data format
// TODO: Remove in future version
if (obs_data_has_user_value(obj, "source")) {
auto sourceName = obs_data_get_string(obj, "source");
obs_data_set_string(obj, "sceneItem", sourceName);
}
MacroAction::Load(obj);
_scene.Load(obj);
const char *sourceName = obs_data_get_string(obj, "source");
_source = GetWeakSourceByName(sourceName);
_source.Load(obj);
_action =
static_cast<SceneOrderAction>(obs_data_get_int(obj, "action"));
_position = obs_data_get_int(obj, "position");
@@ -94,10 +140,10 @@ bool MacroActionSceneOrder::Load(obs_data_t *obj)
std::string MacroActionSceneOrder::GetShortDesc()
{
if (_source) {
return _scene.ToString() + " - " + GetWeakSourceName(_source);
if (_source.ToString().empty()) {
return "";
}
return "";
return _scene.ToString() + " - " + _source.ToString();
}
static inline void populateActionSelection(QComboBox *list)
@@ -112,7 +158,7 @@ MacroActionSceneOrderEdit::MacroActionSceneOrderEdit(
: QWidget(parent)
{
_scenes = new SceneSelectionWidget(window(), false, false, true);
_sources = new QComboBox();
_sources = new SceneItemSelectionWidget(parent);
_actions = new QComboBox();
_position = new QSpinBox();
@@ -122,8 +168,11 @@ MacroActionSceneOrderEdit::MacroActionSceneOrderEdit(
SLOT(ActionChanged(int)));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sources, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(SourceChanged(const QString &)));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
_sources, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sources,
SIGNAL(SceneItemChanged(const SceneItemSelection &)),
this, SLOT(SourceChanged(const SceneItemSelection &)));
QWidget::connect(_position, SIGNAL(valueChanged(int)), this,
SLOT(PositionChanged(int)));
@@ -152,9 +201,7 @@ void MacroActionSceneOrderEdit::UpdateEntryData()
_actions->setCurrentIndex(static_cast<int>(_entryData->_action));
_scenes->SetScene(_entryData->_scene);
populateSceneItemSelection(_sources, _entryData->_scene);
_sources->setCurrentText(
GetWeakSourceName(_entryData->_source).c_str());
_sources->SetSceneItem(_entryData->_source);
_position->setValue(_entryData->_position);
_position->setVisible(_entryData->_action ==
SceneOrderAction::POSITION);
@@ -165,22 +212,19 @@ void MacroActionSceneOrderEdit::SceneChanged(const SceneSelection &s)
if (_loading || !_entryData) {
return;
}
{
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
}
_sources->clear();
populateSceneItemSelection(_sources, _entryData->_scene);
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
}
void MacroActionSceneOrderEdit::SourceChanged(const QString &text)
void MacroActionSceneOrderEdit::SourceChanged(const SceneItemSelection &item)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_source = GetWeakSourceByQString(text);
_entryData->_source = item;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}

View File

@@ -9,75 +9,165 @@ bool MacroActionSwitchScene::_registered = MacroActionFactory::Register(
{MacroActionSwitchScene::Create, MacroActionSwitchSceneEdit::Create,
"AdvSceneSwitcher.action.switchScene"});
void waitForTransitionChange(OBSWeakSource &target)
{
const int maxNrChecks = 100;
int curCheckNr = 0;
bool transitionEnded = false;
auto sceneCheckStartedOn = obs_frontend_get_current_scene();
obs_source_release(sceneCheckStartedOn);
switcher->abortMacroWait = false;
std::unique_lock<std::mutex> lock(switcher->m);
while (!transitionEnded && curCheckNr < maxNrChecks &&
!switcher->abortMacroWait) {
switcher->abortMacroWait = false;
switcher->macroTransitionCv.wait_for(
lock,
std::chrono::milliseconds(
(long long)switcher->interval),
[] { return switcher->abortMacroWait.load(); });
auto curScene = obs_frontend_get_current_scene();
obs_source_release(curScene);
transitionEnded = curScene != sceneCheckStartedOn ||
switcher->currentScene == target;
++curCheckNr;
}
}
bool MacroActionSwitchScene::PerformAction()
{
OBSWeakSource scene = getScene();
switchScene({scene, transition, (int)(_duration.seconds * 1000)});
auto scene = _scene.GetScene();
switchScene({scene, _transition.GetTransition(),
(int)(_duration.seconds * 1000)});
if (_blockUntilTransitionDone) {
waitForTransitionChange(scene);
return !switcher->abortMacroWait;
}
return true;
}
void MacroActionSwitchScene::LogAction()
{
if (switcher->verbose) {
logMatch();
auto t = _scene.GetType();
auto sceneName = GetWeakSourceName(_scene.GetScene(false));
switch (t) {
case SceneSelectionType::SCENE:
vblog(LOG_INFO, "switch to scene '%s'",
_scene.ToString().c_str());
break;
case SceneSelectionType::GROUP:
vblog(LOG_INFO, "switch to scene '%s' (scene group '%s')",
sceneName.c_str(), _scene.ToString().c_str());
break;
case SceneSelectionType::PREVIOUS:
vblog(LOG_INFO, "switch to previous scene '%s'",
sceneName.c_str());
break;
default:
break;
}
}
bool MacroActionSwitchScene::Save(obs_data_t *obj)
{
MacroAction::Save(obj);
SceneSwitcherEntry::save(obj);
_scene.Save(obj);
_transition.Save(obj);
_duration.Save(obj);
obs_data_set_bool(obj, "blockUntilTransitionDone",
_blockUntilTransitionDone);
return true;
}
bool MacroActionSwitchScene::Load(obs_data_t *obj)
{
// Convert old data format
// TODO: Remove in future version
if (obs_data_has_user_value(obj, "targetType")) {
auto sceneName = obs_data_get_string(obj, "target");
obs_data_set_string(obj, "scene", sceneName);
auto transitionName = obs_data_get_string(obj, "transition");
bool usePreviousScene =
strcmp(sceneName, previous_scene_name) == 0;
bool useCurrentTransition =
strcmp(transitionName, current_transition_name) == 0;
obs_data_set_int(
obj, "sceneType",
(usePreviousScene)
? static_cast<int>(SceneSelectionType::PREVIOUS)
: obs_data_get_int(obj, "targetType"));
obs_data_set_int(
obj, "transitionType",
(useCurrentTransition)
? static_cast<int>(
TransitionSelectionType::CURRENT)
: static_cast<int>(
TransitionSelectionType::TRANSITION));
}
MacroAction::Load(obj);
SceneSwitcherEntry::load(obj);
_scene.Load(obj);
_transition.Load(obj);
_duration.Load(obj);
_blockUntilTransitionDone =
obs_data_get_bool(obj, "blockUntilTransitionDone");
return true;
}
std::string MacroActionSwitchScene::GetShortDesc()
{
if (targetType == SwitchTargetType::Scene && scene) {
return GetWeakSourceName(scene);
}
if (targetType == SwitchTargetType::SceneGroup && group) {
return group->name;
}
return "";
return _scene.ToString();
}
MacroActionSwitchSceneEdit::MacroActionSwitchSceneEdit(
QWidget *parent, std::shared_ptr<MacroActionSwitchScene> entryData)
: SwitchWidget(parent, entryData.get(), true, true)
: QWidget(parent)
{
_scenes = new SceneSelectionWidget(window(), true, true);
_transitions = new TransitionSelectionWidget(this);
_duration = new DurationSelection(parent, false);
_blockUntilTransitionDone = new QCheckBox(obs_module_text(
"AdvSceneSwitcher.action.scene.blockUntilTransitionDone"));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_transitions,
SIGNAL(TransitionChanged(const TransitionSelection &)),
this,
SLOT(TransitionChanged(const TransitionSelection &)));
QWidget::connect(_duration, SIGNAL(DurationChanged(double)), this,
SLOT(DurationChanged(double)));
QWidget::connect(scenes, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(ChangeHeaderInfo(const QString &)));
QWidget::connect(_blockUntilTransitionDone, SIGNAL(stateChanged(int)),
this, SLOT(BlockUntilTransitionDoneChanged(int)));
QHBoxLayout *mainLayout = new QHBoxLayout;
QHBoxLayout *entryLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{scenes}}", scenes},
{"{{transitions}}", transitions},
{"{{scenes}}", _scenes},
{"{{transitions}}", _transitions},
{"{{duration}}", _duration},
{"{{blockUntilTransitionDone}}", _blockUntilTransitionDone},
};
placeWidgets(obs_module_text("AdvSceneSwitcher.action.scene.entry"),
mainLayout, widgetPlaceholders);
entryLayout, widgetPlaceholders);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addLayout(entryLayout);
mainLayout->addWidget(_blockUntilTransitionDone);
setLayout(mainLayout);
_entryData = entryData;
_scenes->SetScene(_entryData->_scene);
_transitions->SetTransition(_entryData->_transition);
_duration->SetDuration(_entryData->_duration);
SwitchWidget::loading = false;
_blockUntilTransitionDone->setChecked(
_entryData->_blockUntilTransitionDone);
_loading = false;
}
void MacroActionSwitchSceneEdit::DurationChanged(double seconds)
{
if (SwitchWidget::loading || !_entryData) {
if (_loading || !_entryData) {
return;
}
@@ -85,8 +175,34 @@ void MacroActionSwitchSceneEdit::DurationChanged(double seconds)
_entryData->_duration.seconds = seconds;
}
void MacroActionSwitchSceneEdit::ChangeHeaderInfo(const QString &)
void MacroActionSwitchSceneEdit::BlockUntilTransitionDoneChanged(int state)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_blockUntilTransitionDone = state;
}
void MacroActionSwitchSceneEdit::SceneChanged(const SceneSelection &s)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroActionSwitchSceneEdit::TransitionChanged(const TransitionSelection &t)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_transition = t;
}

View File

@@ -12,13 +12,8 @@ bool MacroActionSceneTransform::_registered = MacroActionFactory::Register(
bool MacroActionSceneTransform::PerformAction()
{
auto s = obs_weak_source_get_source(_scene.GetScene(false));
auto scene = obs_scene_from_source(s);
auto name = GetWeakSourceName(_source);
auto items = getSceneItemsWithName(scene, name);
auto items = _source.GetSceneItems(_scene);
for (auto &item : items) {
// Apply settings
obs_sceneitem_defer_update_begin(item);
obs_sceneitem_set_info(item, &_info);
obs_sceneitem_set_crop(item, &_crop);
@@ -26,8 +21,6 @@ bool MacroActionSceneTransform::PerformAction()
obs_sceneitem_release(item);
}
obs_source_release(s);
return true;
}
@@ -35,34 +28,40 @@ void MacroActionSceneTransform::LogAction()
{
vblog(LOG_INFO,
"performed transform action for source \"%s\" on scene \"%s\"",
GetWeakSourceName(_source).c_str(), _scene.ToString().c_str());
_source.ToString().c_str(), _scene.ToString().c_str());
}
bool MacroActionSceneTransform::Save(obs_data_t *obj)
{
MacroAction::Save(obj);
_scene.Save(obj);
obs_data_set_string(obj, "source", GetWeakSourceName(_source).c_str());
_source.Save(obj);
saveTransformState(obj, _info, _crop);
return true;
}
bool MacroActionSceneTransform::Load(obs_data_t *obj)
{
// Convert old data format
// TODO: Remove in future version
if (obs_data_has_user_value(obj, "source")) {
auto sourceName = obs_data_get_string(obj, "source");
obs_data_set_string(obj, "sceneItem", sourceName);
}
MacroAction::Load(obj);
_scene.Load(obj);
const char *sourceName = obs_data_get_string(obj, "source");
_source = GetWeakSourceByName(sourceName);
_source.Load(obj);
loadTransformState(obj, _info, _crop);
return true;
}
std::string MacroActionSceneTransform::GetShortDesc()
{
if (_source) {
return _scene.ToString() + " - " + GetWeakSourceName(_source);
if (_source.ToString().empty()) {
return "";
}
return "";
return _scene.ToString() + " - " + _source.ToString();
}
std::string MacroActionSceneTransform::GetSettings()
@@ -81,9 +80,13 @@ void MacroActionSceneTransform::SetSettings(std::string &settings)
return;
}
loadTransformState(data, _info, _crop);
auto items = _source.GetSceneItems(_scene);
if (items.empty()) {
return;
}
if (obs_data_has_user_value(data, "size")) {
auto obj = obs_data_get_obj(data, "size");
auto source = obs_weak_source_get_source(_source);
auto source = obs_sceneitem_get_source(items[0]);
if (double h = obs_data_get_double(obj, "height")) {
_info.scale.y =
h / double(obs_source_get_height(source));
@@ -93,9 +96,10 @@ void MacroActionSceneTransform::SetSettings(std::string &settings)
w / double(obs_source_get_width(source));
}
obs_data_release(obj);
obs_source_release(source);
}
for (auto item : items) {
obs_sceneitem_release(item);
}
obs_data_release(data);
}
@@ -104,15 +108,18 @@ MacroActionSceneTransformEdit::MacroActionSceneTransformEdit(
: QWidget(parent)
{
_scenes = new SceneSelectionWidget(window(), false, false, true);
_sources = new QComboBox();
_sources = new SceneItemSelectionWidget(parent);
_getSettings = new QPushButton(obs_module_text(
"AdvSceneSwitcher.action.sceneTransform.getTransform"));
_settings = new QPlainTextEdit();
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sources, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(SourceChanged(const QString &)));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
_sources, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sources,
SIGNAL(SceneItemChanged(const SceneItemSelection &)),
this, SLOT(SourceChanged(const SceneItemSelection &)));
QWidget::connect(_getSettings, SIGNAL(clicked()), this,
SLOT(GetSettingsClicked()));
QWidget::connect(_settings, SIGNAL(textChanged()), this,
@@ -152,13 +159,8 @@ void MacroActionSceneTransformEdit::UpdateEntryData()
}
_scenes->SetScene(_entryData->_scene);
populateSceneItemSelection(_sources, _entryData->_scene);
_sources->setCurrentText(
GetWeakSourceName(_entryData->_source).c_str());
if (_entryData->_source) {
_settings->setPlainText(
formatJsonString(_entryData->GetSettings()));
}
_sources->SetSceneItem(_entryData->_source);
_settings->setPlainText(formatJsonString(_entryData->GetSettings()));
}
void MacroActionSceneTransformEdit::SceneChanged(const SceneSelection &s)
@@ -166,44 +168,39 @@ void MacroActionSceneTransformEdit::SceneChanged(const SceneSelection &s)
if (_loading || !_entryData) {
return;
}
{
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
}
_sources->clear();
populateSceneItemSelection(_sources, _entryData->_scene);
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
}
void MacroActionSceneTransformEdit::SourceChanged(const QString &text)
void MacroActionSceneTransformEdit::SourceChanged(const SceneItemSelection &item)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_source = GetWeakSourceByQString(text);
_entryData->_source = item;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroActionSceneTransformEdit::GetSettingsClicked()
{
if (_loading || !_entryData || !_entryData->_scene.GetScene(false) ||
!_entryData->_source) {
if (_loading || !_entryData || !_entryData->_scene.GetScene(false)) {
return;
}
auto s = obs_weak_source_get_source(_entryData->_scene.GetScene(false));
auto scene = obs_scene_from_source(s);
auto name = GetWeakSourceName(_entryData->_source);
auto item = obs_scene_find_source_recursive(scene, name.c_str());
obs_source_release(s);
if (!item) {
auto items = _entryData->_source.GetSceneItems(_entryData->_scene);
if (items.empty()) {
return;
}
_settings->setPlainText(formatJsonString(getSceneItemTransform(item)));
auto settings = getSceneItemTransform(items[0]);
_settings->setPlainText(formatJsonString(settings));
for (auto item : items) {
obs_sceneitem_release(item);
}
}
void MacroActionSceneTransformEdit::SettingsChanged()

View File

@@ -29,23 +29,6 @@ struct VisibilityData {
bool visible;
};
static bool visibilitySourceEnum(obs_scene_t *, obs_sceneitem_t *item,
void *ptr)
{
VisibilityData *vInfo = reinterpret_cast<VisibilityData *>(ptr);
auto sourceName = obs_source_get_name(obs_sceneitem_get_source(item));
if (vInfo->name == sourceName) {
obs_sceneitem_set_visible(item, vInfo->visible);
}
if (obs_sceneitem_is_group(item)) {
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
obs_scene_enum_items(scene, visibilitySourceEnum, ptr);
}
return true;
}
static bool visibilitySourceTypeEnum(obs_scene_t *, obs_sceneitem_t *item,
void *ptr)
{
@@ -67,25 +50,29 @@ static bool visibilitySourceTypeEnum(obs_scene_t *, obs_sceneitem_t *item,
bool MacroActionSceneVisibility::PerformAction()
{
auto s = obs_weak_source_get_source(_scene.GetScene());
auto scene = obs_scene_from_source(s);
auto sourceName = GetWeakSourceName(_source);
VisibilityData vInfo = {"", _action == SceneVisibilityAction::SHOW};
switch (_sourceType) {
case SceneItemSourceType::SOURCE:
vInfo.name = sourceName;
obs_scene_enum_items(scene, visibilitySourceEnum, &vInfo);
case SceneItemSourceType::SOURCE: {
auto items = _source.GetSceneItems(_scene);
for (auto item : items) {
obs_sceneitem_set_visible(
item, _action == SceneVisibilityAction::SHOW);
obs_sceneitem_release(item);
}
break;
case SceneItemSourceType::SOURCE_GROUP:
vInfo.name = _sourceGroup;
}
case SceneItemSourceType::SOURCE_GROUP: {
auto s = obs_weak_source_get_source(_scene.GetScene());
auto scene = obs_scene_from_source(s);
VisibilityData vInfo = {_sourceGroup,
_action == SceneVisibilityAction::SHOW};
obs_scene_enum_items(scene, visibilitySourceTypeEnum, &vInfo);
obs_source_release(s);
break;
}
default:
break;
}
obs_source_release(s);
return true;
}
@@ -96,8 +83,7 @@ void MacroActionSceneVisibility::LogAction()
if (_sourceType == SceneItemSourceType::SOURCE) {
vblog(LOG_INFO,
"performed visibility action \"%s\" for source \"%s\" on scene \"%s\"",
it->second.c_str(),
GetWeakSourceName(_source).c_str(),
it->second.c_str(), _source.ToString().c_str(),
_scene.ToString().c_str());
} else {
vblog(LOG_INFO,
@@ -116,10 +102,9 @@ bool MacroActionSceneVisibility::Save(obs_data_t *obj)
MacroAction::Save(obj);
_scene.Save(obj);
if (_sourceType == SceneItemSourceType::SOURCE) {
obs_data_set_string(obj, "source",
GetWeakSourceName(_source).c_str());
_source.Save(obj);
} else {
obs_data_set_string(obj, "source", _sourceGroup.c_str());
obs_data_set_string(obj, "sourceGroup", _sourceGroup.c_str());
}
obs_data_set_int(obj, "action", static_cast<int>(_action));
obs_data_set_int(obj, "sourceType", static_cast<int>(_sourceType));
@@ -128,13 +113,20 @@ bool MacroActionSceneVisibility::Save(obs_data_t *obj)
bool MacroActionSceneVisibility::Load(obs_data_t *obj)
{
// Convert old data format
// TODO: Remove in future version
if (obs_data_has_user_value(obj, "source")) {
auto sourceName = obs_data_get_string(obj, "source");
obs_data_set_string(obj, "sceneItem", sourceName);
obs_data_set_string(obj, "sourceGroup", sourceName);
}
MacroAction::Load(obj);
_scene.Load(obj);
_source.Load(obj);
_sourceType = static_cast<SceneItemSourceType>(
obs_data_get_int(obj, "sourceType"));
const char *sourceName = obs_data_get_string(obj, "source");
_source = GetWeakSourceByName(sourceName);
_sourceGroup = sourceName;
_sourceGroup = obs_data_get_string(obj, "sourceGroup");
_action = static_cast<SceneVisibilityAction>(
obs_data_get_int(obj, "action"));
return true;
@@ -142,8 +134,9 @@ bool MacroActionSceneVisibility::Load(obs_data_t *obj)
std::string MacroActionSceneVisibility::GetShortDesc()
{
if (_sourceType == SceneItemSourceType::SOURCE && _source) {
return _scene.ToString() + " - " + GetWeakSourceName(_source);
if (_sourceType == SceneItemSourceType::SOURCE &&
!_source.ToString().empty()) {
return _scene.ToString() + " - " + _source.ToString();
}
if (_sourceType == SceneItemSourceType::SOURCE_GROUP &&
!_sourceGroup.empty()) {
@@ -175,11 +168,12 @@ MacroActionSceneVisibilityEdit::MacroActionSceneVisibilityEdit(
{
_scenes = new SceneSelectionWidget(window(), false, true, true);
_sourceTypes = new QComboBox();
_sources = new QComboBox();
_sources->setSizeAdjustPolicy(QComboBox::AdjustToContents);
_sources = new SceneItemSelectionWidget(parent);
_sourceGroups = new QComboBox();
_actions = new QComboBox();
populateSourceItemTypeSelection(_sourceTypes);
populateSourceGroupSelection(_sourceGroups);
populateActionSelection(_actions);
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
@@ -188,14 +182,19 @@ MacroActionSceneVisibilityEdit::MacroActionSceneVisibilityEdit(
this, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sourceTypes, SIGNAL(currentIndexChanged(int)), this,
SLOT(SourceTypeChanged(int)));
QWidget::connect(_sources, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(SourceChanged(const QString &)));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
_sources, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sources,
SIGNAL(SceneItemChanged(const SceneItemSelection &)),
this, SLOT(SourceChanged(const SceneItemSelection &)));
QWidget::connect(_sourceGroups,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(SourceGroupChanged(const QString &)));
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{scenes}}", _scenes},
{"{{sourceTypes}}", _sourceTypes},
{"{{sources}}", _sources},
{"{{scenes}}", _scenes}, {"{{sourceTypes}}", _sourceTypes},
{"{{sources}}", _sources}, {"{{sourceGroups}}", _sourceGroups},
{"{{actions}}", _actions},
};
placeWidgets(obs_module_text(
@@ -218,14 +217,10 @@ void MacroActionSceneVisibilityEdit::UpdateEntryData()
_sourceTypes->setCurrentIndex(
static_cast<int>(_entryData->_sourceType));
_scenes->SetScene(_entryData->_scene);
if (_entryData->_sourceType == SceneItemSourceType::SOURCE) {
populateSceneItemSelection(_sources, _entryData->_scene);
_sources->setCurrentText(
GetWeakSourceName(_entryData->_source).c_str());
} else {
populateSourceTypeSelection(_sources);
_sources->setCurrentText(_entryData->_sourceGroup.c_str());
}
_sources->SetSceneItem((_entryData->_source));
_sourceGroups->setCurrentText(
QString::fromStdString(_entryData->_sourceGroup));
SetWidgetVisibility();
}
void MacroActionSceneVisibilityEdit::SceneChanged(const SceneSelection &s)
@@ -233,13 +228,9 @@ void MacroActionSceneVisibilityEdit::SceneChanged(const SceneSelection &s)
if (_loading || !_entryData) {
return;
}
{
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
}
_sources->clear();
populateSceneItemSelection(_sources, _entryData->_scene);
_sources->adjustSize();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
}
void MacroActionSceneVisibilityEdit::SourceTypeChanged(int value)
@@ -247,35 +238,36 @@ void MacroActionSceneVisibilityEdit::SourceTypeChanged(int value)
if (_loading || !_entryData) {
return;
}
{
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_sourceType =
static_cast<SceneItemSourceType>(value);
}
_sources->clear();
if (_entryData->_sourceType == SceneItemSourceType::SOURCE) {
populateSceneItemSelection(_sources, _entryData->_scene);
} else {
populateSourceTypeSelection(_sources);
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_sourceType = static_cast<SceneItemSourceType>(value);
SetWidgetVisibility();
}
void MacroActionSceneVisibilityEdit::SourceChanged(const QString &text)
void MacroActionSceneVisibilityEdit::SourceChanged(
const SceneItemSelection &item)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
if (_entryData->_sourceType == SceneItemSourceType::SOURCE) {
_entryData->_source = GetWeakSourceByQString(text);
_entryData->_source = item;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroActionSceneVisibilityEdit::SourceGroupChanged(const QString &text)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
if (text == obs_module_text("AdvSceneSwitcher.selectItem")) {
_entryData->_sourceGroup = "";
} else {
if (text == obs_module_text("AdvSceneSwitcher.selectItem")) {
_entryData->_sourceGroup = "";
} else {
_entryData->_sourceGroup = text.toStdString();
}
_entryData->_sourceGroup = text.toStdString();
}
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
@@ -290,3 +282,15 @@ void MacroActionSceneVisibilityEdit::ActionChanged(int value)
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_action = static_cast<SceneVisibilityAction>(value);
}
void MacroActionSceneVisibilityEdit::SetWidgetVisibility()
{
if (!_entryData) {
return;
}
_sources->setVisible(_entryData->_sourceType ==
SceneItemSourceType::SOURCE);
_sourceGroups->setVisible(_entryData->_sourceType ==
SceneItemSourceType::SOURCE_GROUP);
adjustSize();
}

View File

@@ -13,6 +13,9 @@ bool MacroConditionAudio::_registered = MacroConditionFactory::Register(
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,
"AdvSceneSwitcher.condition.audio.state.unmute"},
};
MacroConditionAudio::~MacroConditionAudio()
@@ -23,19 +26,32 @@ MacroConditionAudio::~MacroConditionAudio()
bool MacroConditionAudio::CheckCondition()
{
// peak will have a value from -60 db to 0 db
bool volumeThresholdreached = false;
if (_condition == AudioCondition::ABOVE) {
volumeThresholdreached = ((double)_peak + 60) * 1.7 > _volume;
} else {
volumeThresholdreached = ((double)_peak + 60) * 1.7 < _volume;
bool ret = false;
auto s = obs_weak_source_get_source(_audioSource);
switch (_condition) {
case AudioCondition::ABOVE:
// peak will have a value from -60 db to 0 db
ret = ((double)_peak + 60) * 1.7 > _volume;
break;
case AudioCondition::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();
return volumeThresholdreached;
obs_source_release(s);
return ret;
}
bool MacroConditionAudio::Save(obs_data_t *obj)
@@ -85,13 +101,10 @@ std::string MacroConditionAudio::GetShortDesc()
return "";
}
void MacroConditionAudio::SetVolumeLevel(
void *data, const float magnitude[MAX_AUDIO_CHANNELS],
const float peak[MAX_AUDIO_CHANNELS],
const float inputPeak[MAX_AUDIO_CHANNELS])
void MacroConditionAudio::SetVolumeLevel(void *data, const float *,
const float peak[MAX_AUDIO_CHANNELS],
const float *)
{
UNUSED_PARAMETER(magnitude);
UNUSED_PARAMETER(inputPeak);
MacroConditionAudio *c = static_cast<MacroConditionAudio *>(data);
for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) {
@@ -189,6 +202,7 @@ void MacroConditionAudioEdit::SourceChanged(const QString &text)
_entryData->_audioSource = GetWeakSourceByQString(text);
_entryData->ResetVolmeter();
UpdateVolmeterSource();
SetWidgetVisibility();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
@@ -211,6 +225,7 @@ void MacroConditionAudioEdit::ConditionChanged(int cond)
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_condition = static_cast<AudioCondition>(cond);
SetWidgetVisibility();
}
void MacroConditionAudioEdit::UpdateEntryData()
@@ -224,4 +239,18 @@ void MacroConditionAudioEdit::UpdateEntryData()
_volume->setValue(_entryData->_volume);
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
UpdateVolmeterSource();
SetWidgetVisibility();
}
void MacroConditionAudioEdit::SetWidgetVisibility()
{
if (!_entryData) {
return;
}
_volume->setVisible(_entryData->_condition == AudioCondition::ABOVE ||
_entryData->_condition == AudioCondition::BELOW);
_volMeter->setVisible(_entryData->_condition == AudioCondition::ABOVE ||
_entryData->_condition == AudioCondition::BELOW);
adjustSize();
}

View File

@@ -10,12 +10,8 @@ bool MacroConditionHotkey::_registered = MacroConditionFactory::Register(
{MacroConditionHotkey::Create, MacroConditionHotkeyEdit::Create,
"AdvSceneSwitcher.condition.hotkey", false});
static void hotkeyCB(void *data, obs_hotkey_id id, obs_hotkey_t *hotkey,
bool pressed)
static void hotkeyCB(void *data, obs_hotkey_id, obs_hotkey_t *, bool pressed)
{
UNUSED_PARAMETER(id);
UNUSED_PARAMETER(data);
UNUSED_PARAMETER(hotkey);
if (pressed) {
auto c = static_cast<MacroConditionHotkey *>(data);
c->SetPressed();

View File

@@ -282,9 +282,8 @@ void MacroConditionMacroEdit::ConditionChanged(int cond)
_entryData->_counterCondition = static_cast<CounterCondition>(cond);
}
void MacroConditionMacroEdit::MacroRemove(const QString &name)
void MacroConditionMacroEdit::MacroRemove(const QString &)
{
UNUSED_PARAMETER(name);
if (_entryData) {
_entryData->_macro.UpdateRef();
}

View File

@@ -19,78 +19,110 @@ static std::map<SceneOrderCondition, std::string> sceneOrderConditionTypes = {
"AdvSceneSwitcher.condition.sceneOrder.type.position"},
};
struct PosInfo {
std::string name;
std::vector<int> pos = {};
struct PosInfo2 {
obs_scene_item *item;
int pos = -1;
int curPos = 0;
};
static bool getSceneItemPositions(obs_scene_t *, obs_sceneitem_t *item,
void *ptr)
static bool getSceneItemPositionHelper(obs_scene_t *, obs_sceneitem_t *item,
void *ptr)
{
PosInfo *posInfo = reinterpret_cast<PosInfo *>(ptr);
auto sourceName = obs_source_get_name(obs_sceneitem_get_source(item));
if (posInfo->name == sourceName) {
posInfo->pos.push_back(posInfo->curPos);
PosInfo2 *posInfo = reinterpret_cast<PosInfo2 *>(ptr);
if (posInfo->item == item) {
posInfo->pos = posInfo->curPos;
return false;
}
if (obs_sceneitem_is_group(item)) {
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
obs_scene_enum_items(scene, getSceneItemPositions, ptr);
obs_scene_enum_items(scene, getSceneItemPositionHelper, ptr);
}
posInfo->curPos += 1;
return true;
}
static bool isAbove(std::vector<int> &v1, std::vector<int> &v2)
PosInfo2 getSceneItemPos(obs_scene_item *item, obs_scene *scene)
{
for (int i : v1) {
for (int j : v2) {
if (i > j) {
return true;
}
}
}
return false;
PosInfo2 pos{item};
obs_scene_enum_items(scene, getSceneItemPositionHelper, &pos);
return pos;
}
static bool isBelow(std::vector<int> &v1, std::vector<int> &v2)
std::vector<int> getSceneItemPositions(std::vector<obs_scene_item *> &items,
obs_scene *scene)
{
for (int i : v1) {
for (int j : v2) {
if (i < j) {
return true;
std::vector<int> positions;
for (auto item : items) {
auto pos = getSceneItemPos(item, scene);
if (pos.pos != -1) {
positions.emplace_back(pos.pos);
}
}
return positions;
}
static bool isAbove(std::vector<int> &pos1, std::vector<int> &pos2)
{
if (pos1.empty() || pos2.empty()) {
return false;
}
for (int i : pos1) {
for (int j : pos2) {
if (i <= j) {
return false;
}
}
}
return false;
return true;
}
static bool isBelow(std::vector<int> &pos1, std::vector<int> &pos2)
{
if (pos1.empty() || pos2.empty()) {
return false;
}
for (int i : pos1) {
for (int j : pos2) {
if (i >= j) {
return false;
}
}
}
return true;
}
bool MacroConditionSceneOrder::CheckCondition()
{
if (!_source) {
auto items1 = _source.GetSceneItems(_scene);
if (items1.empty()) {
return false;
}
bool ret = false;
auto items2 = _source2.GetSceneItems(_scene);
auto s = obs_weak_source_get_source(_scene.GetScene(false));
auto scene = obs_scene_from_source(s);
auto name1 = GetWeakSourceName(_source);
auto name2 = GetWeakSourceName(_source2);
PosInfo pos1 = {name1};
PosInfo pos2 = {name2};
obs_scene_enum_items(scene, getSceneItemPositions, &pos1);
obs_scene_enum_items(scene, getSceneItemPositions, &pos2);
auto positions1 = getSceneItemPositions(items1, scene);
auto positions2 = getSceneItemPositions(items2, scene);
for (auto i : items1) {
obs_sceneitem_release(i);
}
for (auto i : items2) {
obs_sceneitem_release(i);
}
bool ret = false;
switch (_condition) {
case SceneOrderCondition::ABOVE:
ret = isAbove(pos1.pos, pos2.pos);
ret = isAbove(positions1, positions2);
break;
case SceneOrderCondition::BELOW:
ret = isBelow(pos1.pos, pos2.pos);
ret = isBelow(positions1, positions2);
break;
case SceneOrderCondition::POSITION:
for (int p : pos1.pos) {
for (int p : positions1) {
if (p == _position)
ret = true;
}
@@ -100,7 +132,6 @@ bool MacroConditionSceneOrder::CheckCondition()
}
obs_source_release(s);
return ret;
}
@@ -108,9 +139,8 @@ bool MacroConditionSceneOrder::Save(obs_data_t *obj)
{
MacroCondition::Save(obj);
_scene.Save(obj);
obs_data_set_string(obj, "source", GetWeakSourceName(_source).c_str());
obs_data_set_string(obj, "source2",
GetWeakSourceName(_source2).c_str());
_source.Save(obj);
_source2.Save(obj, "sceneItem2", "sceneItemTarget2", "sceneItemIdx2");
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
obs_data_set_int(obj, "position", _position);
return true;
@@ -118,12 +148,19 @@ bool MacroConditionSceneOrder::Save(obs_data_t *obj)
bool MacroConditionSceneOrder::Load(obs_data_t *obj)
{
// Convert old data format
// TODO: Remove in future version
if (obs_data_has_user_value(obj, "source")) {
auto sourceName = obs_data_get_string(obj, "source");
obs_data_set_string(obj, "sceneItem", sourceName);
auto sourceName2 = obs_data_get_string(obj, "source2");
obs_data_set_string(obj, "sceneItem2", sourceName2);
}
MacroCondition::Load(obj);
_scene.Load(obj);
const char *sourceName = obs_data_get_string(obj, "source");
_source = GetWeakSourceByName(sourceName);
const char *source2Name = obs_data_get_string(obj, "source2");
_source2 = GetWeakSourceByName(source2Name);
_source.Load(obj);
_source2.Load(obj, "sceneItem2", "sceneItemTarget2", "sceneItemIdx2");
_condition = static_cast<SceneOrderCondition>(
obs_data_get_int(obj, "condition"));
_position = obs_data_get_int(obj, "position");
@@ -132,15 +169,15 @@ bool MacroConditionSceneOrder::Load(obs_data_t *obj)
std::string MacroConditionSceneOrder::GetShortDesc()
{
if (_source) {
std::string header =
_scene.ToString() + " - " + GetWeakSourceName(_source);
if (_source2 && _condition != SceneOrderCondition::POSITION) {
header += " - " + GetWeakSourceName(_source2);
}
return header;
if (_source.ToString().empty()) {
return "";
}
return "";
std::string header = _scene.ToString() + " - " + _source.ToString();
if (!_source2.ToString().empty() &&
_condition != SceneOrderCondition::POSITION) {
header += " - " + _source2.ToString();
}
return header;
}
static inline void populateConditionSelection(QComboBox *list)
@@ -155,21 +192,37 @@ MacroConditionSceneOrderEdit::MacroConditionSceneOrderEdit(
: QWidget(parent)
{
_scenes = new SceneSelectionWidget(window(), false, false, true);
_sources = new QComboBox();
_sources2 = new QComboBox();
_sources = new SceneItemSelectionWidget(parent);
_sources2 = new SceneItemSelectionWidget(parent);
_conditions = new QComboBox();
_position = new QSpinBox();
_posInfo = new QLabel(obs_module_text(
"AdvSceneSwitcher.condition.sceneOrder.positionInfo"));
populateConditionSelection(_conditions);
if (entryData.get()) {
if (entryData->_condition == SceneOrderCondition::POSITION) {
_sources->SetShowAllSelectionType(
SceneItemSelectionWidget::AllSelectionType::ANY);
} else {
_sources->SetShowAllSelectionType(
SceneItemSelectionWidget::AllSelectionType::ALL);
}
}
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sources, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(SourceChanged(const QString &)));
QWidget::connect(_sources2, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(Source2Changed(const QString &)));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
_sources, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
_sources2, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sources,
SIGNAL(SceneItemChanged(const SceneItemSelection &)),
this, SLOT(SourceChanged(const SceneItemSelection &)));
QWidget::connect(_sources2,
SIGNAL(SceneItemChanged(const SceneItemSelection &)),
this,
SLOT(Source2Changed(const SceneItemSelection &)));
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ConditionChanged(int)));
QWidget::connect(_position, SIGNAL(valueChanged(int)), this,
@@ -199,36 +252,31 @@ void MacroConditionSceneOrderEdit::SceneChanged(const SceneSelection &s)
if (_loading || !_entryData) {
return;
}
{
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
}
_sources->clear();
_sources2->clear();
populateSceneItemSelection(_sources, _entryData->_scene);
populateSceneItemSelection(_sources2, _entryData->_scene);
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
}
void MacroConditionSceneOrderEdit::SourceChanged(const QString &text)
void MacroConditionSceneOrderEdit::SourceChanged(const SceneItemSelection &item)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_source = GetWeakSourceByQString(text);
_entryData->_source = item;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroConditionSceneOrderEdit::Source2Changed(const QString &text)
void MacroConditionSceneOrderEdit::Source2Changed(const SceneItemSelection &item)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_source2 = GetWeakSourceByQString(text);
_entryData->_source2 = item;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
@@ -238,11 +286,21 @@ void MacroConditionSceneOrderEdit::ConditionChanged(int index)
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_condition = static_cast<SceneOrderCondition>(index);
{
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_condition =
static_cast<SceneOrderCondition>(index);
}
SetWidgetVisibility(_entryData->_condition ==
SceneOrderCondition::POSITION);
if (_entryData->_condition == SceneOrderCondition::POSITION) {
_sources->SetShowAllSelectionType(
SceneItemSelectionWidget::AllSelectionType::ANY);
} else {
_sources->SetShowAllSelectionType(
SceneItemSelectionWidget::AllSelectionType::ALL);
}
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
@@ -272,12 +330,9 @@ void MacroConditionSceneOrderEdit::UpdateEntryData()
}
_scenes->SetScene(_entryData->_scene);
populateSceneItemSelection(_sources, _entryData->_scene);
populateSceneItemSelection(_sources2, _entryData->_scene);
_sources->setCurrentText(
GetWeakSourceName(_entryData->_source).c_str());
_sources2->setCurrentText(
GetWeakSourceName(_entryData->_source2).c_str());
_sources->SetSceneItem(_entryData->_source);
_sources2->SetSceneItem(_entryData->_source2);
_position->setValue(_entryData->_position);
_conditions->setCurrentIndex(static_cast<int>(_entryData->_condition));
SetWidgetVisibility(_entryData->_condition ==
SceneOrderCondition::POSITION);

View File

@@ -15,10 +15,7 @@ bool MacroConditionSceneTransform::_registered =
bool MacroConditionSceneTransform::CheckCondition()
{
bool ret = false;
auto s = obs_weak_source_get_source(_scene.GetScene(false));
auto scene = obs_scene_from_source(s);
auto name = GetWeakSourceName(_source);
auto items = getSceneItemsWithName(scene, name);
auto items = _source.GetSceneItems(_scene);
for (auto &item : items) {
auto json = getSceneItemTransform(item);
@@ -27,8 +24,6 @@ bool MacroConditionSceneTransform::CheckCondition()
}
obs_sceneitem_release(item);
}
obs_source_release(s);
return ret;
}
@@ -36,7 +31,7 @@ bool MacroConditionSceneTransform::Save(obs_data_t *obj)
{
MacroCondition::Save(obj);
_scene.Save(obj);
obs_data_set_string(obj, "source", GetWeakSourceName(_source).c_str());
_source.Save(obj);
obs_data_set_string(obj, "settings", _settings.c_str());
obs_data_set_bool(obj, "regex", _regex);
return true;
@@ -44,10 +39,16 @@ bool MacroConditionSceneTransform::Save(obs_data_t *obj)
bool MacroConditionSceneTransform::Load(obs_data_t *obj)
{
// Convert old data format
// TODO: Remove in future version
if (obs_data_has_user_value(obj, "source")) {
auto sourceName = obs_data_get_string(obj, "source");
obs_data_set_string(obj, "sceneItem", sourceName);
}
MacroCondition::Load(obj);
_scene.Load(obj);
const char *sourceName = obs_data_get_string(obj, "source");
_source = GetWeakSourceByName(sourceName);
_source.Load(obj);
_settings = obs_data_get_string(obj, "settings");
_regex = obs_data_get_bool(obj, "regex");
return true;
@@ -55,10 +56,11 @@ bool MacroConditionSceneTransform::Load(obs_data_t *obj)
std::string MacroConditionSceneTransform::GetShortDesc()
{
if (_source) {
return _scene.ToString() + " - " + GetWeakSourceName(_source);
if (_source.ToString().empty()) {
return "";
}
return "";
return _scene.ToString() + " - " + _source.ToString();
}
MacroConditionSceneTransformEdit::MacroConditionSceneTransformEdit(
@@ -67,7 +69,8 @@ MacroConditionSceneTransformEdit::MacroConditionSceneTransformEdit(
: QWidget(parent)
{
_scenes = new SceneSelectionWidget(window(), false, false, true);
_sources = new QComboBox();
_sources = new SceneItemSelectionWidget(
parent, true, SceneItemSelectionWidget::AllSelectionType::ANY);
_getSettings = new QPushButton(obs_module_text(
"AdvSceneSwitcher.condition.sceneTransform.getTransform"));
_settings = new QPlainTextEdit();
@@ -76,8 +79,11 @@ MacroConditionSceneTransformEdit::MacroConditionSceneTransformEdit(
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sources, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(SourceChanged(const QString &)));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
_sources, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sources,
SIGNAL(SceneItemChanged(const SceneItemSelection &)),
this, SLOT(SourceChanged(const SceneItemSelection &)));
QWidget::connect(_getSettings, SIGNAL(clicked()), this,
SLOT(GetSettingsClicked()));
QWidget::connect(_settings, SIGNAL(textChanged()), this,
@@ -125,14 +131,9 @@ void MacroConditionSceneTransformEdit::UpdateEntryData()
}
_scenes->SetScene(_entryData->_scene);
populateSceneItemSelection(_sources, _entryData->_scene);
_sources->setCurrentText(
GetWeakSourceName(_entryData->_source).c_str());
_sources->SetSceneItem(_entryData->_source);
_regex->setChecked(_entryData->_regex);
if (_entryData->_source) {
_settings->setPlainText(
QString::fromStdString(_entryData->_settings));
}
_settings->setPlainText(QString::fromStdString(_entryData->_settings));
}
void MacroConditionSceneTransformEdit::SceneChanged(const SceneSelection &s)
@@ -140,48 +141,45 @@ void MacroConditionSceneTransformEdit::SceneChanged(const SceneSelection &s)
if (_loading || !_entryData) {
return;
}
{
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
}
_sources->clear();
populateSceneItemSelection(_sources, _entryData->_scene);
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
}
void MacroConditionSceneTransformEdit::SourceChanged(const QString &text)
void MacroConditionSceneTransformEdit::SourceChanged(
const SceneItemSelection &item)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_source = GetWeakSourceByQString(text);
_entryData->_source = item;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroConditionSceneTransformEdit::GetSettingsClicked()
{
if (_loading || !_entryData || !_entryData->_scene.GetScene(false) ||
!_entryData->_source) {
if (_loading || !_entryData || !_entryData->_scene.GetScene(false)) {
return;
}
auto s = obs_weak_source_get_source(_entryData->_scene.GetScene(false));
auto scene = obs_scene_from_source(s);
auto name = GetWeakSourceName(_entryData->_source);
auto item = obs_scene_find_source_recursive(scene, name.c_str());
obs_source_release(s);
if (!item) {
auto items = _entryData->_source.GetSceneItems(_entryData->_scene);
if (items.empty()) {
return;
}
QString json = formatJsonString(getSceneItemTransform(item));
auto settings = formatJsonString(getSceneItemTransform(items[0]));
if (_entryData->_regex) {
json = escapeForRegex(json);
settings = escapeForRegex(settings);
}
_settings->setPlainText(settings);
for (auto item : items) {
obs_sceneitem_release(item);
}
_settings->setPlainText(json);
}
void MacroConditionSceneTransformEdit::SettingsChanged()

View File

@@ -22,52 +22,54 @@ static std::map<SceneVisibilityCondition, std::string>
"AdvSceneSwitcher.condition.sceneVisibility.type.hidden"},
};
struct VisibilityData {
std::string name;
bool visible;
bool result;
};
static bool visibilityEnum(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
bool areAllSceneItemsShown(std::vector<obs_scene_item *> &items)
{
VisibilityData *vInfo = reinterpret_cast<VisibilityData *>(ptr);
auto sourceName = obs_source_get_name(obs_sceneitem_get_source(item));
if (vInfo->name == sourceName &&
obs_sceneitem_visible(item) == vInfo->visible) {
vInfo->result = true;
return false;
bool ret = true;
for (auto item : items) {
if (!obs_sceneitem_visible(item)) {
ret = false;
}
obs_sceneitem_release(item);
}
return ret;
}
if (obs_sceneitem_is_group(item)) {
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
obs_scene_enum_items(scene, visibilityEnum, ptr);
bool areAllSceneItemsHidden(std::vector<obs_scene_item *> &items)
{
bool ret = true;
for (auto item : items) {
if (obs_sceneitem_visible(item)) {
ret = false;
}
obs_sceneitem_release(item);
}
return true;
return ret;
}
bool MacroConditionSceneVisibility::CheckCondition()
{
if (!_source) {
auto items = _source.GetSceneItems(_scene);
if (items.empty()) {
return false;
}
auto s = obs_weak_source_get_source(_scene.GetScene());
auto scene = obs_scene_from_source(s);
auto sourceName = GetWeakSourceName(_source);
VisibilityData data = {sourceName,
_condition == SceneVisibilityCondition::SHOWN,
false};
obs_scene_enum_items(scene, visibilityEnum, &data);
obs_source_release(s);
return data.result;
switch (_condition) {
case SceneVisibilityCondition::SHOWN:
return areAllSceneItemsShown(items);
case SceneVisibilityCondition::HIDDEN:
return areAllSceneItemsHidden(items);
break;
default:
break;
}
return false;
}
bool MacroConditionSceneVisibility::Save(obs_data_t *obj)
{
MacroCondition::Save(obj);
_scene.Save(obj);
obs_data_set_string(obj, "source", GetWeakSourceName(_source).c_str());
_source.Save(obj);
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
@@ -76,10 +78,16 @@ bool MacroConditionSceneVisibility::Save(obs_data_t *obj)
bool MacroConditionSceneVisibility::Load(obs_data_t *obj)
{
// Convert old data format
// TODO: Remove in future version
if (obs_data_has_user_value(obj, "source")) {
auto sourceName = obs_data_get_string(obj, "source");
obs_data_set_string(obj, "sceneItem", sourceName);
}
MacroCondition::Load(obj);
_scene.Load(obj);
const char *sourceName = obs_data_get_string(obj, "source");
_source = GetWeakSourceByName(sourceName);
_source.Load(obj);
_condition = static_cast<SceneVisibilityCondition>(
obs_data_get_int(obj, "condition"));
return true;
@@ -87,10 +95,10 @@ bool MacroConditionSceneVisibility::Load(obs_data_t *obj)
std::string MacroConditionSceneVisibility::GetShortDesc()
{
if (_source) {
return _scene.ToString() + " - " + GetWeakSourceName(_source);
if (_source.ToString().empty()) {
return "";
}
return "";
return _scene.ToString() + " - " + _source.ToString();
}
static inline void populateConditionSelection(QComboBox *list)
@@ -106,16 +114,18 @@ MacroConditionSceneVisibilityEdit::MacroConditionSceneVisibilityEdit(
: QWidget(parent)
{
_scenes = new SceneSelectionWidget(window(), false, true, true);
_sources = new QComboBox();
_sources->setSizeAdjustPolicy(QComboBox::AdjustToContents);
_sources = new SceneItemSelectionWidget(parent);
_conditions = new QComboBox();
populateConditionSelection(_conditions);
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sources, SIGNAL(currentTextChanged(const QString &)),
this, SLOT(SourceChanged(const QString &)));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
_sources, SLOT(SceneChanged(const SceneSelection &)));
QWidget::connect(_sources,
SIGNAL(SceneItemChanged(const SceneItemSelection &)),
this, SLOT(SourceChanged(const SceneItemSelection &)));
QWidget::connect(_conditions, SIGNAL(currentIndexChanged(int)), this,
SLOT(ConditionChanged(int)));
@@ -136,14 +146,17 @@ MacroConditionSceneVisibilityEdit::MacroConditionSceneVisibilityEdit(
_loading = false;
}
void MacroConditionSceneVisibilityEdit::SourceChanged(const QString &text)
void MacroConditionSceneVisibilityEdit::SourceChanged(
const SceneItemSelection &item)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_source = GetWeakSourceByQString(text);
_entryData->_source = item;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroConditionSceneVisibilityEdit::SceneChanged(const SceneSelection &s)
@@ -151,13 +164,10 @@ void MacroConditionSceneVisibilityEdit::SceneChanged(const SceneSelection &s)
if (_loading || !_entryData) {
return;
}
{
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
}
_sources->clear();
populateSceneItemSelection(_sources, _entryData->_scene);
_sources->adjustSize();
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroConditionSceneVisibilityEdit::ConditionChanged(int index)
@@ -178,7 +188,5 @@ void MacroConditionSceneVisibilityEdit::UpdateEntryData()
_conditions->setCurrentIndex(static_cast<int>(_entryData->_condition));
_scenes->SetScene(_entryData->_scene);
populateSceneItemSelection(_sources, _entryData->_scene);
_sources->setCurrentText(
GetWeakSourceName(_entryData->_source).c_str());
_sources->SetSceneItem(_entryData->_source);
}

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

@@ -0,0 +1,151 @@
#include "headers/macro-condition-edit.hpp"
#include "headers/macro-condition-studio-mode.hpp"
#include "headers/utility.hpp"
#include "headers/advanced-scene-switcher.hpp"
const std::string MacroConditionStudioMode::id = "studio_mode";
bool MacroConditionStudioMode::_registered = MacroConditionFactory::Register(
MacroConditionStudioMode::id,
{MacroConditionStudioMode::Create, MacroConditionStudioModeEdit::Create,
"AdvSceneSwitcher.condition.studioMode"});
static std::map<StudioModeCondition, std::string> studioModeConditionTypes = {
{StudioModeCondition::STUDIO_MODE_ACTIVE,
"AdvSceneSwitcher.condition.studioMode.state.active"},
{StudioModeCondition::STUDIO_MODE_NOT_ACTIVE,
"AdvSceneSwitcher.condition.studioMode.state.notActive"},
{StudioModeCondition::PREVIEW_SCENE,
"AdvSceneSwitcher.condition.studioMode.state.previewScene"},
};
bool MacroConditionStudioMode::CheckCondition()
{
bool ret = false;
switch (_condition) {
case StudioModeCondition::STUDIO_MODE_ACTIVE:
ret = obs_frontend_preview_program_mode_active();
break;
case StudioModeCondition::STUDIO_MODE_NOT_ACTIVE:
ret = !obs_frontend_preview_program_mode_active();
break;
case StudioModeCondition::PREVIEW_SCENE: {
auto s = obs_frontend_get_current_preview_scene();
auto scene = obs_source_get_weak_source(s);
ret = _scene.GetScene() == scene;
obs_weak_source_release(scene);
obs_source_release(s);
break;
}
default:
break;
}
return ret;
}
bool MacroConditionStudioMode::Save(obs_data_t *obj)
{
MacroCondition::Save(obj);
obs_data_set_int(obj, "condition", static_cast<int>(_condition));
_scene.Save(obj);
return true;
}
bool MacroConditionStudioMode::Load(obs_data_t *obj)
{
MacroCondition::Load(obj);
_condition = static_cast<StudioModeCondition>(
obs_data_get_int(obj, "condition"));
_scene.Load(obj);
return true;
}
std::string MacroConditionStudioMode::GetShortDesc()
{
if (_condition == StudioModeCondition::PREVIEW_SCENE) {
return _scene.ToString();
}
return "";
}
static inline void populateConditionSelection(QComboBox *list)
{
for (auto entry : studioModeConditionTypes) {
list->addItem(obs_module_text(entry.second.c_str()));
}
}
MacroConditionStudioModeEdit::MacroConditionStudioModeEdit(
QWidget *parent, std::shared_ptr<MacroConditionStudioMode> entryData)
: QWidget(parent)
{
_condition = new QComboBox();
_scenes = new SceneSelectionWidget(window());
populateConditionSelection(_condition);
QWidget::connect(_condition, SIGNAL(currentIndexChanged(int)), this,
SLOT(ConditionChanged(int)));
QWidget::connect(_scenes, SIGNAL(SceneChanged(const SceneSelection &)),
this, SLOT(SceneChanged(const SceneSelection &)));
QHBoxLayout *layout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{conditions}}", _condition},
{"{{scenes}}", _scenes},
};
placeWidgets(
obs_module_text("AdvSceneSwitcher.condition.studioMode.entry"),
layout, widgetPlaceholders);
setLayout(layout);
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
void MacroConditionStudioModeEdit::ConditionChanged(int cond)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_condition = static_cast<StudioModeCondition>(cond);
SetWidgetVisibility();
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroConditionStudioModeEdit::SceneChanged(const SceneSelection &s)
{
if (_loading || !_entryData) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
_entryData->_scene = s;
emit HeaderInfoChanged(
QString::fromStdString(_entryData->GetShortDesc()));
}
void MacroConditionStudioModeEdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
_condition->setCurrentIndex(static_cast<int>(_entryData->_condition));
_scenes->SetScene(_entryData->_scene);
SetWidgetVisibility();
}
void MacroConditionStudioModeEdit::SetWidgetVisibility()
{
if (!_entryData) {
return;
}
_scenes->setVisible(_entryData->_condition ==
StudioModeCondition::PREVIEW_SCENE);
}

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

@@ -180,7 +180,7 @@ void AdvSceneSwitcher::on_runMacro_clicked()
return;
}
bool ret = macro->PerformAction(true);
bool ret = macro->PerformAction(true, true);
if (!ret) {
QString err =
obs_module_text("AdvSceneSwitcher.macroTab.runFail");
@@ -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();
@@ -229,8 +239,14 @@ void AdvSceneSwitcher::PopulateMacroConditions(Macro &m, uint32_t afterIdx)
void AdvSceneSwitcher::SetEditMacro(Macro &m)
{
ui->macroName->setText(m.Name().c_str());
ui->runMacroInParallel->setChecked(m.RunInParallel());
{
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

@@ -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
@@ -108,11 +115,11 @@ bool Macro::CeckMatch()
return _matched;
}
bool Macro::PerformAction(bool forceParallel)
bool Macro::PerformAction(bool forceParallel, bool ignorePause)
{
if (!_done) {
vblog(LOG_INFO, "macro %s already running", _name.c_str());
return false;
return !forceParallel;
}
bool ret = true;
@@ -121,9 +128,10 @@ bool Macro::PerformAction(bool forceParallel)
if (_thread.joinable()) {
_thread.join();
}
_thread = std::thread([this] { RunActions(); });
_thread = std::thread(
[this, ignorePause] { RunActions(ignorePause); });
} else {
RunActions(ret);
RunActions(ret, ignorePause);
}
return ret;
}
@@ -141,13 +149,13 @@ void Macro::ResetTimers()
}
}
void Macro::RunActions(bool &retVal)
void Macro::RunActions(bool &retVal, bool ignorePause)
{
bool ret = true;
for (auto &a : _actions) {
a->LogAction();
ret = ret && a->PerformAction();
if (!ret || _stop) {
if (!ret || _stop || (_paused && !ignorePause)) {
retVal = ret;
_done = true;
return;
@@ -156,10 +164,10 @@ void Macro::RunActions(bool &retVal)
_done = true;
}
void Macro::RunActions()
void Macro::RunActions(bool ignorePause)
{
bool unused;
RunActions(unused);
RunActions(unused, ignorePause);
}
void Macro::SetPaused(bool pause)
@@ -193,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);
@@ -271,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);

View File

@@ -0,0 +1,240 @@
#include "headers/scene-item-selection.hpp"
#include <obs-module.h>
void SceneItemSelection::Save(obs_data_t *obj, const char *name,
const char *targetName, const char *idxName)
{
obs_data_set_int(obj, targetName, static_cast<int>(_target));
if (_target == SceneItemSelection::Target::INDIVIDUAL) {
obs_data_set_int(obj, idxName, _idx);
} else {
obs_data_set_int(obj, idxName, 0);
}
obs_data_set_string(obj, name, GetWeakSourceName(_sceneItem).c_str());
}
void SceneItemSelection::Load(obs_data_t *obj, const char *name,
const char *targetName, const char *idxName)
{
_target = static_cast<SceneItemSelection::Target>(
obs_data_get_int(obj, targetName));
_idx = obs_data_get_int(obj, idxName);
auto sceneItemName = obs_data_get_string(obj, name);
_sceneItem = GetWeakSourceByName(sceneItemName);
}
struct ItemCountData {
std::string name;
int count = 0;
};
static bool countSceneItem(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
{
auto data = reinterpret_cast<ItemCountData *>(ptr);
if (obs_sceneitem_is_group(item)) {
obs_scene_t *scene = obs_sceneitem_group_get_scene(item);
obs_scene_enum_items(scene, countSceneItem, ptr);
}
auto name = obs_source_get_name(obs_sceneitem_get_source(item));
if (name == data->name) {
data->count++;
}
return true;
}
int getCountOfSceneItemOccurance(SceneSelection &s, std::string &name,
bool enumAllScenes = true)
{
ItemCountData data{name};
if (enumAllScenes && (s.GetType() == SceneSelectionType::CURRENT ||
s.GetType() == SceneSelectionType::PREVIOUS)) {
auto enumScenes = [](void *param, obs_source_t *source) {
if (!source) {
return true;
}
auto data = reinterpret_cast<ItemCountData *>(param);
auto scene = obs_scene_from_source(source);
obs_scene_enum_items(scene, countSceneItem, data);
return true;
};
obs_enum_scenes(enumScenes, &data);
} else {
auto source = obs_weak_source_get_source(s.GetScene(false));
auto scene = obs_scene_from_source(source);
obs_scene_enum_items(scene, countSceneItem, &data);
obs_source_release(source);
}
return data.count;
}
std::vector<obs_scene_item *>
SceneItemSelection::GetSceneItems(SceneSelection &sceneSelection)
{
auto s = obs_weak_source_get_source(sceneSelection.GetScene(false));
auto scene = obs_scene_from_source(s);
auto name = GetWeakSourceName(_sceneItem);
int count = getCountOfSceneItemOccurance(sceneSelection, name, false);
auto items = getSceneItemsWithName(scene, name);
obs_source_release(s);
std::vector<obs_scene_item *> ret;
if (_target == SceneItemSelection::Target::ALL ||
_target == SceneItemSelection::Target::ANY) {
ret = items;
} else {
// Index order starts at the bottom and increases to the top
// As this might be confusing reverse that order internally
int idx = count - 1 - _idx;
if (idx >= 0 && idx < items.size()) {
obs_sceneitem_addref(items[idx]);
ret.emplace_back(items[idx]);
}
for (auto item : items) {
obs_sceneitem_release(item);
}
}
return ret;
}
std::string SceneItemSelection::ToString()
{
return GetWeakSourceName(_sceneItem);
}
SceneItemSelectionWidget::SceneItemSelectionWidget(QWidget *parent,
bool showAll,
AllSelectionType type)
: QWidget(parent), _showAll(showAll), _allType(type)
{
_sceneItems = new QComboBox();
_idx = new QComboBox();
_sceneItems->setSizeAdjustPolicy(QComboBox::AdjustToContents);
_idx->setSizeAdjustPolicy(QComboBox::AdjustToContents);
populateSceneItemSelection(_sceneItems);
QWidget::connect(_sceneItems,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(SelectionChanged(const QString &)));
QWidget::connect(_idx, SIGNAL(currentIndexChanged(int)), this,
SLOT(IdxChanged(int)));
auto layout = new QHBoxLayout;
layout->addWidget(_idx);
layout->addWidget(_sceneItems);
setLayout(layout);
_idx->hide();
}
void SceneItemSelectionWidget::SetSceneItem(const SceneItemSelection &item)
{
_sceneItems->setCurrentText(
QString::fromStdString(GetWeakSourceName(item._sceneItem)));
if (item._target == SceneItemSelection::Target::ALL) {
_allType = AllSelectionType::ALL;
_idx->setCurrentIndex(0);
} else if (item._target == SceneItemSelection::Target::ANY) {
_allType = AllSelectionType::ANY;
_idx->setCurrentIndex(0);
} else {
int idx = item._idx;
if (_showAll) {
idx += 1;
}
_idx->setCurrentIndex(idx);
}
}
void SceneItemSelectionWidget::SetScene(const SceneSelection &s)
{
_scene = s;
_sceneItems->clear();
_idx->hide();
populateSceneItemSelection(_sceneItems, _scene);
}
void SceneItemSelectionWidget::SetShowAll(bool value)
{
_showAll = value;
}
void SceneItemSelectionWidget::SetShowAllSelectionType(AllSelectionType t)
{
_allType = t;
_sceneItems->setCurrentIndex(0);
}
void SceneItemSelectionWidget::SceneChanged(const SceneSelection &s)
{
SetScene(s);
adjustSize();
}
void SceneItemSelectionWidget::SelectionChanged(const QString &name)
{
SceneItemSelection s;
_sceneItem = GetWeakSourceByQString(name);
s._sceneItem = _sceneItem;
if (_allType == AllSelectionType::ALL) {
s._target = SceneItemSelection::Target::ALL;
} else {
s._target = SceneItemSelection::Target::ANY;
}
auto stdName = name.toStdString();
int sceneItemCount = getCountOfSceneItemOccurance(_scene, stdName);
if (sceneItemCount > 1) {
_idx->show();
SetupIdxSelection(sceneItemCount);
} else {
_idx->hide();
}
emit SceneItemChanged(s);
}
void SceneItemSelectionWidget::IdxChanged(int idx)
{
if (idx < 0) {
return;
}
SceneItemSelection s;
s._sceneItem = _sceneItem;
if (_showAll && idx == 0) {
if (_allType == AllSelectionType::ALL) {
s._target = SceneItemSelection::Target::ALL;
} else {
s._target = SceneItemSelection::Target::ANY;
}
s._idx = 0;
} else {
s._target = SceneItemSelection::Target::INDIVIDUAL;
if (_showAll) {
idx -= 1;
}
s._idx = idx;
}
emit SceneItemChanged(s);
}
void SceneItemSelectionWidget::SetupIdxSelection(int sceneItemCount)
{
_idx->clear();
if (_showAll) {
if (_allType == AllSelectionType::ALL) {
_idx->addItem(obs_module_text(
"AdvSceneSwitcher.sceneItemSelection.all"));
} else {
_idx->addItem(obs_module_text(
"AdvSceneSwitcher.sceneItemSelection.any"));
}
}
for (int i = 1; i <= sceneItemCount; ++i) {
_idx->addItem(QString::number(i) + ".");
}
adjustSize();
}

91
src/status-dock.cpp Normal file
View File

@@ -0,0 +1,91 @@
#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

@@ -238,13 +238,10 @@ void AdvSceneSwitcher::setupAudioTab()
ui->audioFallback->setChecked(switcher->audioFallback.enable);
}
void AudioSwitch::setVolumeLevel(void *data,
const float magnitude[MAX_AUDIO_CHANNELS],
void AudioSwitch::setVolumeLevel(void *data, const float *,
const float peak[MAX_AUDIO_CHANNELS],
const float inputPeak[MAX_AUDIO_CHANNELS])
const float *)
{
UNUSED_PARAMETER(magnitude);
UNUSED_PARAMETER(inputPeak);
AudioSwitch *s = static_cast<AudioSwitch *>(data);
for (int i = 0; i < MAX_AUDIO_CHANNELS; i++) {

View File

@@ -313,10 +313,8 @@ std::string processMessage(std::string payload)
return ret;
}
void WSServer::onMessage(connection_hdl hdl, server::message_ptr message)
void WSServer::onMessage(connection_hdl, server::message_ptr message)
{
UNUSED_PARAMETER(hdl);
auto opcode = message->get_opcode();
if (opcode != websocketpp::frame::opcode::text) {
return;
@@ -449,16 +447,14 @@ void WSClient::disconnect()
}
}
void WSClient::onOpen(connection_hdl hdl)
void WSClient::onOpen(connection_hdl)
{
UNUSED_PARAMETER(hdl);
blog(LOG_INFO, "connection to %s opened", _uri.c_str());
switcher->clientStatus = ClientStatus::CONNECTED;
}
void WSClient::onFail(connection_hdl hdl)
void WSClient::onFail(connection_hdl)
{
UNUSED_PARAMETER(hdl);
blog(LOG_INFO, "connection to %s failed", _uri.c_str());
}
@@ -486,9 +482,8 @@ void WSClient::onMessage(connection_hdl hdl, client::message_ptr message)
}
}
void WSClient::onClose(connection_hdl hdl)
void WSClient::onClose(connection_hdl)
{
UNUSED_PARAMETER(hdl);
blog(LOG_INFO, "client-connection to %s closed.", _uri.c_str());
switcher->clientStatus = ClientStatus::DISCONNECTED;
}

View File

@@ -120,6 +120,10 @@ void SwitcherData::Prune()
bool SwitcherData::versionChanged(obs_data_t *obj, std::string currentVersion)
{
if (!obs_data_has_user_value(obj, "version")) {
return false;
}
switcher->firstBoot = false;
std::string previousVersion = obs_data_get_string(obj, "version");
return previousVersion != currentVersion;
}

View File

@@ -13,6 +13,7 @@
#include <QMessageBox>
#include <QJsonDocument>
#include <QSystemTrayIcon>
#include <QGuiApplication>
#include <unordered_map>
#include <regex>
#include <set>
@@ -317,7 +318,7 @@ static bool getSceneItems(obs_scene_t *, obs_sceneitem_t *item, void *ptr)
return true;
}
std::vector<obs_scene_item *> getSceneItemsWithName(OBSScene scene,
std::vector<obs_scene_item *> getSceneItemsWithName(obs_scene_t *scene,
std::string &name)
{
ItemInfo itemInfo = {name};
@@ -371,13 +372,13 @@ std::string getDataFilePath(const std::string &file)
QString formatJsonString(std::string s)
{
return formatJsonString(s.c_str());
return formatJsonString(QString::fromStdString(s));
}
QString formatJsonString(const char *json)
QString formatJsonString(QString json)
{
QJsonDocument doc = QJsonDocument::fromJson(json);
return doc.toJson(QJsonDocument::Indented);
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
return QString::fromUtf8(doc.toJson(QJsonDocument::Indented));
}
QString escapeForRegex(QString &s)
@@ -844,7 +845,7 @@ void populateSceneItemSelection(QComboBox *list, SceneSelection &s)
list->setCurrentIndex(0);
}
void populateSourceTypeSelection(QComboBox *list)
void populateSourceGroupSelection(QComboBox *list)
{
std::set<QString> sourceTypeNames;
auto enumSourcesTypes = [](void *param, obs_source_t *source) {
@@ -874,6 +875,11 @@ void populateSourceTypeSelection(QComboBox *list)
list->setCurrentIndex(0);
}
bool windowPosValid(QPoint pos)
{
return !!QGuiApplication::screenAt(pos);
}
QMetaObject::Connection PulseWidget(QWidget *widget, QColor startColor,
QColor endColor, QString specifier,
bool once)