Compare commits

..

207 Commits
1.14 ... 1.17.2

Author SHA1 Message Date
WarmUpTill
af188b55df Move plugins to separate folder (#400) 2022-01-29 15:47:16 +01:00
WarmUpTill
f287a1041d Add option to also check for configured volume level 2022-01-25 12:46:16 -08:00
WarmUpTill
fda9b1c3ea Fix dock location and size not saving correctly
OBS will handle the docking position / window size and position as long
as an object name is set
2022-01-25 10:33:41 -08:00
WarmUpTill
9eb7f58525 CI: Save debian build result 2022-01-25 10:33:02 -08:00
WarmUpTill
abd6fd6b7e Add sequence action (#395) 2022-01-22 18:07:26 +01:00
WarmUpTill
2909b1300e Fix empty statusControl of general tab blocking mouse input 2022-01-22 06:14:03 -08:00
WarmUpTill
d1331a60b9 Fix crash on exit caused by status dock 2022-01-22 06:14:03 -08:00
WarmUpTill
d5fc3befb8 Remove QtConcurrent dependency 2022-01-22 06:14:03 -08:00
WarmUpTill
80f9c79907 CI: Bump windows QT version to 5.15.2 2022-01-22 06:14:03 -08:00
WarmUpTill
e4bd1fc180 Reduce amount of signals emitted on repopulate 2022-01-22 06:14:03 -08:00
WarmUpTill
59c87ca027 Emphasize that a duration of 0s means using default duration 2022-01-21 09:51:00 -08:00
WarmUpTill
eda161de39 Sort condition and action selection alphabetically 2022-01-21 09:51:00 -08:00
WarmUpTill
6033426a6e Enable word wrap for macro priority warning 2022-01-21 09:51:00 -08:00
WarmUpTill
caea16c6ad Hide selected macro for run or stop action
Running a macro from within itself is not supported and stopping it from
withint itself does not seem useful either.
2022-01-21 09:51:00 -08:00
WarmUpTill
e3a39a5df7 Add label clarifying the condition's intent 2022-01-21 09:51:00 -08:00
WarmUpTill
38b7e08711 Add macro action to stop other macros 2022-01-21 09:51:00 -08:00
WarmUpTill
7349841758 Fix unexpectedly returning true for hotkey condition
The condition would return true after unpause, if a configured hotkey was pressed
during the time the macro was paused.
2022-01-21 09:50:19 -08:00
WarmUpTill
5d58269b02 Add function to access parent macro from condition or action 2022-01-21 09:50:19 -08:00
WarmUpTill
8a4aef0f50 Update bug_report.md 2022-01-19 20:22:26 +01:00
WarmUpTill
4b877d865c Add issue templates 2022-01-16 19:43:51 +01:00
WarmUpTill
82503286ea Use the same widget for main settings window and status dock 2022-01-14 09:11:36 -08:00
WarmUpTill
16ee789c82 Add option to perform macro actions only on condition change 2022-01-06 08:41:18 -08:00
WarmUpTill
d040a01016 Reintroduce checkbox to change current scene check transition behaviour 2022-01-06 08:41:18 -08:00
WarmUpTill
eb952afe58 Enable time constraints for transition condition 2022-01-06 08:41:18 -08:00
WarmUpTill
34cff925fc CI: No longer query for 32 bit OBS install path 2022-01-05 20:21:03 +01:00
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
WarmUpTill
82da6b3217 Update locale of "cooldown" and "no match" behaviour 2021-12-06 11:44:52 -08:00
WarmUpTill
8d83df9034 Add warning if macro functionality is not running with highest priority 2021-12-06 10:27:20 -08:00
WarmUpTill
0029977ae1 Adjust and move default priorities
New users will be confused if their macros are not executed,
if they are "blocked" by other scene switching methods.
2021-12-06 10:27:20 -08:00
WarmUpTill
0a481b3e31 Add example to data folder instructions for Linux 2021-12-04 08:32:52 -08:00
WarmUpTill
70b3c2e240 Workaround OpenCV MacOS build issue 2021-12-04 08:32:52 -08:00
WarmUpTill
1785035b96 Fix warnings 2021-12-04 08:32:52 -08:00
WarmUpTill
69ab101ba3 Fix header info for media and transition condition 2021-12-04 08:32:52 -08:00
WarmUpTill
d1e752cda1 Remove Linux workaround 2021-12-04 08:32:37 -08:00
WarmUpTill
e9d366f2b9 Update readme to include flatpak 2021-12-04 04:32:29 -08:00
WarmUpTill
b168518c60 Update zh-CN locale (provided by qwe1154323937) 2021-12-04 04:32:29 -08:00
WarmUpTill
845506f7e4 Allow running macros in parallel to other macros 2021-12-04 04:09:30 -08:00
WarmUpTill
9dd47b811b Add button to manually run macro actions 2021-12-04 04:09:30 -08:00
WarmUpTill
eafad7fe7f Add option to match any or all media sources of a specific scene 2021-12-04 04:04:55 -08:00
WarmUpTill
f36062859d Allow setting random duration in specified range 2021-12-04 03:37:46 -08:00
WarmUpTill
949e26781a Enable screenshots of scenes 2021-12-04 03:37:08 -08:00
WarmUpTill
2d70fbac36 Add compatability check for screenshot functionality 2021-12-04 03:37:08 -08:00
WarmUpTill
bb954a2e9a Add macro action for triggering screenshots 2021-12-04 03:37:08 -08:00
WarmUpTill
631423a251 Add condition to check if the plugin is running
This will only ever return true as the plugin cannot perform checks if
it is not running.
This is intended to be used in cases where it can be useful to trigger
actions once the plugin was stopped and restarted or if one wants to
perform actions after a certain amount of plugin "uptime".
2021-12-01 11:38:38 -08:00
WarmUpTill
c527f15744 Add hotkey to toggle pause state of macros 2021-12-01 09:23:04 -08:00
WarmUpTill
8fdacc3ef7 Suggest file name when saving settings 2021-11-28 09:57:30 -08:00
WarmUpTill
02918785ba Hide waitForTransition option if waiting for transition
The additions to the transition condition to check for target and source
scene of a ongoing transition fullfill the same role and this option
does not really fit the current scene check anyways.
2021-11-28 09:56:50 -08:00
WarmUpTill
2d9e6bcaa2 Add transition option to check for transition source and target scene 2021-11-28 09:56:50 -08:00
WarmUpTill
f2570e1deb Add the option to execute another macro's actions 2021-11-28 09:56:37 -08:00
WarmUpTill
f9afbcbc59 Add macro action to display system tray notifications 2021-11-28 09:56:17 -08:00
WarmUpTill
51b4ef326d Add fallback using QDesktopServices::openUrl() for "run" action
Users not familiar with launching processes with arguments might expect
the run action to behave like clicking on icons on the desktop and be
frustrated if the "file is not being opened".
Thus introducing this fallback might help some users out.
2021-11-23 11:11:41 -08:00
WarmUpTill
ad08df3d2f Clean up adding new macros to Random action 2021-11-23 11:11:41 -08:00
WarmUpTill
4d32e921f9 Resize list to minimum necessary height 2021-11-23 11:11:41 -08:00
WarmUpTill
5dfed8ac2a CI: Switch to OBS 27.1.3 2021-11-20 05:37:57 -08:00
WarmUpTill
d7102d395e Ensure contents of comboboxes are readable when changing scene/filter 2021-11-20 03:52:54 -08:00
WarmUpTill
82a41694a1 Allow interacting with OBS main window while plugin settings are opened 2021-11-20 03:52:54 -08:00
WarmUpTill
a1cae263c1 Add macro action "random" (#353)
This should be expanded upon by adding the ability to add weights to each macro.
2021-11-20 12:52:12 +01:00
WarmUpTill
cce6e240c2 Add option to fade in/out volume change 2021-11-17 12:30:10 -08:00
WarmUpTill
9d04b4d1a0 Move setLayoutVisible() to utility 2021-11-17 12:30:10 -08:00
WarmUpTill
fd7e48eff9 Add scene-visibility macro condition 2021-11-17 12:29:57 -08:00
WarmUpTill
0350a46004 Allow use of "previous scene" 2021-11-17 12:29:57 -08:00
WarmUpTill
00fec4b573 Fix macro hotkeys not working 2021-11-17 12:29:41 -08:00
WarmUpTill
c40a3af8ca Fix add, delete, reorder not working when changing macro segment type 2021-11-17 12:06:53 -08:00
WarmUpTill
e452d8cc8c Allow selecting source type for scene visibility action
This should allow to simplify some setups which required showing /
hiding all sources of a particular type.
2021-11-12 10:05:54 -08:00
WarmUpTill
fbc9818764 Fix macro count not updating correctly
The underlying issue are the potential deadlocks when triggering
frontent function calls while saving / loading is triggered in parallel
like it can happen when switching scene collections.

Hopefully the new frontend events allow for a cleaner solution.
2021-11-12 10:05:11 -08:00
WarmUpTill
5ef09f661f Show warning if macro is paused
And clean up timer handling for this condition type
2021-11-12 10:05:11 -08:00
WarmUpTill
2155a942f3 Do not check conditions of paused macros 2021-11-12 10:05:11 -08:00
WarmUpTill
5af206da60 Fix typo 2021-11-09 10:24:14 -08:00
WarmUpTill
924f68df64 Fix typo 2021-11-07 11:14:25 +01:00
WarmUpTill
2f3c4a6dae Cleanup 2021-11-06 22:30:26 +01:00
WarmUpTill
f955c07bda Fix warnings 2021-11-01 11:23:43 -07:00
WarmUpTill
6f1cd3cbcc Enable building without opencv 2021-11-01 11:23:43 -07:00
WarmUpTill
95537f39e4 Switch to using process names for process condition and executable tab (#337)
Previously the process condition and executable tab were just reusing
the window title functionality.
2021-10-31 14:05:54 +01:00
WarmUpTill
0490c97ad9 Add option to use pattern matching for "output changed" condition
This will allow you to ignore minor changes in the video output, for
example in noisy video streams.
2021-10-31 06:05:16 -07:00
WarmUpTill
4b17314c66 Add conditions "stream starting" and "stream stopping" 2021-10-31 05:40:28 -07:00
WarmUpTill
7459793fe3 Improve missing data dir error 2021-10-30 11:40:34 -07:00
WarmUpTill
8a39a859be Remove whitespace 2021-10-30 11:40:26 -07:00
WarmUpTill
f8a592f17a CI: Update readme 2021-10-30 11:40:26 -07:00
WarmUpTill
f824ac8f4e Add option to display plugin running state in system tray 2021-10-30 11:40:10 -07:00
WarmUpTill
8e9323173a CI: Run builds on tag creation also 2021-10-28 14:38:25 -07:00
WarmUpTill
9bc59c1082 Add option to not save remaining time 2021-10-25 11:19:53 -07:00
WarmUpTill
8b9f03a349 Add timer action
This action can be used to control the state of the timers on macro
conditions
2021-10-23 13:54:26 -07:00
WarmUpTill
093b0f9ec0 Add pause / continue and save / load remaining time for time condition 2021-10-23 13:54:26 -07:00
WarmUpTill
254eabfa8d Fix exact image match not wokring when using images with alpha channel
The screenshots taken from video sources were using the image format
Format_RGBX8888 instead of Format_RGBA8888.
The alpha channel of screenshots taken from OBS would be blended with a
black background while this step would be not performed for files loaded
to macht match the video sources.
2021-10-23 13:54:15 -07:00
WarmUpTill
b2da8faf37 Improve performance by not creating pattern data each interval 2021-10-23 13:54:15 -07:00
WarmUpTill
3eba20e2d8 Add option to use alpha channel as mask for pattern match 2021-10-23 13:54:15 -07:00
WarmUpTill
08841aa88e Use duration control class / widget for scene triggers 2021-10-23 13:53:56 -07:00
WarmUpTill
2e96c226b5 Improve performance of expand / collapse all 2021-10-23 13:53:56 -07:00
WarmUpTill
c34308f743 Fix scroll position being lost when adding or removing macro segments 2021-10-23 13:53:56 -07:00
WarmUpTill
4af07d9d55 Fix incorrectly set start scene type when extending scquence with groups
This would result in extended sequences being aborted early whenever one
would try to extend after a scene group entry
2021-10-23 13:53:56 -07:00
WarmUpTill
d743260ca8 Add wait for transition to complete option for currrent scene check
Previous behaviour was to always wait for the transition to complete, as
switcher->currentScene is only updated on
OBS_FRONTEND_EVENT_SCENE_CHANGED.
2021-10-23 13:53:56 -07:00
WarmUpTill
8ff50056f0 Fix crash when switching scene collection during macro wait
Also update comment stating why the main mutex needs to be unlocked
during the "action" phase of running macros
2021-10-23 13:53:56 -07:00
WarmUpTill
b786831f3b Remove unnecessary return value check 2021-10-23 13:53:56 -07:00
WarmUpTill
32e2a5f44c Add git tag to version info 2021-10-19 13:02:15 -07:00
WarmUpTill
e3f277c32a Reword date repeat option 2021-10-19 13:01:24 -07:00
WarmUpTill
5a7d76061c Clean up general tab
- Remove unnecessary spacer next to priority list
- Remove horizontal line in General behviour section
2021-10-19 13:01:01 -07:00
WarmUpTill
39a8c34fa6 Add description for the "min neighbors" parameter 2021-10-09 08:08:15 -07:00
WarmUpTill
ead51e2f13 Fix minNeighbors parameter not loading correctly 2021-10-09 08:08:15 -07:00
WarmUpTill
3b465e1fdc Fix crash while loading haar cascade 2021-10-03 12:30:45 -07:00
WarmUpTill
26fd26051b CI: Run on ubuntu-latest 2021-10-03 11:11:53 -07:00
WarmUpTill
08933a3683 Add transition condition 2021-10-03 07:51:09 -07:00
WarmUpTill
9be00ba3ca Rework to use transition selection widget 2021-10-03 07:51:09 -07:00
WarmUpTill
cce15529fe Adjust return type 2021-10-03 07:51:09 -07:00
WarmUpTill
588f90f0b1 Add transition selection widget 2021-10-03 07:51:09 -07:00
WarmUpTill
d3220c40dc Add any transition selection in populate function 2021-10-03 07:51:09 -07:00
WarmUpTill
79c659b4fa Reduce logging 2021-10-03 01:38:08 -07:00
WarmUpTill
292adb990d Add option to throttle object and pattern recognition 2021-10-03 01:38:08 -07:00
WarmUpTill
b7a0f6c5d0 Add object detection option 2021-10-03 01:38:08 -07:00
WarmUpTill
b3f1aff03c Add file selection widget
Rework the following macro conditions and actions to use this widget:
 - file action
 - run action
 - file condition
2021-10-03 01:38:08 -07:00
WarmUpTill
aea9d1b319 Update build instructions 2021-10-03 01:38:08 -07:00
WarmUpTill
1fd724e4f4 Include OpenCV in build 2021-10-03 01:38:08 -07:00
WarmUpTill
3d1c613f1c Add pattern match using openCV 2021-10-03 01:38:08 -07:00
WarmUpTill
9ca2f4470b Add opencv as submodule 2021-10-03 01:38:08 -07:00
WarmUpTill
34527b08a9 Fix crash in getSourceSettings() 2021-10-02 14:14:57 -07:00
WarmUpTill
3ae1050488 CI: Switch to obs tag 27.1.1 2021-09-30 12:13:15 -07:00
WarmUpTill
d7ec7c6e40 Limit key press to OBS by default on MacOS 2021-09-30 10:42:57 -07:00
WarmUpTill
e98ee64974 Set canSimulateKeyPresses to false on Macos (not implemented) 2021-09-30 10:42:57 -07:00
WarmUpTill
7c6428b27e Include press duration option and option to limit key press to OBS 2021-09-30 10:42:57 -07:00
WarmUpTill
aca9b84fc6 Fix rapid scene switch restarting certain transitions (#313)
When using certain transition types repeated scene switches to the same target scene will restart a transition that is already in progress.
This can be avoided by using obs_frontend_get_current_scene() instead of switcher->currentScene during the check if the target scene is already active.
obs_frontend_get_current_scene() will already point to the new scene, even if the transition is still in progess, while switcher->currentScene will only be updated once a transition is finished.
2021-09-26 14:04:01 +02:00
WarmUpTill
d397f5e406 Add transition action 2021-09-19 05:15:49 -07:00
WarmUpTill
97cbcd7e61 Add condition "scene has not changed" 2021-09-18 10:21:54 -07:00
WarmUpTill
64fd8dd50d Add "apt update" calls 2021-09-18 10:21:35 -07:00
WarmUpTill
a0dd1cf3ef Remove unused variable 2021-09-16 10:27:32 -07:00
WarmUpTill
25cf51abea Add option to specify lib and data install location 2021-09-13 12:50:10 -07:00
Joao Eriberto Mota Filho
3c8f5088d3 Fix word "unknown" 2021-09-13 10:58:39 -07:00
Joao Eriberto Mota Filho
66f3c74cf3 Fix some mistakes in debian CI test
Some mistakes found when packaging for Debian:
  - Remove trash from rules and enforce hardening.
  - Use the same licensing from Debian package to avoid a misinterpretation
    from FTP Master.
  - Fix target variable in debian/rules
2021-09-13 10:58:39 -07:00
WarmUpTill
6c23110fb9 Strip Linux binary debug symbols to reduce release artifact size 2021-09-12 11:09:00 -07:00
WarmUpTill
c9001df97c Add libxss-dev dependency 2021-09-12 11:09:00 -07:00
WarmUpTill
76fa1f8942 Add backward compatibility check to support OBS 25 2021-09-12 10:20:59 -07:00
Joao Eriberto Mota Filho
55ca146a82 Install missing obs-frontend-api.h 2021-09-12 10:20:59 -07:00
Joao Eriberto Mota Filho
a3625242de Create CI test for Debian packaging (in Ubuntu 20.04) 2021-09-12 10:20:59 -07:00
WarmUpTill
db4214c918 Remove dependency to <util/util.hpp> 2021-09-12 03:11:21 -07:00
WarmUpTill
f024199e2d Add backwards compatibility check 2021-09-12 03:11:21 -07:00
WarmUpTill
299e7bc868 Improve build instructions 2021-09-12 03:11:21 -07:00
WarmUpTill
0262e066bf Update cmake script to work better for out of tree builds
Use package name 'CURL' for out of tree builds.
Removed ObsPluginHelpers.cmake and FindLibObs.cmake as they disturbed
out of tree build.
2021-09-12 03:11:21 -07:00
WarmUpTill
bee75336d0 Add option to for macro condition scene to trigger on any scene change 2021-09-10 15:14:09 -07:00
WarmUpTill
96b472776a Remove unused variable 2021-09-10 15:14:09 -07:00
WarmUpTill
fb457f723a Add macro action scene swap 2021-09-10 14:21:29 -07:00
WarmUpTill
eee3e05c10 Add action to switch preview scene 2021-09-02 10:06:54 -07:00
WarmUpTill
ccc147a1b3 Fix empty paths not saving on file tab 2021-08-27 23:40:00 +02:00
WarmUpTill
45a149f6df Also save window geo when using ESC or the close button 2021-08-27 09:10:50 -07:00
WarmUpTill
076be21d40 Validate window position before setting it 2021-08-27 09:10:50 -07:00
WarmUpTill
ab5bdb32f5 Highlight newly added macro segments 2021-08-27 08:43:28 -07:00
WarmUpTill
8cfed048cc Create copy of previous macro segment when inserting new segment 2021-08-27 08:43:28 -07:00
WarmUpTill
c842595214 Add "size" section to scene item transform info 2021-08-27 08:43:08 -07:00
WarmUpTill
8fa3e8b038 Fix crash on clicking "Get settings" if source or filter is null 2021-08-27 08:43:08 -07:00
WarmUpTill
174c17edea Escape settings when pressing "Get settings" and regex is active 2021-08-27 08:43:08 -07:00
WarmUpTill
9d8fadda80 Remove unused include 2021-08-27 08:43:08 -07:00
WarmUpTill
58028d3c3d Add macro condition "scene transform" 2021-08-27 08:43:08 -07:00
WarmUpTill
3dcabe543f Add matchJson(), escapeRegex() move TransformState functions to utility 2021-08-27 08:43:08 -07:00
WarmUpTill
1a7ebc5569 Fix warning 2021-08-19 12:56:34 -07:00
WarmUpTill
522ab2963e Fix typo 2021-08-19 12:56:34 -07:00
WarmUpTill
d9bd98ce9c Parallelize windows build 2021-08-19 12:56:34 -07:00
WarmUpTill
2af0735a2f Expand date condition functionality
The date condition now supports the condition types "after", "before"
and specifying a time range.
2021-08-12 11:01:45 -07:00
WarmUpTill
556943c293 Fix writing current scene to file 2021-08-11 12:49:07 -07:00
WarmUpTill
e3004184c4 Format json strings of user input and source settings
Source settings and user specified settings might use different json
formatting and thus not match even though the json contents match.

It might not be possible to do the formatting for regex strings so
revert to the originally specified settings string if it cannot.
2021-08-09 11:39:48 -07:00
WarmUpTill
7b2c2e91db Rename function 2021-08-09 11:39:48 -07:00
WarmUpTill
06ea7bf1d9 Fix crash when deleting macro with wait action
Note that this might still not be completely race free but should
improve the situation a lot.
2021-08-09 11:39:20 -07:00
WarmUpTill
1474509cb9 Fix extended sequence abort when using non-instant transitions 2021-07-30 00:47:40 +02:00
WarmUpTill
87aa8d3b40 Remove code used for backwards compatibility 2021-07-29 15:16:29 -07:00
WarmUpTill
d3e8b76fa6 Do not apply MouseWheelWidgetAdjustmentGuard to QScrollBars
Without this change, it will be annoying to interact with expanded
QComboBoxes and there should be no danger of accidentally modifying
macro settings by interacting with QScrollBars
2021-07-29 15:16:19 -07:00
WarmUpTill
99c9b1a4a2 Fix macro video condition save
Logic, collapsed state and time constraint were not saved for video
condition.
2021-07-24 23:47:24 -07:00
WarmUpTill
8c0aad4c96 Add note to network tab
The requirement of the scene names having to match extactly was not made
clear and caused some confusion.
2021-07-24 23:31:35 -07:00
WarmUpTill
c964ed04d3 Clean up includes 2021-07-22 09:40:31 -07:00
WarmUpTill
810235e0b7 Clean up duplicate code 2021-07-22 09:40:31 -07:00
WarmUpTill
e2b3563810 Rename files 2021-07-22 09:40:31 -07:00
WarmUpTill
76c5ec480b Add MacroSegment and MacroSegmentEdit to remove duplicate code 2021-07-22 09:40:31 -07:00
WarmUpTill
84e4b740a8 Prevent accidental edits of actions and conditions when scrolling 2021-07-22 09:40:31 -07:00
WarmUpTill
95409dfa26 Add option to expand or collapse all macro actions or conditions 2021-07-22 09:40:31 -07:00
WarmUpTill
058af0d3bb Move GetShortDesc() and GetId() to MacroSegment class 2021-07-22 09:40:31 -07:00
WarmUpTill
fd789b476b Persist collapse / expand state 2021-07-22 09:40:31 -07:00
WarmUpTill
3fc82df278 Handle macro control signals 2021-07-22 09:40:31 -07:00
WarmUpTill
d541356fd3 Add macro control widget 2021-07-22 09:40:31 -07:00
WarmUpTill
5c2adacca1 Update build instructions and readme(#267)
* Adjust build instructions

* Add install instructions

* Add note regarding QtConcurrent
2021-07-22 18:39:34 +02:00
WarmUpTill
7200668158 Add option to show frame 2021-07-19 12:13:29 -07:00
WarmUpTill
7cf7fd6112 Show current cursor position 2021-07-19 12:13:29 -07:00
WarmUpTill
41821cbeb2 Add macro condition that triggers if cursor position changed
Extend condition previously named "region"
2021-07-19 12:13:29 -07:00
WarmUpTill
9537579235 Rename macro condition "region" to "cursor" 2021-07-19 12:13:29 -07:00
WarmUpTill
40a701a934 Add "--recursive" option to "git clone" calls 2021-07-18 19:37:16 +02:00
WarmUpTill
6c8556c66c Rework cmake and readme (#264)
* Add missing include

* Rework CMakeLists.txt to support out of tree builds

* Update build instructions

* Fix windows build issue and copy locale on Linux

* Update build instructions

* Add downloads section
2021-07-17 17:17:03 +02:00
WarmUpTill
a467dffd05 Fix crash on Fedora 2021-07-13 13:14:43 -07:00
WarmUpTill
497dbd89d4 Fix warning 2021-07-13 13:14:43 -07:00
WarmUpTill
0fdbce25a1 Clean up minor UI inconsistencies 2021-07-13 13:14:43 -07:00
206 changed files with 364699 additions and 2868 deletions

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

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

View File

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

55
.github/workflows/build-debian.yml vendored Normal file
View File

@@ -0,0 +1,55 @@
name: debian-build
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
mv ../*.deb .
- name: Publish
if: success()
uses: actions/upload-artifact@v2.2.1
with:
name: "obs-scene-switcher.deb"
path: ${{ github.workspace }}/*.deb

View File

@@ -1,38 +1,36 @@
name: build obs plugin
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
on: [push, pull_request, workflow_dispatch]
env:
PLUGIN_NAME: SceneSwitcher
LIB_NAME: advanced-scene-switcher
OBS_TAG: 27.1.3
jobs:
macos64:
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'
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
@@ -44,19 +42,28 @@ 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"
shell: bash
run: |
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}/deps/opencv
mkdir build
cd build
cmake -DBUILD_LIST="core,imgproc,objdetect" ..
make -j4
make install
- name: Configure
shell: bash
run: |
@@ -72,7 +79,7 @@ jobs:
cd ./build
make -j4
cd -
- name: 'Install prerequisite: Packages app'
- name: "Install prerequisite: Packages app"
if: success()
shell: bash
run: |
@@ -83,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
@@ -100,22 +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'
runs-on: [ubuntu-18.04]
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'
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
@@ -168,40 +180,52 @@ jobs:
qtbase5-private-dev \
libqt5svg5-dev \
swig \
libxss-dev
- name: 'Configure'
libxss-dev \
libx11-xcb-dev \
libxcb-xfixes0-dev \
libopencv-dev \
libprocps-dev
- 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)
FILE_NAME=${{ env.PLUGIN_NAME }}-$FILE_DATE-${{ github.sha }}-linux64.tar.gz
echo "FILE_NAME=${FILE_NAME}" >> $GITHUB_ENV
mkdir -p ./${{ env.LIB_NAME }}/bin/64bit/
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
mkdir -p ./${{ env.LIB_NAME }}/bin/64bit/adv-ss-plugins
strip -d ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/src/external-macro-modules/opencv/advanced-scene-switcher-opencv.so
mv ./build/UI/frontend-plugins/${{ env.PLUGIN_NAME }}/src/external-macro-modules/opencv/advanced-scene-switcher-opencv.so ./${{ env.LIB_NAME }}/bin/64bit/adv-ss-plugins
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]
strategy:
matrix:
arch: [32, 64]
env:
QT_VERSION: 5.10.1
QT_VERSION: 5.15.2
CMAKE_GENERATOR: "Visual Studio 16 2019"
CMAKE_SYSTEM_VERSION: "10.0.18363.657"
WINDOWS_DEPS_VERSION: '2019'
WINDOWS_DEPS_VERSION: "2019"
steps:
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.0.2
@@ -209,74 +233,121 @@ jobs:
uses: actions/checkout@v2.3.4
with:
repository: obsproject/obs-studio
submodules: 'recursive'
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"
run: |
cd UI/frontend-plugins/${{ env.PLUGIN_NAME }}/deps/opencv
mkdir build
cd build
if ( ${{ matrix.arch }} -eq 32 )
{
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DBUILD_LIST="core,imgproc,objdetect" ..
}
else
{
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DBUILD_LIST="core,imgproc,objdetect" ..
}
msbuild /m /p:Configuration=Release OpenCV.sln
msbuild INSTALL.vcxproj
- name: Configure
run: |
mkdir ./package
mkdir ./build32
cd ./build32
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win32" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
cd ..
mkdir ./build64
cd ./build64
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win64" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2017_64" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
mkdir ./build${{ matrix.arch }}
cd ./build${{ matrix.arch }}
Get-Location
if ( ${{ matrix.arch }} -eq 32 )
{
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"Win32" -DOpenCV_DIR="${{ github.workspace }}/UI/frontend-plugins/SceneSwitcher/deps/opencv/build/" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win32" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2019" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
}
else
{
cmake -G"${{ env.CMAKE_GENERATOR }}" -A"x64" -DOpenCV_DIR="${{ github.workspace }}/UI/frontend-plugins/SceneSwitcher/deps/opencv/build/" -DCMAKE_SYSTEM_VERSION="${{ env.CMAKE_SYSTEM_VERSION }}" -DBUILD_BROWSER=false -DBUILD_CAPTIONS=false -DCOMPILE_D3D12_HOOK=false -DDepsPath="${{ github.workspace }}/cmbuild/deps/win64" -DQTDIR="${{ github.workspace }}/cmbuild/QT/${{ env.QT_VERSION }}/msvc2019_64" -DCOPIED_DEPENDENCIES=FALSE -DCOPY_DEPENDENCIES=TRUE ..
}
- name: Build
run: |
msbuild /m /p:Configuration=RelWithDebInfo .\build32\obs-studio.sln
msbuild /m /p:Configuration=RelWithDebInfo .\build64\obs-studio.sln
msbuild /m /p:Configuration=RelWithDebInfo .\build${{ matrix.arch }}\obs-studio.sln
- name: Package
if: success()
run: |
$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 .\build32\rundir\RelWithDebInfo\obs-plugins\32bit\ .\package\obs-plugins\32bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
robocopy .\build64\rundir\RelWithDebInfo\obs-plugins\64bit\ .\package\obs-plugins\64bit ${{ env.LIB_NAME }}.* /E /XF .gitignore
robocopy .\build64\rundir\RelWithDebInfo\data\obs-plugins\${{ env.LIB_NAME }}\ .\package\data\obs-plugins\${{ 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\obs-plugins\${{ matrix.arch }}bit\ .\package\obs-plugins\${{ matrix.arch }}bit adv-ss-plugins /E /XF .gitignore
robocopy .\build${{ matrix.arch }}\rundir\RelWithDebInfo\data\obs-plugins\${{ env.LIB_NAME }}\ .\package\data\obs-plugins\${{ env.LIB_NAME }}\ /E /XF .gitignore
cp UI/frontend-plugins/${{ env.PLUGIN_NAME }}/deps/opencv/build/bin/Release/*dll package/obs-plugins/${{ matrix.arch }}bit/adv-ss-plugins
cp UI/frontend-plugins/${{ env.PLUGIN_NAME }}/deps/openvr/bin/win${{ matrix.arch }}/*dll package/obs-plugins/${{ matrix.arch }}bit/adv-ss-plugins
exit 0
- name: Publish zip
if: success()
uses: actions/upload-artifact@v2.2.1
with:
name: '${{ env.FILE_NAME }}'
name: "${{ env.FILE_NAME }}-${{ matrix.arch }}bit"
path: package/*
- name: "Package Installer (Prereqs)"
windows-installer:
needs: [windows]
name: "Create Windows Installer"
runs-on: [windows-latest]
steps:
- name: "Checkout plugin"
uses: actions/checkout@v2.3.4
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v1.0.2
- name: "Prepare innosetup"
run: |
curl "-kL" "https://files.jrsoftware.org/is/6/innosetup-6.0.3.exe" "-f" "--retry" "5" "-o" "inno.exe"
.\inno.exe /VERYSILENT /SP- /SUPPRESSMSGBOXES /NORESTART
mkdir build
cd build
cmake ..
continue-on-error: true
- name: Download artifacts
uses: actions/download-artifact@v2
with:
path: artifacts
- name: "Prepare package dir"
run: |
curl "-kL" "https://github.com/Xaymar/msvc-redist-helper/releases/download/0.1/msvc-redist-helper-64.exe" "-f" "--retry" "5" "-o" "msvc-redist-helper-64.exe"
curl "-kL" "https://github.com/Xaymar/msvc-redist-helper/releases/download/0.1/msvc-redist-helper-32.exe" "-f" "--retry" "5" "-o" "msvc-redist-helper-32.exe"
curl "-kL" "https://files.jrsoftware.org/is/6/innosetup-6.0.3.exe" "-f" "--retry" "5" "-o" "inno.exe"
.\inno.exe /VERYSILENT /SP- /SUPPRESSMSGBOXES /NORESTART
- name: "Package Installer (Compile)"
$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}
mkdir package
cd package
cp -r ../artifacts/${env:FILE_NAME}-32bit/* .
cp -r ../artifacts/${env:FILE_NAME}-64bit/obs-plugins/* obs-plugins
- name: "Compile"
run: |
& 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe' /Qp ".\build64\UI\frontend-plugins\${{ env.PLUGIN_NAME }}\CI\windows\setup.iss"
- name: Publish installer
& 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe' /Qp ".\build\CI\windows\setup.iss"
- name: "Publish"
if: success()
uses: actions/upload-artifact@v2.2.0
with:
name: '${{ env.FILE_NAME }}-installer'
path: build64/UI/frontend-plugins/SceneSwitcher/CI/windows/Output/*.exe
name: "${{ env.FILE_NAME }}-installer"
path: build/CI/windows/Output/*.exe
release:
needs: [macos64, ubuntu64, windows]
name: 'Create Release'
runs-on: [ubuntu-18.04]
needs: [macos64, ubuntu64, windows, windows-installer]
name: "Create Release"
runs-on: [ubuntu-latest]
steps:
- name: "Checkout plugin"
uses: actions/checkout@v2.3.4
@@ -286,13 +357,14 @@ 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
tar xf artifacts/${{ env.PLUGIN_NAME }}*-linux64.tar.gz/${{ env.PLUGIN_NAME }}*-linux64.tar.gz -C ${{ env.PLUGIN_NAME }}/Linux/
mv artifacts/${{ env.PLUGIN_NAME }}*-macos.pkg/${{ env.PLUGIN_NAME }}*-macos.pkg ${{ env.PLUGIN_NAME }}/MacOs/${{ env.PLUGIN_NAME }}.pkg
mv ./artifacts/${{ env.PLUGIN_NAME }}*-windows/* ${{ env.PLUGIN_NAME }}/Windows/
mv ./artifacts/${{ env.PLUGIN_NAME }}*-windows-32bit/* ${{ env.PLUGIN_NAME }}/Windows/
mv ./artifacts/${{ env.PLUGIN_NAME }}*-windows-64bit/obs-plugins/* ${{ env.PLUGIN_NAME }}/Windows/obs-plugins
mv ./artifacts/${{ env.PLUGIN_NAME }}*-windows-installer/*.exe ${{ env.PLUGIN_NAME }}/Windows/
rm ${{ env.PLUGIN_NAME }}/Windows/obs-plugins/32bit/advanced-scene-switcher.pdb
rm ${{ env.PLUGIN_NAME }}/Windows/obs-plugins/64bit/advanced-scene-switcher.pdb
@@ -304,4 +376,4 @@ jobs:
uses: actions/upload-artifact@v2.2.1
with:
name: "Release"
path: '*.zip'
path: "*.zip"

6
.gitmodules vendored
View File

@@ -4,3 +4,9 @@
[submodule "deps/websocketpp"]
path = deps/websocketpp
url = https://github.com/zaphoyd/websocketpp.git
[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

152
BUILDING.md Normal file
View File

@@ -0,0 +1,152 @@
# Compiling the plugin
You have the option to ...
- either add the plugin to the OBS source tree directly and build the plugin while building OBS itself. (**in tree**)
- or you can move the sources of this plugin outside of the OBS source tree and build it separately from OBS. (**out of tree**)
As both methods require you to have a working [OBS Studio development environment](https://obsproject.com/wiki/install-instructions), [Qt](https://download.qt.io/official_releases/qt/5.15/5.15.2/) and [CMake](https://cmake.org/download/) it is recommended to build the plugin in tree as it is easier to set up and will enable straightforward debugging.
Note that your Qt install must include the QtConcurrent module.
## Compiling in tree (recommended)
Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/UI/frontend-plugins/:
```
cd obs-studio/UI/frontend-plugins/
git clone --recursive https://github.com/WarmUpTill/SceneSwitcher.git
```
Then modify the obs-studio/UI/frontend-plugins/CMakeLists.txt file and add an entry for the scene switcher:
```
add_subdirectory(SceneSwitcher)
```
Now follow the [build instructions for obs-studio](https://obsproject.com/wiki/install-instructions) for your particular platform.
Note that on Linux systems it might be necessary to additionally install the following packages to fulfill the dependencies to `XTest`, `XScreensaver` and `OpenCV` - exact command may differ:
```
sudo apt-get install \
libxtst-dev \
libxss-dev \
libopencv-dev
```
## Compiling out of tree
### Prerequisites
You'll need [Qt](https://download.qt.io/official_releases/qt/5.15/5.15.2/), [CMake](https://cmake.org/download/) and a working [OBS Studio development environment](https://obsproject.com/wiki/install-instructions) installed on your computer.
Once you've set this up, do the following:
```
git clone --recursive https://github.com/WarmUpTill/SceneSwitcher.git
cd SceneSwitcher
mkdir build && cd build
```
### Windows
In cmake-gui, you'll have to set these CMake variables :
- **BUILD_OUT_OF_TREE** (bool) : true
- **LIBOBS_LIB** (filepath) : location of the obs.lib file
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source
code of OBS Studio, located at [source_directory]/libobs/.
- **LIBOBS_FRONTEND_API_LIB** (filepath) : location of the obs-frontend-api.lib file
(usually in the same place as LIBOBS_LIB)
- **LIBOBS_FRONTEND_INCLUDE_DIR** (path) : location of the obs-frontend-api
subfolder in the source code of OBS Studio, located at [source_directory]/UI/obs-frontend-api.
- **CURL_LIBRARY** (filepath) : location of the libcurl.lib file
(part of the dependencies2019/win64/bin folder used to build OBS)
- **CURL_INCLUDE_DIR** (path) : location of the curl
subfolder in OBS dependencies folder: ".../dependencies2019/win64/include/"
Assuming that you set up Qt via QT installer:
- **Qt5Core_DIR** (path) : C:/Qt/5.15.2/msvc2019_64/lib/cmake/Qt5Core
- **Qt5Gui_DIR** (path): C:/Qt/5.15.2/msvc2019_64/lib/cmake/Qt5Gui
- **Qt5Widgets_DIR** (path) : C:/Qt/5.15.2/msvc2019_64/lib/cmake/Qt5Widgets
Just keep hitting configure until all the vars are filled out. Then hit generate.
### Linux
Install dependencies `XTest`, `XScreensaver` and `OpenCV` - exact command may differ:
```
sudo apt-get install \
libxtst-dev \
libxss-dev \
libopencv-dev
```
Most versions of Linux you can use cmake-gui or the command line.
**For the command line:**
```
# [...] are placeholders
cmake -DBUILD_OUT_OF_TREE=1 \
-DLIBOBS_INCLUDE_DIR=[...]/obs-studio/libobs/ \
-DLIBOBS_LIB=[...]/libobs.so \
-DLIBOBS_FRONTEND_INCLUDE_DIR=[...]/obs-studio/UI/obs-frontend-api/ \
-DLIBOBS_FRONTEND_API_LIB=[...]/libobs-frontend-api.so \
-DCMAKE_INSTALL_PREFIX=/usr ..
make -j4
sudo make install
```
For cmake-gui you'll have to set the following variables:
- **BUILD_OUT_OF_TREE** (bool) : true
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source
code of OBS Studio, located at [source_directory]/libobs/.
- **LIBOBS_LIB** (filepath) : location of the libobs.so file (usually CMake finds
this, but if not it'll usually be in /usr/lib/libobs.so)
- **LIBOBS_FRONTEND_API_LIB** (filepath) : location of the libobs-frontend-api.so
file (usually in the same place as LIBOBS_LIB)
- **LIBOBS_FRONTEND_INCLUDE_DIR** (path) : location of the obs-frontend-api
subfolder in the source code of OBS Studio, located at
[source_directory]/UI/obs-frontend-api.
Assuming that you installed Qt via your system package manager, it should be
found automatically. If not, then usually you'll find it in something like:
- **Qt5Core_DIR** (path) : /usr/lib64/cmake/Qt5Core
- **Qt5Gui_DIR** (path): /usr/lib64/cmake/Qt5Gui
- **Qt5Widgets_DIR** (path) : /usr/lib64/cmake/Qt5Widgets
Just keep hitting configure until all the vars are filled out. Then hit generate.
Then open a terminal in the build folder and type:
```
make -j4
sudo make install
```
NOTE: The Linux version of this plugin is dependent on libXScrnSaver, libcurl and libXtst.
### OS X
In cmake-gui, you'll have to set these CMake variables :
- **BUILD_OUT_OF_TREE** (bool) : true
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source
code of OBS Studio, located at [source_directory]/libobs/.
- **LIBOBS_LIB** (filepath) : location of the libobs.0.dylib file (usually
in /Applications/OBS.app/Contents/Resources/bin/libobs.0.dylib)
- **LIBOBS_FRONTEND_API_LIB** (filepath) : location of the libobs-frontend-api.0.dylib
file (usually in usually in /Applications/OBS.app/Contents/Resources/bin/libobs-frontend-api.0.dylib)
- **LIBOBS_FRONTEND_INCLUDE_DIR** (path) : location of the obs-frontend-api subfolder
in the source code of OBS Studio, located at [source_directory]/UI/obs-frontend-api.
Assuming that you installed Qt via the regular Qt App way:
- **Qt5Core_DIR** (path) : Usually /Applications/Qt/5.10.1/clang_64/lib/cmake/Qt5Core
- **Qt5Widgets_DIR** (path) : Usually /Applications/Qt/5.10.1/clang_64/lib/cmake/Qt5Widgets
- **Qt5MacExtras_DIR** (path) : Usually /Applications/Qt/5.10.1/clang_64/lib/cmake/Qt5MacExtras
Just keep hitting configure until all the vars are filled out. Then hit generate.
Open xcode (or a terminal, depending on the build type you chose), build and copy
the advanced-scene-switcher.so file to 'Library/Application Support/obs-studio/plugins/advanced-scene-switcher/bin/'
And the 'data' folder to 'Library/Application Support/obs-studio/plugins/advanced-scene-switcher/'.
Note that you might have to adjust the library search paths using the install_name_tool if you want the plugin to run on machines other than your build machine:
```
install_name_tool -change @rpath/libobs-frontend-api.dylib @executable_path/../Frameworks/libobs-frontend-api.dylib UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /usr/local/opt/qt5/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /usr/local/opt/qt5/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /usr/local/opt/qt5/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
```

View File

@@ -0,0 +1,5 @@
obs-scene-switcher (0.1+testonly) focal; urgency=medium
* Initial release (Closes: #123456)
-- Joao Eriberto Mota Filho <eriberto@debian.org> Fri, 03 Sep 2021 11:39:52 -0300

22
CI/linux/debian/control Normal file
View File

@@ -0,0 +1,22 @@
Source: obs-scene-switcher
Section: video
Priority: optional
Maintainer: Joao Eriberto Mota Filho <eriberto@debian.org>
Build-Depends: cmake,
debhelper-compat (= 12),
libcurl4-openssl-dev,
libobs-dev,
libxtst-dev,
qtbase5-dev,
libxss-dev,
libopencv-dev
Standards-Version: 4.6.0
Homepage: https://obsproject.com/forum/resources/advanced-scene-switcher.395/
Rules-Requires-Root: no
Package: obs-scene-switcher
Architecture: any
Depends: ${misc:Depends}, ${shlibs:Depends}
Description: automated scene switcher for OBS Studio (plugin)
Advanced Scene Switcher is based on the built in scene switcher. It extends
its functionality by adding several features.

60
CI/linux/debian/copyright Normal file
View File

@@ -0,0 +1,60 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: SceneSwitcher
Upstream-Contact: https://github.com/WarmUpTill/SceneSwitcher/issues
Source: https://github.com/WarmUpTill/SceneSwitcher
Files: *
Copyright: 2016-2021 WarmUpTill <WarmUpTill@web.de>
License: GPL-2
Files: cmake/GetGitRevisionDescription.cmake
cmake/GetGitRevisionDescription.cmake.in
Copyright: 2009-2013 Iowa State University
2013-2020 Contributors
2013-2020 Ryan Pavlik
License: BSL-1.0
Files: debian/*
Copyright: 2021 Joao Eriberto Mota Filho <eriberto@debian.org>
License: BSL-1.0
License: GPL-2
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2.
.
This package is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>
.
On Debian systems, the complete text of the GNU General
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
License: BSL-1.0
Boost Software License - Version 1.0 - August 17th, 2003
.
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
.
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

16
CI/linux/debian/rules Normal file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/make -f
#export DH_VERBOSE = 1
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
export QT_SELECT = qt5
%:
dh $@
dh_auto_configure -- -DBUILD_OUT_OF_TREE=1 \
-DLIBOBS_INCLUDE_DIR=/usr/include/obs \
-DLIBOBS_LIB=/usr/lib/${DEB_TARGET_MULTIARCH}/libobs.so \
-DLIBOBS_FRONTEND_INCLUDE_DIR=/usr/include/obs \
-DLIBOBS_FRONTEND_API_LIB=/usr/lib/${DEB_TARGET_MULTIARCH}/libobs-frontend-api.so

View File

@@ -0,0 +1 @@
3.0 (native)

View File

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

View File

@@ -1,4 +1,4 @@
Note that you will have to use OBS version 26.1 or newer!
Note that you will have to use OBS version 27 or newer!
--- Windows ---
Recommended: Run the provided installer. (You might have to click 'More info' and select 'Run anyway' if it is blocked by Windows)
@@ -8,18 +8,25 @@ It is usually located at 'C:\Program Files (x86)\obs-studio\'.
Remember to install the Visual C++ Redistributable for Visual Studio 2019, if you have not done so already. (See plugin overview page)
--- macOS ---
Recommended: Run the provided installer. (You might have to right-click or control-click and select 'open' if it is blocked)
Alternatively extract the *so file and data folder and either ...
... right-click the OBS app inside your Applications folder and choose 'Show Package Contents'.
Copy the advanced-scene-switcher.so file to 'Contents/Plugins' and the 'data' folder to 'Contents/Resources'.
... or copy the advanced-scene-switcher.so file to Library/Application Support/obs-studio/plugins/advanced-scene-switcher/bin/ .
And the 'data' folder to 'Library/Application Support/obs-studio/plugins/advanced-scene-switcher/'.
Run the provided installer. (You might have to right-click or control-click and select 'open' if it is blocked)
--- Linux ---
Copy the advanced-scene-switcher.so file and into the OBS Studio plugin folder.
Note that the plugin has dependencies to:
* libXss
* libopencv-imgproc
* libopencv-objdetect
Optional:
* libXtst
* libcurl
If you are using snap you can install the following package for an OBS installation which comes bundled with the plugin:
sudo snap install obs-studio
The plugin is also available via the Flatpak package manager for users who installed OBS via Flatpak:
flatpak install com.obsproject.Studio.Plugin.SceneSwitcher
If you have installed OBS via other means, it is most likely necessary to install the plugin manually.
To do so copy the advanced-scene-switcher.so file and into the OBS Studio plugin folder.
The location of this folder can vary, so you might have to look around a bit.
Examples are ...
@@ -30,13 +37,39 @@ Examples are ...
~/.local/share/flatpak/app/com.obsproject.Studio/x86_64/stable/active/files/lib/obs-plugins/
/var/lib/flatpak/app/com.obsproject.Studio/x86_64/stable/active/files/lib/obs-plugins/
Unfortunately the expected location of the locale, which can be found in the data folder, can vary also.
The data folder usually should be copied to:
~/.config/obs-studio/plugins/advanced-scene-switcher/
Unfortunately the expected location of the "locale" and "res" folder, which can be found in the data folder, can vary also.
The data folder usually should be copied to "~/.config/obs-studio/plugins/advanced-scene-switcher/" and reflect the following structure:
/home/user/.config/obs-studio/plugins/
└── advanced-scene-switcher
├── bin
│ └── 64bit
│ └── advanced-scene-switcher.so
└── data
├── locale
│ ├── de-DE.ini
│ ├── en-US.ini
│ ├── ru-RU.ini
│ └── zh-CN.ini
└── res
├── cascadeClassifiers
│ ├── haarcascade_eye_tree_eyeglasses.xml
│ ├── haarcascade_eye.xml
│ ├── haarcascade_frontalface_alt2.xml
│ ├── haarcascade_frontalface_alt_tree.xml
│ ├── haarcascade_frontalface_alt.xml
│ ├── haarcascade_frontalface_default.xml
│ ├── haarcascade_fullbody.xml
│ ├── haarcascade_lefteye_2splits.xml
│ ├── haarcascade_lowerbody.xml
│ ├── haarcascade_profileface.xml
│ ├── haarcascade_righteye_2splits.xml
│ └── haarcascade_upperbody.xml
└── time.svg
If this does not work you can try to copy the "locale" folder found inside the data folder to:
/usr/share/obs/obs-plugins/advanced-scene-switcher/locale
~/.local/share/flatpak/app/com.obsproject.Studio/x86_64/stable/active/files/share/obs/obs-plugins/advanced-scene-switcher/locale
/var/lib/flatpak/app/com.obsproject.Studio/x86_64/stable/active/files/share/obs/obs-plugins/advanced-scene-switcher/locale
In doubt please check where other "en-US.ini" files are located on your system.
In doubt, please check where other "en-US.ini" files are located on your system.

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

@@ -1,317 +1,436 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.14)
project(advanced-scene-switcher)
add_definitions(-DASIO_STANDALONE)
# generate version info
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE RELWITHDEBINFO)
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
OR CMAKE_COMPILER_IS_CLANG)
set(CMAKE_CXX_FLAGS
"-Wall -Wextra -Wvla -Wno-unused-function -Wno-missing-field-initializers ${CMAKE_CXX_FLAGS} -fno-strict-aliasing"
)
set(CMAKE_C_FLAGS
"-Wall -Wextra -Wvla -Wno-unused-function -Werror-implicit-function-declaration -Wno-missing-braces -Wno-missing-field-initializers ${CMAKE_C_FLAGS} -std=gnu99 -fno-strict-aliasing"
)
option(USE_LIBC++ "Use libc++ instead of libstdc++" ${APPLE})
if(USE_LIBC++)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
elseif(MSVC)
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
# Disable pointless constant condition warnings
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} /wd4127 /wd4201 /wd4456 /wd4457 /wd4458 /wd4459 /wd4595"
)
add_definitions(-DUNICODE -D_UNICODE -D_CRT_SECURE_NO_WARNINGS
-D_CRT_NONSTDC_NO_WARNINGS)
endif()
# Generate version info
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
include(GetGitRevisionDescription)
get_git_head_revision(GIT_REFSPEC GIT_SHA1)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp" @ONLY)
git_describe(GIT_TAG)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.cpp.in"
"${CMAKE_CURRENT_BINARY_DIR}/src/version.cpp" @ONLY)
# Windows installer
if(WIN32)
get_filename_component(ISS_PLUGIN_FILES_DIR "${CMAKE_BINARY_DIR}\\..\\package" ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_PLUGIN_FILES_DIR}" ISS_PLUGIN_FILES_DIR)
get_filename_component(ISS_MSVC_REDIST_HELPER_DIR "${CMAKE_PACKAGE_PREFIX}\\.." ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_MSVC_REDIST_HELPER_DIR}" ISS_MSVC_REDIST_HELPER_DIR)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/CI/windows/setup.iss.in" "${CMAKE_CURRENT_BINARY_DIR}/CI/windows/setup.iss" @ONLY)
endif()
if(WIN32)
get_filename_component(ISS_PLUGIN_FILES_DIR "${CMAKE_BINARY_DIR}\\..\\package" ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_PLUGIN_FILES_DIR}" ISS_PLUGIN_FILES_DIR)
get_filename_component(ISS_MSVC_REDIST_HELPER_DIR "${CMAKE_PACKAGE_PREFIX}\\.." ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_MSVC_REDIST_HELPER_DIR}" ISS_MSVC_REDIST_HELPER_DIR)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/CI/windows/setup.iss.in" "${CMAKE_CURRENT_BINARY_DIR}/CI/windows/setup.iss" @ONLY)
get_filename_component(ISS_PLUGIN_FILES_DIR
"${CMAKE_BINARY_DIR}\\..\\package" ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_PLUGIN_FILES_DIR}" ISS_PLUGIN_FILES_DIR)
get_filename_component(ISS_MSVC_REDIST_HELPER_DIR "${CMAKE_BINARY_DIR}\\.."
ABSOLUTE)
file(TO_NATIVE_PATH "${ISS_MSVC_REDIST_HELPER_DIR}"
ISS_MSVC_REDIST_HELPER_DIR)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/CI/windows/setup.iss.in"
"${CMAKE_CURRENT_BINARY_DIR}/CI/windows/setup.iss" @ONLY)
endif()
# Out of tree specific settings
if(BUILD_OUT_OF_TREE)
set(CMAKE_PREFIX_PATH "${QTDIR}")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/external")
set(CMAKE_PREFIX_PATH "${QTDIR}")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(LibObs)
find_package(LibObs-frontend-api)
if(LibObs_FOUND)
set(LIBOBS_LIB ${LIBOBS_LIBRARIES})
set(LIBOBS_INCLUDE_DIR ${LIBOBS_INCLUDE_DIRS})
endif()
if(LibObs-frontend-api_FOUND)
set(LIBOBS_FRONTEND_API_LIB ${LIBOBS-FRONTEND-API_LIBRARIES})
set(LIBOBS_FRONTEND_INCLUDE_DIR ${LIBOBS-FRONTEND-API_INCLUDE_DIR})
endif()
include(external/FindLibObs.cmake)
find_package(LibObs REQUIRED)
find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(Libcurl REQUIRED)
find_path(LIBOBS_FRONTEND_INCLUDE_DIR HINTS ${LIBOBS_INCLUDE_DIRS})
find_file(LIBOBS_FRONTEND_API_LIB NAMES libobs-frontend-api.* HINTS ${LIBOBS_LIB} )
if(NOT LIBOBS_LIB)
message(FATAL_ERROR "obs library not found - please set LIBOBS_LIB")
endif()
if(NOT LIBOBS_FRONTEND_API_LIB)
message(
FATAL_ERROR
"libobs frontend-api library not found - please set LIBOBS_FRONTEND_API_LIB"
)
endif()
if(NOT LIBOBS_INCLUDE_DIR)
message(
FATAL_ERROR "obs.hpp header not found - please set LIBOBS_INCLUDE_DIR")
endif()
if(NOT LIBOBS_FRONTEND_INCLUDE_DIR)
message(
FATAL_ERROR
" obs-frontend-api.h not found - please set LIBOBS_FRONTEND_INCLUDE_DIR"
)
endif()
include_directories("${LIBOBS_INCLUDE_DIR}" "${LIBOBS_FRONTEND_INCLUDE_DIR}"
${Qt5Core_INCLUDES} ${Qt5Widgets_INCLUDES})
find_package(CURL REQUIRED)
include_directories("${CURL_INCLUDE_DIRS}")
else()
find_package(Libcurl REQUIRED)
include_directories("${LIBCURL_INCLUDE_DIRS}")
add_definitions(-DVCAM_SUPPORTED)
add_definitions(-DREPLAYBUFFER_SUPPORTED)
endif()
# Platform specific settings
if(APPLE)
find_library(COCOA Cocoa)
if(BUILD_OUT_OF_TREE)
find_package(Qt5MacExtras REQUIRED)
endif()
include_directories(${COCOA})
set(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
find_library(COCOA Cocoa)
if(BUILD_OUT_OF_TREE)
find_package(Qt5MacExtras REQUIRED)
endif()
include_directories(${COCOA})
endif()
if(UNIX AND NOT APPLE)
find_package(X11 REQUIRED)
link_libraries(${X11_LIBRARIES})
include_directories(${X11_INCLUDE_DIR})
find_package(X11 REQUIRED COMPONENTS Xtst Xss)
find_path(PROCPS_INCLUDE_DIR NAMES proc/procps.h)
if(NOT PROCPS_INCLUDE_DIR)
message(
FATAL_ERROR "procps include dir not found - please set PROCPS_INCLUDE_DIR"
)
endif()
find_library(PROCPS_LIBRARY NAMES procps)
if(NOT PROCPS_LIBRARY)
message(FATAL_ERROR "procps lib not found - please set PROCPS_LIBRARY")
endif()
link_libraries(${X11_LIBRARIES} ${procps_LIBRARIES})
include_directories("${X11_INCLUDE_DIR}" "${X11_Xtst_INCLUDE_PATH}"
"${X11_Xss_INCLUDE_PATH}" "${PROCPS_INCLUDE_DIR}")
endif()
include_directories(
"${CMAKE_CURRENT_SOURCE_DIR}/deps/asio/asio/include"
"${CMAKE_CURRENT_SOURCE_DIR}/deps/websocketpp"
)
set(advanced-scene-switcher_HEADERS
${advanced-scene-switcher_HEADERS}
src/headers/advanced-scene-switcher.hpp
src/headers/switcher-data-structs.hpp
src/headers/scene-group.hpp
src/headers/scene-trigger.hpp
src/headers/switch-audio.hpp
src/headers/switch-executable.hpp
src/headers/switch-file.hpp
src/headers/switch-idle.hpp
src/headers/switch-media.hpp
src/headers/switch-network.hpp
src/headers/switch-pause.hpp
src/headers/switch-random.hpp
src/headers/switch-screen-region.hpp
src/headers/switch-time.hpp
src/headers/switch-transitions.hpp
src/headers/switch-window.hpp
src/headers/switch-sequence.hpp
src/headers/switch-video.hpp
src/headers/switch-generic.hpp
src/headers/macro-action-edit.hpp
src/headers/macro-action-audio.hpp
src/headers/macro-action-file.hpp
src/headers/macro-action-filter.hpp
src/headers/macro-action-hotkey.hpp
src/headers/macro-action-macro.hpp
src/headers/macro-action-media.hpp
src/headers/macro-action-plugin-state.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-order.hpp
src/headers/macro-action-scene-switch.hpp
src/headers/macro-action-scene-transform.hpp
src/headers/macro-action-scene-visibility.hpp
src/headers/macro-action-source.hpp
src/headers/macro-action-streaming.hpp
src/headers/macro-action-virtual-cam.hpp
src/headers/macro-action-wait.hpp
src/headers/macro-condition-edit.hpp
src/headers/macro-condition-audio.hpp
src/headers/macro-condition-date.hpp
src/headers/macro-condition-macro.hpp
src/headers/macro-condition-file.hpp
src/headers/macro-condition-filter.hpp
src/headers/macro-condition-hotkey.hpp
src/headers/macro-condition-idle.hpp
src/headers/macro-condition-media.hpp
src/headers/macro-condition-plugin-state.hpp
src/headers/macro-condition-process.hpp
src/headers/macro-condition-recording.hpp
src/headers/macro-condition-region.hpp
src/headers/macro-condition-replay-buffer.hpp
src/headers/macro-condition-scene-order.hpp
src/headers/macro-condition-scene.hpp
src/headers/macro-condition-source.hpp
src/headers/macro-condition-streaming.hpp
src/headers/macro-condition-timer.hpp
src/headers/macro-condition-video.hpp
src/headers/macro-condition-virtual-cam.hpp
src/headers/macro-condition-window.hpp
src/headers/macro.hpp
src/headers/macro-selection.hpp
src/headers/curl-helper.hpp
src/headers/hotkey.hpp
src/headers/scene-selection.hpp
src/headers/screenshot-helper.hpp
src/headers/name-dialog.hpp
src/headers/duration-control.hpp
src/headers/section.hpp
src/headers/platform-funcs.hpp
src/headers/utility.hpp
src/headers/volume-control.hpp
src/headers/version.h
)
set(advanced-scene-switcher_SOURCES
${advanced-scene-switcher_SOURCES}
src/advanced-scene-switcher.cpp
src/advanced-scene-switcher-module.c
src/switcher-data-structs.cpp
src/scene-group.cpp
src/scene-trigger.cpp
src/switch-transitions.cpp
src/switch-screen-region.cpp
src/switch-priority.cpp
src/switch-executable.cpp
src/switch-idle.cpp
src/switch-sequence.cpp
src/switch-file.cpp
src/switch-window.cpp
src/switch-media.cpp
src/switch-network.cpp
src/hotkey.cpp
src/general.cpp
src/switch-pause.cpp
src/switch-random.cpp
src/switch-time.cpp
src/switch-audio.cpp
src/switch-video.cpp
src/switch-generic.cpp
src/macro-action-edit.cpp
src/macro-action-audio.cpp
src/macro-action-file.cpp
src/macro-action-filter.cpp
src/macro-action-hotkey.cpp
src/macro-action-macro.cpp
src/macro-action-media.cpp
src/macro-action-plugin-state.cpp
src/macro-action-recording.cpp
src/macro-action-replay-buffer.cpp
src/macro-action-run.cpp
src/macro-action-scene-order.cpp
src/macro-action-scene-switch.cpp
src/macro-action-scene-transform.cpp
src/macro-action-scene-visibility.cpp
src/macro-action-source.cpp
src/macro-action-streaming.cpp
src/macro-action-virtual-cam.cpp
src/macro-action-wait.cpp
src/macro-condition-edit.cpp
src/macro-condition-audio.cpp
src/macro-condition-date.cpp
src/macro-condition-macro.cpp
src/macro-condition-file.cpp
src/macro-condition-filter.cpp
src/macro-condition-hotkey.cpp
src/macro-condition-idle.cpp
src/macro-condition-media.cpp
src/macro-condition-plugin-state.cpp
src/macro-condition-process.cpp
src/macro-condition-recording.cpp
src/macro-condition-region.cpp
src/macro-condition-replay-buffer.cpp
src/macro-condition-scene-order.cpp
src/macro-condition-scene.cpp
src/macro-condition-source.cpp
src/macro-condition-streaming.cpp
src/macro-condition-timer.cpp
src/macro-condition-video.cpp
src/macro-condition-virtual-cam.cpp
src/macro-condition-window.cpp
src/macro.cpp
src/macro-selection.cpp
src/macro-tab.cpp
src/curl-helper.cpp
src/scene-selection.cpp
src/screenshot-helper.cpp
src/name-dialog.cpp
src/duration-control.cpp
src/section.cpp
src/utility.cpp
src/volume-control.cpp
src/version.cpp
)
set(advanced-scene-switcher_UI
${advanced-scene-switcher_UI}
forms/advanced-scene-switcher.ui
)
if(WIN32)
add_definitions(-D_WEBSOCKETPP_CPP11_STL_)
set(advanced-scene-switcher_PLATFORM_SOURCES
src/win/advanced-scene-switcher-win.cpp)
set(advanced-scene-switcher_PLATFORM_SOURCES
src/win/advanced-scene-switcher-win.cpp)
elseif(APPLE)
set(advanced-scene-switcher_PLATFORM_SOURCES
src/osx/advanced-scene-switcher-osx.mm)
set_source_files_properties(advanced-scene-switcher-osx.mm
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
set(advanced-scene-switcher_PLATFORM_LIBS
${COCOA})
set(advanced-scene-switcher_PLATFORM_SOURCES
src/osx/advanced-scene-switcher-osx.mm)
set_source_files_properties(advanced-scene-switcher-osx.mm
PROPERTIES COMPILE_FLAGS "-fobjc-arc")
set(advanced-scene-switcher_PLATFORM_LIBS ${COCOA})
else()
set(advanced-scene-switcher_PLATFORM_SOURCES
src/linux/advanced-scene-switcher-nix.cpp)
set(advanced-scene-switcher_PLATFORM_LIBS
Xss)
set(advanced-scene-switcher_PLATFORM_SOURCES
src/linux/advanced-scene-switcher-nix.cpp)
set(advanced-scene-switcher_PLATFORM_LIBS Xss ${PROCPS_LIBRARY})
endif()
qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS
${advanced-scene-switcher_UI}
${advanced-scene-switcher_PLATFORM_UI})
# asio and websocketpp
add_definitions(-DASIO_STANDALONE)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/deps/asio/asio/include"
"${CMAKE_CURRENT_SOURCE_DIR}/deps/websocketpp")
if(WIN32)
add_definitions(-D_WEBSOCKETPP_CPP11_STL_)
endif()
add_library(advanced-scene-switcher MODULE
${advanced-scene-switcher_HEADERS}
${advanced-scene-switcher_SOURCES}
${advanced-scene-switcher_UI_HEADERS}
${advanced-scene-switcher_PLATFORM_SOURCES}
${advanced-scene-switcher_PLATFORM_HEADERS}
)
# Setup QT tools
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/forms")
set(advanced-scene-switcher_UI ${advanced-scene-switcher_UI}
forms/advanced-scene-switcher.ui)
qt5_wrap_ui(advanced-scene-switcher_UI_HEADERS ${advanced-scene-switcher_UI}
${advanced-scene-switcher_PLATFORM_UI})
# The plugin sources
set(advanced-scene-switcher_HEADERS
${advanced-scene-switcher_HEADERS}
src/headers/advanced-scene-switcher.hpp
src/headers/switcher-data-structs.hpp
src/headers/scene-group.hpp
src/headers/scene-trigger.hpp
src/headers/switch-audio.hpp
src/headers/switch-executable.hpp
src/headers/switch-file.hpp
src/headers/switch-idle.hpp
src/headers/switch-media.hpp
src/headers/switch-network.hpp
src/headers/switch-pause.hpp
src/headers/switch-random.hpp
src/headers/switch-screen-region.hpp
src/headers/switch-time.hpp
src/headers/switch-transitions.hpp
src/headers/switch-window.hpp
src/headers/switch-sequence.hpp
src/headers/switch-video.hpp
src/headers/switch-generic.hpp
src/headers/macro-action-edit.hpp
src/headers/macro-action-audio.hpp
src/headers/macro-action-file.hpp
src/headers/macro-action-filter.hpp
src/headers/macro-action-hotkey.hpp
src/headers/macro-action-macro.hpp
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
src/headers/macro-action-scene-transform.hpp
src/headers/macro-action-scene-visibility.hpp
src/headers/macro-action-screenshot.hpp
src/headers/macro-action-sequence.hpp
src/headers/macro-action-source.hpp
src/headers/macro-action-streaming.hpp
src/headers/macro-action-systray.hpp
src/headers/macro-action-timer.hpp
src/headers/macro-action-transition.hpp
src/headers/macro-action-virtual-cam.hpp
src/headers/macro-action-wait.hpp
src/headers/macro-condition-edit.hpp
src/headers/macro-condition-audio.hpp
src/headers/macro-condition-cursor.hpp
src/headers/macro-condition-date.hpp
src/headers/macro-condition-file.hpp
src/headers/macro-condition-filter.hpp
src/headers/macro-condition-hotkey.hpp
src/headers/macro-condition-idle.hpp
src/headers/macro-condition-macro.hpp
src/headers/macro-condition-media.hpp
src/headers/macro-condition-plugin-state.hpp
src/headers/macro-condition-process.hpp
src/headers/macro-condition-recording.hpp
src/headers/macro-condition-replay-buffer.hpp
src/headers/macro-condition-scene-order.hpp
src/headers/macro-condition-scene-transform.hpp
src/headers/macro-condition-scene-visibility.hpp
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-virtual-cam.hpp
src/headers/macro-condition-window.hpp
src/headers/macro.hpp
src/headers/macro-controls.hpp
src/headers/macro-segment.hpp
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
src/headers/name-dialog.hpp
src/headers/duration-control.hpp
src/headers/file-selection.hpp
src/headers/section.hpp
src/headers/status-control.hpp
src/headers/platform-funcs.hpp
src/headers/utility.hpp
src/headers/volume-control.hpp
src/headers/version.h)
set(advanced-scene-switcher_SOURCES
${advanced-scene-switcher_SOURCES}
src/advanced-scene-switcher.cpp
src/advanced-scene-switcher-module.c
src/switcher-data-structs.cpp
src/scene-group.cpp
src/scene-trigger.cpp
src/switch-transitions.cpp
src/switch-screen-region.cpp
src/switch-priority.cpp
src/switch-executable.cpp
src/switch-idle.cpp
src/switch-sequence.cpp
src/switch-file.cpp
src/switch-window.cpp
src/switch-media.cpp
src/switch-network.cpp
src/file-selection.cpp
src/hotkey.cpp
src/general.cpp
src/switch-pause.cpp
src/switch-random.cpp
src/switch-time.cpp
src/switch-audio.cpp
src/switch-video.cpp
src/switch-generic.cpp
src/macro-action-edit.cpp
src/macro-action-audio.cpp
src/macro-action-file.cpp
src/macro-action-filter.cpp
src/macro-action-hotkey.cpp
src/macro-action-macro.cpp
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
src/macro-action-scene-transform.cpp
src/macro-action-scene-visibility.cpp
src/macro-action-screenshot.cpp
src/macro-action-sequence.cpp
src/macro-action-source.cpp
src/macro-action-streaming.cpp
src/macro-action-systray.cpp
src/macro-action-timer.cpp
src/macro-action-transition.cpp
src/macro-action-virtual-cam.cpp
src/macro-action-wait.cpp
src/macro-condition-edit.cpp
src/macro-condition-audio.cpp
src/macro-condition-cursor.cpp
src/macro-condition-date.cpp
src/macro-condition-file.cpp
src/macro-condition-filter.cpp
src/macro-condition-hotkey.cpp
src/macro-condition-idle.cpp
src/macro-condition-macro.cpp
src/macro-condition-media.cpp
src/macro-condition-plugin-state.cpp
src/macro-condition-process.cpp
src/macro-condition-recording.cpp
src/macro-condition-replay-buffer.cpp
src/macro-condition-scene-order.cpp
src/macro-condition-scene-transform.cpp
src/macro-condition-scene-visibility.cpp
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-virtual-cam.cpp
src/macro-condition-window.cpp
src/macro.cpp
src/macro-controls.cpp
src/macro-segment.cpp
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-control.cpp
src/section.cpp
src/utility.cpp
src/volume-control.cpp
src/version.cpp)
# Backwards compatability checks with older OBS versions
if(DEFINED LibObs_VERSION_MAJOR)
if(LibObs_VERSION_MAJOR GREATER_EQUAL 27)
add_definitions(-DVCAM_SUPPORTED)
else()
message(
WARNING
"OBS version ${LibObs_VERSION_MAJOR} found - disabling virtual camera functionality"
)
endif()
if(LibObs_VERSION_MAJOR GREATER_EQUAL 26)
add_definitions(-DREPLAYBUFFER_SUPPORTED)
else()
message(
WARNING
"OBS version ${LibObs_VERSION_MAJOR} found - disabling replay buffer and screenshot functionality"
)
list(REMOVE_ITEM advanced-scene-switcher_SOURCES
src/macro-action-screenshot.cpp)
list(REMOVE_ITEM advanced-scene-switcher_HEADERS
src/headers/macro-action-screenshot.hpp)
endif()
endif()
add_library(
advanced-scene-switcher SHARED
${advanced-scene-switcher_HEADERS}
${advanced-scene-switcher_SOURCES}
${advanced-scene-switcher_UI_HEADERS}
${advanced-scene-switcher_PLATFORM_SOURCES}
${advanced-scene-switcher_PLATFORM_HEADERS})
# Out of tree build
if(BUILD_OUT_OF_TREE)
include_directories(
"${LIBOBS_INCLUDE_DIRS}"
"${LIBOBS_FRONTEND_INCLUDE_DIR}"
${Qt5Core_INCLUDES}
${Qt5Widgets_INCLUDES}
${LIBCURL_INCLUDE_DIRS})
target_link_libraries(
advanced-scene-switcher ${advanced-scene-switcher_PLATFORM_LIBS}
${LIBOBS_LIB} ${LIBOBS_FRONTEND_API_LIB} Qt5::Core Qt5::Widgets)
target_link_libraries(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.
file(GLOB ASS_TRANSLATION_FILES "data/locale/*.ini")
# 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.
file(GLOB ASS_TRANSLATION_FILES
"data/locale/*.ini"
)
# OSX
if(APPLE)
set_target_properties(advanced-scene-switcher PROPERTIES PREFIX "")
endif()
# Windows
if(WIN32)
string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
message("${CMAKE_CXX_FLAGS_RELEASE}")
find_package(w32-pthreads REQUIRED)
target_link_libraries(advanced-scene-switcher
w32-pthreads)
endif()
# OSX
if(APPLE)
set_target_properties(advanced-scene-switcher PROPERTIES PREFIX "")
endif()
# Linux
if(UNIX AND NOT APPLE)
set(CMAKE_C_FLAGS "-Wall -Wextra -Wvla -Wno-unused-function -Werror-implicit-function-declaration -Wno-missing-braces -Wno-missing-field-initializers ${CMAKE_C_FLAGS} -std=c99 -fno-strict-aliasing")
if(ARCH EQUAL 64)
set(ARCH_NAME "x86_64")
else()
set(ARCH_NAME "i686")
endif()
set_target_properties(advanced-scene-switcher PROPERTIES PREFIX "")
install(TARGETS advanced-scene-switcher
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/obs-plugins)
install(FILES ${ASS_TRANSLATION_FILES}
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/obs/obs-plugins/advanced-scene-switcher/locale")
endif()
# Linux
if(UNIX AND NOT APPLE)
if(NOT LIB_OUT_DIR)
set(LIB_OUT_DIR "/lib/obs-plugins")
endif()
if(NOT DATA_OUT_DIR)
set(DATA_OUT_DIR "/share/obs/obs-plugins/advanced-scene-switcher")
endif()
set_target_properties(advanced-scene-switcher PROPERTIES PREFIX "")
install(TARGETS advanced-scene-switcher
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${LIB_OUT_DIR})
install(DIRECTORY data/locale
DESTINATION ${CMAKE_INSTALL_PREFIX}/${DATA_OUT_DIR})
install(DIRECTORY data/res
DESTINATION ${CMAKE_INSTALL_PREFIX}/${DATA_OUT_DIR})
endif()
else()
target_link_libraries(advanced-scene-switcher
${advanced-scene-switcher_PLATFORM_LIBS}
obs-frontend-api
Qt5::Widgets
libobs)
install_obs_plugin_with_data(advanced-scene-switcher data)
# In tree build
target_link_libraries(
advanced-scene-switcher ${advanced-scene-switcher_PLATFORM_LIBS}
obs-frontend-api Qt5::Widgets libobs)
install_obs_plugin_with_data(advanced-scene-switcher data)
endif()
add_subdirectory(src/external-macro-modules)

132
README.md
View File

@@ -1,119 +1,31 @@
# SceneSwitcher
An automated scene switcher for OBS Studio
An automated scene switcher for OBS Studio.
More information can be found on https://obsproject.com/forum/resources/automatic-scene-switching.395/ and see https://github.com/WarmUpTill/SceneSwitcher/blob/master/CI/release/README.txt for installing releases.
More information can be found on https://obsproject.com/forum/resources/automatic-scene-switching.395/.
## Compiling in tree (recommended)
Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/UI/frontend-plugins/:
## Downloads
Binaries for Windows, MacOS, and Linux are available in the [Releases](https://github.com/WarmUpTill/SceneSwitcher/releases) section.
## Installing the plugin
For the Windows and MacOS platforms, it is recommended to run the provided installers.
For Linux the Snap package manager offers an OBS Studio installation which is bundled with the plugin:
```
cd obs-studio/UI/frontend-plugins/
git clone https://github.com/WarmUpTill/SceneSwitcher.git
sudo snap install obs-studio
```
The plugin is also available via the Flatpak package manager for users who installed OBS via Flatpak:
```
flatpak install com.obsproject.Studio.Plugin.SceneSwitcher
```
Then modify the obs-studio/UI/frontend-plugins/CMakeLists.txt file and add an entry for the scene switcher:
add_subdirectory(SceneSwitcher)
If that is not an option you will have to ...
1. Copy the library to the plugins folder of you obs installation.
2. Copy the contents of the data directory to its respective folders of your obs installation.
## Compiling out of tree
### Prerequisites
You'll need CMake and a working development environment for OBS Studio installed
on your computer. Once you've done that, do the following:
```
git clone https://github.com/WarmUpTill/SceneSwitcher.git
cd SceneSwitcher
mkdir build && cd build
```
Unfortunately the exact location of these folders may vary from system to system.
### Windows
In cmake-gui, you'll have to set these CMake variables :
- **BUILD_OUT_OF_TREE** (bool) : true
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source
code of OBS Studio, located at [source_directory]/libobs/.
- **LIBOBS_LIB** (filepath) : location of the obs.dll file (usually set to
C:\Program Files\obs-studio\bin\64bit\obs.dll)
## Compiling the plugin
Assuming that you installed Qt via the regular Qt App way:
- **Qt5Core_DIR** (path) : C:/Qt/5.10.1/msvc2017_64/lib/cmake/Qt5Core
- **Qt5Gui_DIR** (path): C:/Qt/5.10.1/msvc2017_64/lib/cmake/Qt5Gui
- **Qt5Widgets_DIR** (path) : C:/Qt/5.10.1/msvc2017_64/lib/cmake/Qt5Widgets
- **LIBOBS_FRONTEND_API_LIB** (filepath) : location of the libobs-frontend-api.dll
file, usually C:/Program Files/obs-studio/bin/64bit/obs-frontend-api.dll
(usually in the same place as LIBOBS_LIB)
- **LIBOBS_FRONTEND_INCLUDE_DIR** (path) : location of the obs-frontend-api
subfolder in the source code of OBS Studio, located at [source_directory]/UI/obs-frontend-api.
Just keep hitting configure until all the vars are filled out. Then hit generate.
### Linux
Most versions of Linux you can use cmake-gui or the command line.
**For the command line:**
```
cmake -DBUILD_OUT_OF_TREE=1 -DLIBOBS_INCLUDE_DIR="<path to the libobs/ sub-folder in obs-studio's source code>" \
-DLIBOBS_FRONTEND_INCLUDE_DIR="<path to the UI/obs-frontend-api/ sub-folder in obs-studio's source code>" \
-DLIBOBS_LIB="<path to the libobs.so file>" \
-DLIBOBS_FRONTEND_API_LIB="<path to the libobs-frontend-api.so file (usually in the same place as LIBOBS_LIB)>" \
-DCMAKE_INSTALL_PREFIX=/usr ..
make -j4
sudo make install
```
For cmake-gui you'll have to set the following variables:
- **BUILD_OUT_OF_TREE** (bool) : true
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source
code of OBS Studio, located at [source_directory]/libobs/.
- **LIBOBS_LIB** (filepath) : location of the libobs.so file (usually CMake finds
this, but if not it'll usually be in /usr/lib/libobs.so)
Assuming that you installed Qt via your system package manager, it should be
found automatically. If not, then usually you'll find it in something like:
- **Qt5Core_DIR** (path) : /usr/lib64/cmake/Qt5Core
- **Qt5Gui_DIR** (path): /usr/lib64/cmake/Qt5Gui
- **Qt5Widgets_DIR** (path) : /usr/lib64/cmake/Qt5Widgets
- **LIBOBS_FRONTEND_API_LIB** (filepath) : location of the libobs-frontend-api.so
file (usually in the same place as LIBOBS_LIB)
- **LIBOBS_FRONTEND_INCLUDE_DIR** (path) : location of the obs-frontend-api
subfolder in the source code of OBS Studio, located at
[source_directory]/UI/obs-frontend-api.
Just keep hitting configure until all the vars are filled out. Then hit generate.
Then open a terminal in the build folder and type:
```
make -j4
sudo make install
```
NOTE: The Linux version of this plugin is dependent on libXScrnSaver.
### OS X
In cmake-gui, you'll have to set these CMake variables :
- **BUILD_OUT_OF_TREE** (bool) : true
- **LIBOBS_INCLUDE_DIR** (path) : location of the libobs subfolder in the source
code of OBS Studio, located at [source_directory]/libobs/.
- **LIBOBS_LIB** (filepath) : location of the libobs.0.dylib file (usually
in /Applications/OBS.app/Contents/Resources/bin/libobs.0.dylib)
Assuming that you installed Qt via the regular Qt App way:
- **Qt5Core_DIR** (path) : Usually /Applications/Qt/5.10.1/clang_64/lib/cmake/Qt5Core
- **Qt5Widgets_DIR** (path) : Usually /Applications/Qt/5.10.1/clang_64/lib/cmake/Qt5Widgets
- **Qt5MacExtras_DIR** (path) : Usually /Applications/Qt/5.10.1/clang_64/lib/cmake/Qt5MacExtras
- **LIBOBS_FRONTEND_API_LIB** (filepath) : location of the libobs-frontend-api.0.dylib
file (usually in usually in /Applications/OBS.app/Contents/Resources/bin/libobs-frontend-api.0.dylib)
- **LIBOBS_FRONTEND_INCLUDE_DIR** (path) : location of the obs-frontend-api subfolder
in the source code of OBS Studio, located at [source_directory]/UI/obs-frontend-api.
Just keep hitting configure until all the vars are filled out. Then hit generate.
Open xcode (or a terminal, depending on the build type you chose), build and copy
the advanced-scene-switcher.so file to /Applications/OBS.app/Contents/PlugIns
Note that you might have to adjust the library search paths using the install_name_tool if you want the plugin to run on machines other than your build machine:
```
install_name_tool -change @rpath/libobs-frontend-api.dylib @executable_path/../Frameworks/libobs-frontend-api.dylib UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change @rpath/libobs.0.dylib @executable_path/../Frameworks/libobs.0.dylib UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /usr/local/opt/qt5/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /usr/local/opt/qt5/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
install_name_tool -change /usr/local/opt/qt5/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore UI/frontend-plugins/SceneSwitcher/advanced-scene-switcher.so
```
See the [build instructions](BUILDING.md).

View File

@@ -1,3 +1,5 @@
#include "src/headers/version.h"
#define GIT_SHA1 "@GIT_SHA1@"
const char g_GIT_SHA1[] = GIT_SHA1;
#define GIT_TAG "@GIT_TAG@"
const char g_GIT_SHA1[] = GIT_SHA1;
const char g_GIT_TAG[] = GIT_TAG;

View File

@@ -45,7 +45,7 @@ AdvSceneSwitcher.generalTab.priority.fileContent="Datei Inhalt"
AdvSceneSwitcher.generalTab.priority.sceneSequence="Szenenfolge"
AdvSceneSwitcher.generalTab.priority.idleDetection="Inaktivitätserkennung"
AdvSceneSwitcher.generalTab.priority.executable="Prozess"
AdvSceneSwitcher.generalTab.priority.screenRegion="Bildschrimbereich"
AdvSceneSwitcher.generalTab.priority.screenRegion="Bildschirmbereich"
AdvSceneSwitcher.generalTab.priority.windowTitle="Fenstername"
AdvSceneSwitcher.generalTab.priority.media="Medien"
AdvSceneSwitcher.generalTab.priority.time="Zeit"
@@ -98,7 +98,7 @@ AdvSceneSwitcher.executableTab.entry="Wenn {{processes}} läuft wechsle zu {{sce
AdvSceneSwitcher.executableTab.help="Dieser Tab erlaubt es Szenen zu wechseln, wenn bestimmte Prozesse laufen.\nDas kann nützlich sein, wenn sich der Name eines Fensters ändern kann oder dieser nicht bekannt ist.\n\nKlicke auf das markierte Plus Symbol, um einen neuen Eintrag hinzuzufügen."
; Screen Region Tab
AdvSceneSwitcher.screenRegionTab.title="Bildschrimbereich"
AdvSceneSwitcher.screenRegionTab.title="Bildschirmbereich"
AdvSceneSwitcher.screenRegionTab.currentPosition="Mauszeiger ist bei:"
AdvSceneSwitcher.screenRegionTab.showGuideFrames="Hilfsrahmen einblenden"
AdvSceneSwitcher.screenRegionTab.hideGuideFrames="Hilfsrahmen ausblenden"

View File

@@ -19,15 +19,16 @@ AdvSceneSwitcher.generalTab.status.autoStart.streaming="Streaming"
AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming="Recording or Streaming"
AdvSceneSwitcher.generalTab.status.checkInterval="Check switch conditions every"
AdvSceneSwitcher.generalTab.generalBehavior="General behavior"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="If no switch condition is met for"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="If no actions are performed for"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="Will only ever be as accurate as the configured check interval."
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="Don't switch"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="Switch to any scene in Random tab"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="Switch to:"
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="After a match do not switch scenes for"
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="After a match don't perform actions for"
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="During this time potential matches will be ignored!"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Enable verbose logging"
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Save window position and size"
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Show system tray notifications"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="Disable UI hints"
AdvSceneSwitcher.generalTab.priority="Priority"
AdvSceneSwitcher.generalTab.priority.description="Switching methods priority (Highest priority is at the top)"
@@ -56,6 +57,7 @@ AdvSceneSwitcher.generalTab.priority.macro="Macro"
; Macro Tab
AdvSceneSwitcher.macroTab.title="Macro"
AdvSceneSwitcher.macroTab.macros="Macros"
AdvSceneSwitcher.macroTab.priorityWarning="Note: It is recommended to configure macros to be the highest priority functionality.\nThis setting can be changed on the General tab."
AdvSceneSwitcher.macroTab.help="Macros allow you to execute a string of actions depending on multiple conditions.\n\nClick on the highlighted plus symbol to add a new Macro."
AdvSceneSwitcher.macroTab.editConditionHelp="This section allows you to define Macro conditions.\n\nSelect an existing or add a new Macro on the left.\nThen click the plus button below to add a new condition."
AdvSceneSwitcher.macroTab.editActionHelp="This section allows you to define Macro actions.\n\nSelect an existing or add a new Macro on the left.\nThen click the plus button below to add a new action."
@@ -65,9 +67,15 @@ AdvSceneSwitcher.macroTab.edit.condition="Condition type:"
AdvSceneSwitcher.macroTab.edit.action="Action type:"
AdvSceneSwitcher.macroTab.add="Add new macro"
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"
AdvSceneSwitcher.macroTab.expandAll="Expand all"
AdvSceneSwitcher.macroTab.collapseAll="Collapse all"
; Macro Logic
AdvSceneSwitcher.logic.none="Ignore entry"
@@ -80,37 +88,76 @@ 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.entry="Volume of {{audioSources}} is {{condition}} {{volume}}"
AdvSceneSwitcher.condition.region="Screen region"
AdvSceneSwitcher.condition.region.entry="Cursor is in {{minX}} {{minY}} x {{maxX}} {{maxY}}"
AdvSceneSwitcher.condition.audio.state.below="below"
AdvSceneSwitcher.condition.audio.state.exact="exactly"
AdvSceneSwitcher.condition.audio.state.above="above"
AdvSceneSwitcher.condition.audio.state.mute="muted"
AdvSceneSwitcher.condition.audio.state.unmute="unmuted"
AdvSceneSwitcher.condition.audio.type.output="Output volume"
AdvSceneSwitcher.condition.audio.type.volume="Configured volume level"
AdvSceneSwitcher.condition.audio.entry="{{checkType}} of {{audioSources}} is {{condition}} {{volume}}"
AdvSceneSwitcher.condition.cursor="Cursor"
AdvSceneSwitcher.condition.cursor.type.region="is in region"
AdvSceneSwitcher.condition.cursor.type.moving="is moving"
AdvSceneSwitcher.condition.cursor.showFrame="Show frame"
AdvSceneSwitcher.condition.cursor.hideFrame="Hide frame"
AdvSceneSwitcher.condition.cursor.entry.line1="Cursor is {{conditions}} {{minX}} {{minY}} {{maxX}} {{maxY}} - {{toggleFrameButton}}"
AdvSceneSwitcher.condition.cursor.entry.line2="Cursor is currently at {{xPos}} x {{yPos}}"
AdvSceneSwitcher.condition.scene="Scene"
AdvSceneSwitcher.condition.scene.type.current="Current"
AdvSceneSwitcher.condition.scene.type.previous="Previous"
AdvSceneSwitcher.condition.scene.entry="{{sceneType}} scene is {{scenes}}"
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.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"
AdvSceneSwitcher.condition.file="File"
AdvSceneSwitcher.condition.file.entry.line1="Content of {{fileType}} {{filePath}} {{browseButton}} matches:"
AdvSceneSwitcher.condition.file.entry.line1="Content of {{fileType}} {{filePath}} matches:"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
AdvSceneSwitcher.condition.media="Media"
AdvSceneSwitcher.condition.media.entry="{{mediaSources}} state is {{states}} and {{timeRestrictions}} {{time}}"
AdvSceneSwitcher.condition.media.anyOnScene="Any media source on"
AdvSceneSwitcher.condition.media.allOnScene="All media sources on"
AdvSceneSwitcher.condition.media.matchOnChange="Only match on change (Note: This option will be removed in a future version - please use time constraints instead)"
AdvSceneSwitcher.condition.media.entry="{{mediaSources}}{{scenes}} state is {{states}} and {{timeRestrictions}} {{time}}"
AdvSceneSwitcher.condition.video="Video"
AdvSceneSwitcher.condition.video.condition.match="exactly matches"
AdvSceneSwitcher.condition.video.condition.differ="does not match"
AdvSceneSwitcher.condition.video.condition.hasChanged="has changed"
AdvSceneSwitcher.condition.video.condition.hasNotChanged="has not changed"
AdvSceneSwitcher.condition.video.condition.noImage="has no output"
AdvSceneSwitcher.condition.video.condition.pattern="matches pattern"
AdvSceneSwitcher.condition.video.condition.object="contains object"
AdvSceneSwitcher.condition.video.askFileAction="Do you want to use an existing file or create a screenshot of the currently selected source?"
AdvSceneSwitcher.condition.video.askFileAction.file="Use existing file"
AdvSceneSwitcher.condition.video.askFileAction.screenshot="Create screenshot"
AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{filePath}} {{browseButton}}"
AdvSceneSwitcher.condition.video.usePatternForChangedCheck="Use pattern matching"
AdvSceneSwitcher.condition.video.usePatternForChangedCheck.tooltip="This will allow you to control how much the image has to change for the condition to be true."
AdvSceneSwitcher.condition.video.patternThreshold="Threshold: "
AdvSceneSwitcher.condition.video.patternThresholdDescription="A higher threshold value means that the pattern needs to match the video source more closely."
AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask="Use alpha channel as mask for pattern."
AdvSceneSwitcher.condition.video.objectScaleThreshold="Scale factor: "
AdvSceneSwitcher.condition.video.objectScaleThresholdDescription="A lower scale factor will lead to more matches but higher CPU load."
AdvSceneSwitcher.condition.video.minNeighborDescription="A higher minimum neighbors value will result in fewer but higher quality matches."
AdvSceneSwitcher.condition.video.showMatch="Show match"
AdvSceneSwitcher.condition.video.screenshotFail="Failed to get screenshot of source!"
AdvSceneSwitcher.condition.video.patternMatchFail="Pattern was not found!"
AdvSceneSwitcher.condition.video.objectMatchFail="Object was not found!"
AdvSceneSwitcher.condition.video.modelLoadFail="Model data could not be loaded!"
AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="Model data (haar cascade classifier): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="Minimum neighbors: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.minSize="Minimum size: {{minSizeX}} x {{minSizeY}}"
AdvSceneSwitcher.condition.video.entry.maxSize="Maximum size: {{maxSizeX}} x {{maxSizeY}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}Reduce CPU load by performing check only every {{throttleCount}} milliseconds"
AdvSceneSwitcher.condition.stream="Streaming"
AdvSceneSwitcher.condition.stream.state.start="Stream running"
AdvSceneSwitcher.condition.stream.state.stop="Stream stopped"
AdvSceneSwitcher.condition.stream.state.starting="Stream starting"
AdvSceneSwitcher.condition.stream.state.stopping="Stream stopping"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.record="Recording"
AdvSceneSwitcher.condition.record.state.start="Recording running"
@@ -123,11 +170,17 @@ AdvSceneSwitcher.condition.idle="Idle"
AdvSceneSwitcher.condition.idle.entry="No keyboard or mouse inputs for {{duration}}"
AdvSceneSwitcher.condition.pluginState="Plugin state"
AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="Automated scene change was triggered in this interval"
AdvSceneSwitcher.condition.pluginState.state.running="Advanced scene switcher is running"
AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
AdvSceneSwitcher.condition.timer="Timer"
AdvSceneSwitcher.condition.timer.entry.line1="{{duration}} have passed"
AdvSceneSwitcher.condition.timer.type.fixed="Fixed"
AdvSceneSwitcher.condition.timer.type.random="Random"
AdvSceneSwitcher.condition.timer.pause="Pause"
AdvSceneSwitcher.condition.timer.continue="Continue"
AdvSceneSwitcher.condition.timer.entry.line1.fixed="{{type}} duration of {{duration}} has passed"
AdvSceneSwitcher.condition.timer.entry.line1.random="{{type}} duration from {{duration}} to {{duration2}} has passed"
AdvSceneSwitcher.condition.timer.entry.line2="Time remaining: {{remaining}} seconds"
AdvSceneSwitcher.condition.timer.entry.line3="{{reset}} {{autoReset}} Automatically reset timer after duration was reached"
AdvSceneSwitcher.condition.timer.entry.line3="{{pauseContinue}} {{reset}} {{saveRemaining}} Save time remaining {{autoReset}} Automatically reset timer after duration was reached"
AdvSceneSwitcher.condition.timer.reset="Reset"
AdvSceneSwitcher.condition.macro="Macro"
AdvSceneSwitcher.condition.macro.type.count="Count"
@@ -137,6 +190,7 @@ AdvSceneSwitcher.condition.macro.count.type.below="Less than"
AdvSceneSwitcher.condition.macro.count.type.above="More than"
AdvSceneSwitcher.condition.macro.count.type.equal="Exactly"
AdvSceneSwitcher.condition.macro.count.reset="Reset"
AdvSceneSwitcher.condition.macro.pausedWarning="Selected macro is currently paused!"
AdvSceneSwitcher.condition.macro.state.entry="Conditions of {{macros}} are true"
AdvSceneSwitcher.condition.macro.count.entry.line1="{{macros}} was executed {{conditions}} {{count}} times"
AdvSceneSwitcher.condition.macro.count.entry.line2="Current count: {{currentCount}} {{resetCount}}"
@@ -167,23 +221,58 @@ 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"
AdvSceneSwitcher.condition.hotkey.entry="Name: {{name}}"
AdvSceneSwitcher.condition.hotkey.entry.line1="Hotkey is pressed"
AdvSceneSwitcher.condition.hotkey.entry.line2="Name: {{name}}"
AdvSceneSwitcher.condition.replay="Replay buffer"
AdvSceneSwitcher.condition.replay.state.stopped="Replay buffer stopped"
AdvSceneSwitcher.condition.replay.state.started="Replay buffer started"
AdvSceneSwitcher.condition.replay.state.saved="Replay buffer saved"
AdvSceneSwitcher.condition.replay.entry="{{state}}"
AdvSceneSwitcher.condition.date="Date"
AdvSceneSwitcher.condition.date.entry.line1="{{dateTime}} {{ignoreDate}} Ignore date selection {{ignoreTime}} Ignore time selection"
AdvSceneSwitcher.condition.date.entry.line2="{{repeat}} Repeat every {{duration}}"
AdvSceneSwitcher.condition.date.state.at="At"
AdvSceneSwitcher.condition.date.state.after="After"
AdvSceneSwitcher.condition.date.state.before="Before"
AdvSceneSwitcher.condition.date.state.between="Between"
AdvSceneSwitcher.condition.date.entry.line1="{{condition}} {{dateTime}} {{dateTime2}} {{ignoreDate}} Ignore date component {{ignoreTime}} Ignore time component"
AdvSceneSwitcher.condition.date.entry.line2="{{repeat}} Repeat every {{duration}} on date match"
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.line2="{{settings}}"
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}} {{getSettings}}"
AdvSceneSwitcher.condition.transition="Transition"
AdvSceneSwitcher.condition.transition.type.current="Current transition type is"
AdvSceneSwitcher.condition.transition.type.duration="Current transition duration is"
AdvSceneSwitcher.condition.transition.type.started="Transition started"
AdvSceneSwitcher.condition.transition.type.ended="Transition ended"
AdvSceneSwitcher.condition.transition.type.transitionSource="Transitioning from"
AdvSceneSwitcher.condition.transition.type.transitionTarget="Transitioning to"
AdvSceneSwitcher.condition.transition.durationSuffix="seconds"
AdvSceneSwitcher.condition.transition.entry="{{conditions}}{{transitions}}{{scenes}}{{duration}}{{durationSuffix}}"
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.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"
@@ -194,6 +283,7 @@ AdvSceneSwitcher.action.audio.type.mute="Mute"
AdvSceneSwitcher.action.audio.type.unmute="Unmute"
AdvSceneSwitcher.action.audio.type.sourceVolume="Set source volume"
AdvSceneSwitcher.action.audio.type.masterVolume="Set master volume"
AdvSceneSwitcher.action.audio.fade="{{fade}}Fade over {{duration}} seconds"
AdvSceneSwitcher.action.audio.entry="{{actions}} {{audioSources}} {{volume}}"
AdvSceneSwitcher.action.recording="Recording"
AdvSceneSwitcher.action.recording.type.stop="Stop recording"
@@ -215,11 +305,13 @@ AdvSceneSwitcher.action.run="Run"
AdvSceneSwitcher.action.run.arguments="Arguments:"
AdvSceneSwitcher.action.run.addArgument="Add argument"
AdvSceneSwitcher.action.run.addArgumentDescription="Add new argument:"
AdvSceneSwitcher.action.run.entry="Run {{filePath}} {{browseButton}}"
AdvSceneSwitcher.action.run.entry="Run {{filePath}}"
AdvSceneSwitcher.action.sceneVisibility="Scene item visibility"
AdvSceneSwitcher.action.sceneVisibility.type.show="Show"
AdvSceneSwitcher.action.sceneVisibility.type.hide="Hide"
AdvSceneSwitcher.action.sceneVisibility.entry="On {{scenes}} {{actions}} {{sources}}"
AdvSceneSwitcher.action.sceneVisibility.type.source="Source"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="Any"
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"
@@ -245,11 +337,15 @@ AdvSceneSwitcher.action.macro="Macro"
AdvSceneSwitcher.action.macro.type.pause="Pause"
AdvSceneSwitcher.action.macro.type.unpause="Unpause"
AdvSceneSwitcher.action.macro.type.resetCounter="Reset counter"
AdvSceneSwitcher.action.macro.type.run="Run"
AdvSceneSwitcher.action.macro.type.stop="Stop"
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
AdvSceneSwitcher.action.pluginState="Plugin state"
AdvSceneSwitcher.action.pluginState.type.stop="Stop the Advanced Scene Switcher plugin"
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"
@@ -263,22 +359,54 @@ AdvSceneSwitcher.action.hotkey.leftAlt="Left Alt"
AdvSceneSwitcher.action.hotkey.rightAlt="Right Alt"
AdvSceneSwitcher.action.hotkey.leftMeta="Left Meta"
AdvSceneSwitcher.action.hotkey.rightMeta="Right Meta"
AdvSceneSwitcher.action.hotkey.onlyOBS="Send keypress only to OBS"
AdvSceneSwitcher.action.hotkey.disabled="Cannot simulate key presses - functionality disabled!"
AdvSceneSwitcher.action.hotkey.entry="Press {{keys}}"
AdvSceneSwitcher.action.hotkey.entry="Press {{keys}} for {{duration}} milliseconds"
AdvSceneSwitcher.action.sceneOrder="Scene item order"
AdvSceneSwitcher.action.sceneOrder.type.moveUp="Move up"
AdvSceneSwitcher.action.sceneOrder.type.moveDown="Move down"
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"
AdvSceneSwitcher.action.file.entry="{{actions}} to {{filePath}} {{browseButton}}:"
AdvSceneSwitcher.action.file.entry="{{actions}} to {{filePath}}:"
AdvSceneSwitcher.action.previewScene="Switch preview scene"
AdvSceneSwitcher.action.previewScene.entry="Switch preview scene to {{scenes}}"
AdvSceneSwitcher.action.SceneSwap="Swap scene (Studio mode)"
AdvSceneSwitcher.action.SceneSwap.entry="Swap preview and program scene in studio mode"
AdvSceneSwitcher.action.transition="Transition"
AdvSceneSwitcher.action.transition.entry.line1="{{setType}}Set transition type to {{transitions}}"
AdvSceneSwitcher.action.transition.entry.line2="{{setDuration}}Set transition duration to {{duration}}seconds"
AdvSceneSwitcher.action.timer="Timer"
AdvSceneSwitcher.action.timer.type.pause="Pause"
AdvSceneSwitcher.action.timer.type.continue="Continue"
AdvSceneSwitcher.action.timer.type.reset="Reset"
AdvSceneSwitcher.action.timer.type.setTimeRemaining="Set time remaining of"
AdvSceneSwitcher.action.timer.entry="{{timerAction}} timers on {{macros}} {{duration}}"
AdvSceneSwitcher.action.random="Random"
AdvSceneSwitcher.action.random.entry="Randomly run any of the following macros (paused macros are ignored)"
AdvSceneSwitcher.action.systray="System tray notification"
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."
AdvSceneSwitcher.action.sequence="Sequence"
AdvSceneSwitcher.action.sequence.entry="Each time this action is performed run the next macro in the list (paused macros are ignored)"
AdvSceneSwitcher.action.sequence.status="Last executed macro: %1 - Next macro to be executed: %2"
AdvSceneSwitcher.action.sequence.status.none="none"
AdvSceneSwitcher.action.sequence.restart="Restart from beginning once end of list is reached"
AdvSceneSwitcher.action.sequence.continueFrom="Continue with selected item"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="Transition"
@@ -450,6 +578,7 @@ AdvSceneSwitcher.videoTab.help="<html><head/><body><p>This tab will allow you to
; Network Tab
AdvSceneSwitcher.networkTab.title="Network"
AdvSceneSwitcher.networkTab.description="This tab will allow you to remotely control the active scene of another OBS instance.\nPlease note that the scene names have to match exactly on all OBS instances."
AdvSceneSwitcher.networkTab.warning="Running the server outside of a local network will allow third parties to read the active scene."
AdvSceneSwitcher.networkTab.DisabledWarning="This functionality unfortunately had to be disabled on macOS due to library incompatibilities when running the obs-websocket plugin in parallel."
AdvSceneSwitcher.networkTab.server="Start server (Sends scene switch messages to all connected clients)"
@@ -523,8 +652,10 @@ AdvSceneSwitcher.hotkey.stopSwitcherHotkey="Stop the Advanced Scene Switcher"
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="Toggle Start/Stop for the Advanced Scene Switcher"
AdvSceneSwitcher.hotkey.macro.pause="Pause macro %1"
AdvSceneSwitcher.hotkey.macro.unpause="Unpause macro %1"
AdvSceneSwitcher.hotkey.macro.togglePause="Toggle pause of macro %1"
AdvSceneSwitcher.askBackup="Detected a new version of the Advanced Scene Switcher.\nShould a backup of the old settings be created?"
AdvSceneSwitcher.askForMacro="Select macro {{macroSelection}}"
AdvSceneSwitcher.close="Close"
AdvSceneSwitcher.browse="Browse"
@@ -534,6 +665,7 @@ AdvSceneSwitcher.selectPreviousScene="Previous Scene"
AdvSceneSwitcher.selectCurrentScene="Current Scene"
AdvSceneSwitcher.selectAnyScene="Any Scene"
AdvSceneSwitcher.currentTransition="Current Transition"
AdvSceneSwitcher.anyTransition="Any Transition"
AdvSceneSwitcher.selectTransition="--select transition--"
AdvSceneSwitcher.selectWindow="--select window--"
AdvSceneSwitcher.selectSource="--select source--"
@@ -544,13 +676,21 @@ 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"

View File

@@ -81,8 +81,7 @@ AdvSceneSwitcher.condition.audio="Аудио"
AdvSceneSwitcher.ondition.audio.state.below="Ниже"
AdvSceneSwitcher.ondition.audio.state.above="Выше"
AdvSceneSwitcher.condition.audio.entry="Громкость {{audioSources}} равна {{condition}} {{volume}} в течении {{duration}} секунд"
AdvSceneSwitcher.condition.region="Область экрана"
AdvSceneSwitcher.condition.region.entry="Курсор находится в {{minX}} {{minY}} x {{maxX}} {{maxY}}"
AdvSceneSwitcher.condition.cursor="Область экрана"
AdvSceneSwitcher.condition.scene="Сцена"
AdvSceneSwitcher.condition.scene.type.current="Текущий"
AdvSceneSwitcher.condition.scene.type.previous="Предыдущий"

View File

@@ -12,17 +12,23 @@ AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart="总是自动启动"
AdvSceneSwitcher.generalTab.status.onStartup.doNotStart="不要启动"
AdvSceneSwitcher.generalTab.status.start="启动"
AdvSceneSwitcher.generalTab.status.stop="停止"
AdvSceneSwitcher.generalTab.status.autoStart="在以下情况下自动启动场景切换程序:"
AdvSceneSwitcher.generalTab.status.autoStart.never="从不"
AdvSceneSwitcher.generalTab.status.autoStart.recording="录制"
AdvSceneSwitcher.generalTab.status.autoStart.streaming="推流"
AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming="录制和推流"
AdvSceneSwitcher.generalTab.status.checkInterval="检查切换条件时间间隔"
AdvSceneSwitcher.generalTab.generalBehavior="一般表现"
AdvSceneSwitcher.generalTab.generalBehavior="全局行为"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet="如果不符合任何切换条件"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip="时间精度最高只能达到配置的轮询间隔"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.dontSwitch="不切换"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="切换到随机场景列表中任意随机场景"
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="切换到"
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="比赛结束多少秒后切换场景"
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="在此期间,可能的匹配项将被忽略!"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="详细日志输出"
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="保存窗口位置和大小"
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="显示系统托盘通知"
AdvSceneSwitcher.generalTab.generalBehavior.disableUIHints="禁用UI提示"
AdvSceneSwitcher.generalTab.priority="优先级"
AdvSceneSwitcher.generalTab.priority.description="切换场景优先级 (最上方的项优先级最高)"
@@ -45,22 +51,338 @@ AdvSceneSwitcher.generalTab.priority.windowTitle="窗口标题"
AdvSceneSwitcher.generalTab.priority.media="媒体"
AdvSceneSwitcher.generalTab.priority.time="时间"
AdvSceneSwitcher.generalTab.priority.audio="音频"
AdvSceneSwitcher.generalTab.priority.video="视频"
AdvSceneSwitcher.generalTab.priority.macro="宏"
; Macro Tab
AdvSceneSwitcher.macroTab.title="宏"
AdvSceneSwitcher.macroTab.macros="宏文件"
AdvSceneSwitcher.macroTab.help="宏允许您根据多种条件执行一系列操作。\n\n单击突出显示的加号可添加新宏."
AdvSceneSwitcher.macroTab.editConditionHelp="此部分允许您定义宏条件。\n\n在左侧选择现有宏或添加新宏。\n然后单击下面的加号按钮添加新条件。"
AdvSceneSwitcher.macroTab.editActionHelp="此部分允许您定义宏操作。\n\n在左侧选择现有宏或添加新宏。\n然后单击下面的加号按钮添加新操作."
AdvSceneSwitcher.macroTab.edit="编辑宏"
AdvSceneSwitcher.macroTab.edit.logic="逻辑类型:"
AdvSceneSwitcher.macroTab.edit.condition="条件类型:"
AdvSceneSwitcher.macroTab.edit.action="动作类型:"
AdvSceneSwitcher.macroTab.add="添加新宏"
AdvSceneSwitcher.macroTab.name="名称:"
AdvSceneSwitcher.macroTab.defaultname="宏 %1"
AdvSceneSwitcher.macroTab.exists="宏名称已存在"
AdvSceneSwitcher.macroTab.copy="创建副本"
AdvSceneSwitcher.macroTab.expandAll="全部展开"
AdvSceneSwitcher.macroTab.collapseAll="全部收回"
; Macro Logic
AdvSceneSwitcher.logic.none="忽略条目"
AdvSceneSwitcher.logic.and="和"
AdvSceneSwitcher.logic.or="或"
AdvSceneSwitcher.logic.andNot="和 不"
AdvSceneSwitcher.logic.orNot="或 不"
AdvSceneSwitcher.logic.rootNone="如果"
AdvSceneSwitcher.logic.not="如果 不"
; Macro Conditions
AdvSceneSwitcher.condition.audio="音频"
AdvSceneSwitcher.condition.audio.state.below="小于"
AdvSceneSwitcher.condition.audio.state.above="大于"
AdvSceneSwitcher.condition.audio.entry="音量 来源 {{audioSources}} 是 {{condition}} {{volume}}"
AdvSceneSwitcher.condition.cursor="光标"
AdvSceneSwitcher.condition.cursor.type.region="当前位置"
AdvSceneSwitcher.condition.cursor.type.moving="正在移动"
AdvSceneSwitcher.condition.cursor.showFrame="显示帧率"
AdvSceneSwitcher.condition.cursor.hideFrame="隐藏帧率"
AdvSceneSwitcher.condition.cursor.entry.line1="光标 处于{{conditions}} {{minX}} {{minY}} {{maxX}} {{maxY}} - {{toggleFrameButton}}"
AdvSceneSwitcher.condition.cursor.entry.line2="光标当前位于 {{xPos}} x {{yPos}}"
AdvSceneSwitcher.condition.scene="场景"
AdvSceneSwitcher.condition.scene.type.current="当前场景是"
AdvSceneSwitcher.condition.scene.type.previous="上一个场景是"
AdvSceneSwitcher.condition.scene.type.changed="场景改变了"
AdvSceneSwitcher.condition.scene.type.notChanged="场景没有改变"
AdvSceneSwitcher.condition.scene.waitForTransition="等待过渡完成"
AdvSceneSwitcher.condition.scene.entry="{{sceneType}} {{scenes}} {{waitForTransition}}"
AdvSceneSwitcher.condition.window="窗口"
AdvSceneSwitcher.condition.window.entry.line1="{{windows}} 存在..."
AdvSceneSwitcher.condition.window.entry.line2="... 并且是 {{fullscreen}} 全屏 {{maximized}} 最大化 {{focused}} 获得焦点 {{windowFocusChanged}} 焦点窗口已更改"
AdvSceneSwitcher.condition.file="文件"
AdvSceneSwitcher.condition.file.entry.line1="内容 {{fileType}} {{filePath}} (本地是文本,网络是获取的网页)完全匹配:"
AdvSceneSwitcher.condition.file.entry.line2="{{matchText}}"
AdvSceneSwitcher.condition.file.entry.line3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
AdvSceneSwitcher.condition.media="媒体"
AdvSceneSwitcher.condition.media.entry="{{mediaSources}} 状态是 {{states}} 和 {{timeRestrictions}} {{time}}"
AdvSceneSwitcher.condition.video="视频"
AdvSceneSwitcher.condition.video.condition.match="完全匹配"
AdvSceneSwitcher.condition.video.condition.differ="不匹配"
AdvSceneSwitcher.condition.video.condition.hasChanged="改变了"
AdvSceneSwitcher.condition.video.condition.hasNotChanged="没有改变"
AdvSceneSwitcher.condition.video.condition.noImage="没有输出"
AdvSceneSwitcher.condition.video.condition.pattern="匹配模式"
AdvSceneSwitcher.condition.video.condition.object="包含对象"
AdvSceneSwitcher.condition.video.askFileAction="是否要使用现有文件或创建当前选定源的屏幕截图?"
AdvSceneSwitcher.condition.video.askFileAction.file="使用现有文件"
AdvSceneSwitcher.condition.video.askFileAction.screenshot="创建屏幕截图"
AdvSceneSwitcher.condition.video.usePatternForChangedCheck="使用模式匹配"
AdvSceneSwitcher.condition.video.usePatternForChangedCheck.tooltip="这将允许您控制图像必须更改多少才能使条件为真."
AdvSceneSwitcher.condition.video.patternThreshold="阈值: "
AdvSceneSwitcher.condition.video.patternThresholdDescription="较高的阈值意味着模式需要更紧密地匹配视频源."
AdvSceneSwitcher.condition.video.patternThresholdUseAlphaAsMask="使用alpha通道作为图案的遮罩."
AdvSceneSwitcher.condition.video.objectScaleThreshold="模型比例: "
AdvSceneSwitcher.condition.video.objectScaleThresholdDescription="较低的模比例将导致更多的匹配但会导致更高的CPU负载."
AdvSceneSwitcher.condition.video.minNeighborDescription="较高的“最小区域”值将导致较少但质量较高的匹配."
AdvSceneSwitcher.condition.video.showMatch="显示模式"
AdvSceneSwitcher.condition.video.screenshotFail="无法获取源的屏幕截图!"
AdvSceneSwitcher.condition.video.patternMatchFail="没有找到模式!"
AdvSceneSwitcher.condition.video.objectMatchFail="找不到对象!"
AdvSceneSwitcher.condition.video.modelLoadFail="无法加载模型数据!"
AdvSceneSwitcher.condition.video.entry="{{videoSources}} {{condition}} {{imagePath}}"
AdvSceneSwitcher.condition.video.entry.modelPath="模型数据 (haar级联分类器): {{modelDataPath}}"
AdvSceneSwitcher.condition.video.entry.minNeighbor="最小区域: {{minNeighbors}}"
AdvSceneSwitcher.condition.video.entry.minSize="最小尺寸: {{minSizeX}} x {{minSizeY}}"
AdvSceneSwitcher.condition.video.entry.maxSize="最大尺寸: {{maxSizeX}} x {{maxSizeY}}"
AdvSceneSwitcher.condition.video.entry.throttle="{{throttleEnable}}通过只执行每一次检查来减少CPU负载 {{throttleCount}} 毫秒"
AdvSceneSwitcher.condition.stream="推流"
AdvSceneSwitcher.condition.stream.state.start="推流启动"
AdvSceneSwitcher.condition.stream.state.stop="推流停止"
AdvSceneSwitcher.condition.stream.state.starting="推流启动中"
AdvSceneSwitcher.condition.stream.state.stopping="推流停止中"
AdvSceneSwitcher.condition.stream.entry="{{streamState}}"
AdvSceneSwitcher.condition.record="录制"
AdvSceneSwitcher.condition.record.state.start="录制运行中"
AdvSceneSwitcher.condition.record.state.pause="录制暂停"
AdvSceneSwitcher.condition.record.state.stop="录制停止"
AdvSceneSwitcher.condition.record.entry="{{recordState}}"
AdvSceneSwitcher.condition.process="进程"
AdvSceneSwitcher.condition.process.entry="{{processes}} 正在运行 {{focused}} 而且是获得焦点"
AdvSceneSwitcher.condition.idle="闲置检测"
AdvSceneSwitcher.condition.idle.entry="没有键盘或鼠标输入{{duration}}"
AdvSceneSwitcher.condition.pluginState="插件状态"
AdvSceneSwitcher.condition.pluginState.state.sceneSwitched="在此时间间隔内触发了自动场景更改"
AdvSceneSwitcher.condition.pluginState.entry="{{condition}}"
AdvSceneSwitcher.condition.timer="计时器"
AdvSceneSwitcher.condition.timer.pause="暂停"
AdvSceneSwitcher.condition.timer.continue="继续"
AdvSceneSwitcher.condition.timer.entry.line1="{{duration}} 时间倒计时"
AdvSceneSwitcher.condition.timer.entry.line2="剩余时间: {{remaining}} 秒"
AdvSceneSwitcher.condition.timer.entry.line3="{{pauseContinue}} {{reset}} {{saveRemaining}} 保存剩余时间 {{autoReset}} 达到时间后自动重置计时器"
AdvSceneSwitcher.condition.timer.reset="重置"
AdvSceneSwitcher.condition.macro="宏"
AdvSceneSwitcher.condition.macro.type.count="计数"
AdvSceneSwitcher.condition.macro.type.state="状态"
AdvSceneSwitcher.condition.macro.type.selection="条件类型: {{types}}"
AdvSceneSwitcher.condition.macro.count.type.below="少于"
AdvSceneSwitcher.condition.macro.count.type.above="大于"
AdvSceneSwitcher.condition.macro.count.type.equal="等于"
AdvSceneSwitcher.condition.macro.count.reset="重置"
AdvSceneSwitcher.condition.macro.pausedWarning="所选宏当前已暂停!"
AdvSceneSwitcher.condition.macro.state.entry="条件 {{macros}} 是真的"
AdvSceneSwitcher.condition.macro.count.entry.line1="{{macros}} 运行 {{conditions}} {{count}} 次(相对于下面计数匹配)"
AdvSceneSwitcher.condition.macro.count.entry.line2="当前计数: {{currentCount}} {{resetCount}}"
AdvSceneSwitcher.condition.source="源"
AdvSceneSwitcher.condition.source.type.active="激活状态"
AdvSceneSwitcher.condition.source.type.showing="显示状态"
AdvSceneSwitcher.condition.source.type.settings="设置完全匹配"
AdvSceneSwitcher.condition.source.regex="使用正则表达式"
AdvSceneSwitcher.condition.source.getSettings="获取当前设置"
AdvSceneSwitcher.condition.source.entry.line1="{{sources}} {{conditions}}"
AdvSceneSwitcher.condition.source.entry.line2="{{settings}}"
AdvSceneSwitcher.condition.source.entry.line3="{{regex}} {{getSettings}}"
AdvSceneSwitcher.condition.virtualCamera="虚拟摄像机"
AdvSceneSwitcher.condition.virtualCamera.state.start="虚拟摄像机启动"
AdvSceneSwitcher.condition.virtualCamera.state.stop="虚拟摄像机停止"
AdvSceneSwitcher.condition.virtualCamera.entry="{{states}}"
AdvSceneSwitcher.condition.filter="滤镜"
AdvSceneSwitcher.condition.filter.type.active="已启用"
AdvSceneSwitcher.condition.filter.type.showing="已关闭"
AdvSceneSwitcher.condition.filter.type.settings="设置完全匹配"
AdvSceneSwitcher.condition.filter.regex="使用正则表达式"
AdvSceneSwitcher.condition.filter.getSettings="获取当前设置"
AdvSceneSwitcher.condition.filter.entry.line1="在 {{sources}} {{filters}} {{conditions}}"
AdvSceneSwitcher.condition.filter.entry.line2="{{settings}}"
AdvSceneSwitcher.condition.filter.entry.line3="{{regex}} {{getSettings}}"
AdvSceneSwitcher.condition.sceneOrder="场景项目顺序"
AdvSceneSwitcher.condition.sceneOrder.type.above="高于"
AdvSceneSwitcher.condition.sceneOrder.type.below="低于"
AdvSceneSwitcher.condition.sceneOrder.type.position="位置值排比"
AdvSceneSwitcher.condition.sceneOrder.positionInfo="位置值从底部以0开始对于每个场景项目包括场景组中的项目增加1自行测试按照上下往上排比数值。"
AdvSceneSwitcher.condition.sceneOrder.entry="在 {{scenes}} {{sources}} {{conditions}} {{sources2}} {{position}}"
AdvSceneSwitcher.condition.hotkey="热键"
AdvSceneSwitcher.condition.hotkey.name="宏触发热键"
AdvSceneSwitcher.condition.hotkey.tip="注意您可以在OBS设置窗口中为此热键配置按键绑定"
AdvSceneSwitcher.condition.hotkey.entry="名称: {{name}}"
AdvSceneSwitcher.condition.replay="回放缓存"
AdvSceneSwitcher.condition.replay.state.stopped="回放缓存已停止"
AdvSceneSwitcher.condition.replay.state.started="回放缓存已启动"
AdvSceneSwitcher.condition.replay.state.saved="已保存回放缓存"
AdvSceneSwitcher.condition.replay.entry="{{state}}"
AdvSceneSwitcher.condition.date="日期"
AdvSceneSwitcher.condition.date.state.at="现在"
AdvSceneSwitcher.condition.date.state.after="之后"
AdvSceneSwitcher.condition.date.state.before="之前"
AdvSceneSwitcher.condition.date.state.between="之间"
AdvSceneSwitcher.condition.date.entry.line1="{{condition}} {{dateTime}} {{dateTime2}} {{ignoreDate}} 忽略日期 {{ignoreTime}} 忽略时间"
AdvSceneSwitcher.condition.date.entry.line2="{{repeat}} 重复的每一次 {{duration}} 匹配的时间"
AdvSceneSwitcher.condition.sceneTransform="场景项目被改变"
AdvSceneSwitcher.condition.sceneTransform.getTransform="内容或者设置被改变了"
AdvSceneSwitcher.condition.sceneTransform.regex="使用正则表达式"
AdvSceneSwitcher.condition.sceneTransform.entry.line1="在 {{scenes}} {{sources}} 匹配变换"
AdvSceneSwitcher.condition.sceneTransform.entry.line2="{{settings}}"
AdvSceneSwitcher.condition.sceneTransform.entry.line3="{{regex}} {{getSettings}}"
AdvSceneSwitcher.condition.transition="转场"
AdvSceneSwitcher.condition.transition.type.current="当前转场特效类型为"
AdvSceneSwitcher.condition.transition.type.duration="当前转场特效持续时间为"
AdvSceneSwitcher.condition.transition.type.started="转场特效开始"
AdvSceneSwitcher.condition.transition.type.ended="转场特效结束"
AdvSceneSwitcher.condition.transition.durationSuffix="秒"
AdvSceneSwitcher.condition.transition.entry="{{conditions}}{{transitions}}{{duration}}{{durationSuffix}}"
AdvSceneSwitcher.condition.sceneVisibility="场景项目可见"
AdvSceneSwitcher.condition.sceneVisibility.type.shown="显示的"
AdvSceneSwitcher.condition.sceneVisibility.type.hidden="隐藏的"
AdvSceneSwitcher.condition.sceneVisibility.entry="在 {{scenes}} {{sources}} 是 {{conditions}} "
; Macro Actions
AdvSceneSwitcher.action.switchScene="切换场景"
AdvSceneSwitcher.action.scene.entry="切换场景 {{scenes}} 使用 {{transitions}} 时长 {{duration}} 秒"
AdvSceneSwitcher.action.wait="等待"
AdvSceneSwitcher.action.wait.type.fixed="固定数值"
AdvSceneSwitcher.action.wait.type.random="随机数值"
AdvSceneSwitcher.action.wait.entry.fixed="等待 {{waitType}} 持续时间为 {{duration}}"
AdvSceneSwitcher.action.wait.entry.random="等待 {{waitType}} 持续时间为 {{duration}} 到 {{duration2}}"
AdvSceneSwitcher.action.audio="音频"
AdvSceneSwitcher.action.audio.type.mute="静音"
AdvSceneSwitcher.action.audio.type.unmute="取消静音"
AdvSceneSwitcher.action.audio.type.sourceVolume="来源音量"
AdvSceneSwitcher.action.audio.type.masterVolume="主音量"
AdvSceneSwitcher.action.audio.fade="{{fade}}淡出 {{duration}} 秒"
AdvSceneSwitcher.action.audio.entry="{{actions}} {{audioSources}} {{volume}}"
AdvSceneSwitcher.action.recording="录制"
AdvSceneSwitcher.action.recording.type.stop="停止录制"
AdvSceneSwitcher.action.recording.type.start="开始录制"
AdvSceneSwitcher.action.recording.type.pause="暂停录制"
AdvSceneSwitcher.action.recording.type.unpause="取消录制暂停"
AdvSceneSwitcher.action.recording.pause.hint="请注意,根据您的录制设置,您可能无法暂停录制"
AdvSceneSwitcher.action.recording.entry="{{actions}}{{pauseHint}}"
AdvSceneSwitcher.action.replay="回放缓冲区"
AdvSceneSwitcher.action.replay.type.stop="停止回放缓冲区"
AdvSceneSwitcher.action.replay.type.start="启动回放缓冲区"
AdvSceneSwitcher.action.replay.type.save="保存回放缓冲区"
AdvSceneSwitcher.action.replay.entry="{{actions}}"
AdvSceneSwitcher.action.streaming="推流"
AdvSceneSwitcher.action.streaming.type.stop="停止推流"
AdvSceneSwitcher.action.streaming.type.start="开始推流"
AdvSceneSwitcher.action.streaming.entry="{{actions}}"
AdvSceneSwitcher.action.run="运行"
AdvSceneSwitcher.action.run.arguments="参数:"
AdvSceneSwitcher.action.run.addArgument="添加参数"
AdvSceneSwitcher.action.run.addArgumentDescription="添加新参数:"
AdvSceneSwitcher.action.run.entry="运行 {{filePath}}"
AdvSceneSwitcher.action.sceneVisibility="场景项目可见性"
AdvSceneSwitcher.action.sceneVisibility.type.show="显示"
AdvSceneSwitcher.action.sceneVisibility.type.hide="隐藏"
AdvSceneSwitcher.action.sceneVisibility.type.source="来源"
AdvSceneSwitcher.action.sceneVisibility.type.sourceGroup="全部"
AdvSceneSwitcher.action.sceneVisibility.entry="在 {{scenes}} {{actions}} {{sourceTypes}} {{sources}}"
AdvSceneSwitcher.action.filter="滤镜"
AdvSceneSwitcher.action.filter.type.enable="开启"
AdvSceneSwitcher.action.filter.type.disable="关闭"
AdvSceneSwitcher.action.filter.type.settings="参数设置"
AdvSceneSwitcher.action.filter.entry="在 {{sources}} {{actions}} {{filters}}"
AdvSceneSwitcher.action.filter.getSettings="获取当前设置"
AdvSceneSwitcher.action.source="来源"
AdvSceneSwitcher.action.source.type.enable="启用"
AdvSceneSwitcher.action.source.type.disable="停用"
AdvSceneSwitcher.action.source.type.settings="配置设置"
AdvSceneSwitcher.action.source.entry="{{actions}} {{sources}}"
AdvSceneSwitcher.action.source.warning="警告OBS UI无法控制全局启用和禁用源注意通过这个设置禁用我测试你必须通过这个在启用才行不然点击小眼睛你无法显示"
AdvSceneSwitcher.action.source.getSettings="获取当前设置"
AdvSceneSwitcher.action.media="媒体"
AdvSceneSwitcher.action.media.type.play="开始"
AdvSceneSwitcher.action.media.type.pause="暂停"
AdvSceneSwitcher.action.media.type.stop="停止"
AdvSceneSwitcher.action.media.type.restart="重新启动"
AdvSceneSwitcher.action.media.type.next="下一个"
AdvSceneSwitcher.action.media.type.previous="上一个"
AdvSceneSwitcher.action.media.entry="{{actions}} {{mediaSources}}"
AdvSceneSwitcher.action.macro="宏"
AdvSceneSwitcher.action.macro.type.pause="暂停"
AdvSceneSwitcher.action.macro.type.unpause="取消暂停"
AdvSceneSwitcher.action.macro.type.resetCounter="复位计数器"
AdvSceneSwitcher.action.macro.entry="{{actions}} {{macros}}"
AdvSceneSwitcher.action.pluginState="插件状态"
AdvSceneSwitcher.action.pluginState.type.stop="停止高级场景切换插件"
AdvSceneSwitcher.action.pluginState.type.noMatch="没有匹配项:"
AdvSceneSwitcher.action.pluginState.entry="{{actions}} {{values}} {{scenes}}"
AdvSceneSwitcher.action.virtualCamera="虚拟摄像机"
AdvSceneSwitcher.action.virtualCamera.type.stop="停止虚拟摄像机"
AdvSceneSwitcher.action.virtualCamera.type.start="启动虚拟摄像机"
AdvSceneSwitcher.action.virtualCamera.entry="{{actions}}"
AdvSceneSwitcher.action.hotkey="热键"
AdvSceneSwitcher.action.hotkey.leftShift="左 Shift"
AdvSceneSwitcher.action.hotkey.rightShift="右 Shift"
AdvSceneSwitcher.action.hotkey.leftCtrl="左 Ctrl"
AdvSceneSwitcher.action.hotkey.rightCtrl="右 Ctrl"
AdvSceneSwitcher.action.hotkey.leftAlt="左 Alt"
AdvSceneSwitcher.action.hotkey.rightAlt="右 Alt"
AdvSceneSwitcher.action.hotkey.leftMeta="左 Meta"
AdvSceneSwitcher.action.hotkey.rightMeta="右 Meta"
AdvSceneSwitcher.action.hotkey.onlyOBS="仅向OBS发送按键"
AdvSceneSwitcher.action.hotkey.disabled="无法模拟按键-功能已禁用!"
AdvSceneSwitcher.action.hotkey.entry="按下 {{keys}} for {{duration}} 毫秒"
AdvSceneSwitcher.action.sceneOrder="场景项目顺序"
AdvSceneSwitcher.action.sceneOrder.type.moveUp="上移"
AdvSceneSwitcher.action.sceneOrder.type.moveDown="下移"
AdvSceneSwitcher.action.sceneOrder.type.moveTop="顶部"
AdvSceneSwitcher.action.sceneOrder.type.moveBottom="底部"
AdvSceneSwitcher.action.sceneOrder.type.movePosition="移动到数值位置"
AdvSceneSwitcher.action.sceneOrder.entry="在 {{scenes}} {{actions}} {{sources}} {{position}}"
AdvSceneSwitcher.action.sceneTransform="场景项变换"
AdvSceneSwitcher.action.sceneTransform.getTransform="得到变换"
AdvSceneSwitcher.action.sceneTransform.entry="On {{scenes}} transform {{sources}}"
AdvSceneSwitcher.action.file="文件"
AdvSceneSwitcher.action.file.type.write="写入"
AdvSceneSwitcher.action.file.type.append="追加写入"
AdvSceneSwitcher.action.file.entry="{{actions}} to {{filePath}}:"
AdvSceneSwitcher.action.previewScene="切换预览场景"
AdvSceneSwitcher.action.previewScene.entry="将预览场景切换到 {{scenes}}"
AdvSceneSwitcher.action.SceneSwap="交换场景 (Studio mode)"
AdvSceneSwitcher.action.SceneSwap.entry="在studio模式下交换预览和编程场景"
AdvSceneSwitcher.action.transition="过场特效"
AdvSceneSwitcher.action.transition.entry.line1="{{setType}}将过场特效类型设置为 {{transitions}}"
AdvSceneSwitcher.action.transition.entry.line2="{{setDuration}}将过场特效持续时间设置为 {{duration}}seconds"
AdvSceneSwitcher.action.timer="计时器"
AdvSceneSwitcher.action.timer.type.pause="暂停"
AdvSceneSwitcher.action.timer.type.continue="继续"
AdvSceneSwitcher.action.timer.type.reset="重置"
AdvSceneSwitcher.action.timer.type.setTimeRemaining="设置剩余时间"
AdvSceneSwitcher.action.timer.entry="{{timerAction}} 定时在 {{macros}} {{duration}}"
AdvSceneSwitcher.action.random="随机"
AdvSceneSwitcher.action.random.arguments="宏:"
AdvSceneSwitcher.action.random.addArgument="增加 宏"
AdvSceneSwitcher.action.random.entry="运行 {{macroSelection}}"
; Transition Tab
AdvSceneSwitcher.transitionTab.title="转场特效"
AdvSceneSwitcher.transitionTab.setTransitionBy="更改转场特效时:"
AdvSceneSwitcher.transitionTab.transitionOverride="在场景切换器中设定的转场特效优先级高于场景设定的转场特效"
AdvSceneSwitcher.transitionTab.adjustActiveTransitionType="更改激活转场特效类型"
AdvSceneSwitcher.transitionTab.transitionForAToB="当自动从场景A切换到场景B时使用的转场特效"
AdvSceneSwitcher.transitionTab.transitionsHelp="<html><head/><body><p>这里的设定<span style=\"font-style:bold;\">只影响由场景切换器引起的转场有效</span>,不影响你手动的引起的转场。<br/>在这里设定的转场特效优先级高于场景切换器其他地方设置的<br/><br/>Click the plus symbol below to continue.</p></body></html>"
AdvSceneSwitcher.transitionTab.transitionsHelp="<html><head/><body><p>这里的设定<span style=\"font-style:bold;\">只影响由场景切换器引起的转场有效</span>,不影响你手动的引起的转场。<br/>在这里设定的转场特效优先级高于场景切换器其他地方设置的<br/><br/>单击加号添加项目.</p></body></html>"
AdvSceneSwitcher.transitionTab.defaultTransition="当切换到这个场景时修改默认转场特效"
AdvSceneSwitcher.transitionTab.switchDefaultLabel="活跃时切换默认转场特效为"
AdvSceneSwitcher.transitionTab.entry="从场景 {{scenes}} 切换到场景 {{scenes2}} 时使用转场特效 {{transitions}}"
AdvSceneSwitcher.transitionTab.defaultTransitionEntry="当场景 {{scenes}} 被激活时更改默认转场特效为 {{transitions}}"
AdvSceneSwitcher.transitionTab.defaultTransitionsHelp="单击加号添加项目."
AdvSceneSwitcher.transitionTab.defaultTransition.delay="场景更改 {{defTransitionDelay}} 后切换转换特效."
AdvSceneSwitcher.transitionTab.defaultTransition.delay.help="延迟用于避免取消场景切换,如果在转换仍在进行时更改了转换类型,则可能会发生这种情况."
; Pause Scenes Tab
AdvSceneSwitcher.pauseTab.title="暂停"
AdvSceneSwitcher.pauseTab.pauseOnScene="当切换到这个场景时暂停场景切换器"
AdvSceneSwitcher.pauseTab.pauseInFocus1="当窗口"
AdvSceneSwitcher.pauseTab.pauseInFocus2="获得焦点时暂停场景切换器"
AdvSceneSwitcher.pauseTab.pauseTypeScene="场景处于活动状态"
AdvSceneSwitcher.pauseTab.pauseTypeWindow="窗口处于焦点位置"
AdvSceneSwitcher.pauseTab.pauseTargetAll="全部"
AdvSceneSwitcher.pauseTab.pauseEntry="暂停 {{pauseTargets}} 检查时 {{pauseTypes}} {{scenes}} {{windows}}"
AdvSceneSwitcher.pauseTab.help="在此选项卡上,您可以配置在场景处于活动状态或窗口处于焦点时暂停各个切换方法。\n\n单击高亮显示的加号继续."
; Window Title Tab
AdvSceneSwitcher.windowTitleTab.title="窗口标题"
@@ -71,31 +393,37 @@ AdvSceneSwitcher.windowTitleTab.fullscreen="全屏时"
AdvSceneSwitcher.windowTitleTab.maximized="最大化时"
AdvSceneSwitcher.windowTitleTab.focused="窗口聚集时"
AdvSceneSwitcher.windowTitleTab.entry="{{windows}} {{scenes}} {{transitions}} {{fullscreen}} {{maximized}} {{focused}}"
AdvSceneSwitcher.windowTitleTab.windowsHelp="根据正在运行的应用程序的窗口标题切换场景。\n可以选择以下附加条件\n窗口全屏显示\n窗口最大化\n窗口聚焦\n\n单击高亮显示的加号继续."
AdvSceneSwitcher.windowTitleTab.ignoreWindowsHelp="如果忽略某个窗口标题,则场景切换程序的作用将与之前选择的窗口仍处于焦点状态一样。\n如果您经常切换到其他窗口则这将允许您避免场景切换不会触发场景更改。\n\n请选择窗口或在上面输入窗口标题然后单击下面的加号将其添加到列表中."
; Executable Tab
AdvSceneSwitcher.executableTab.title="程序"
AdvSceneSwitcher.executableTab.implemented="感谢dasOven的实现"
AdvSceneSwitcher.executableTab.requiresFocus="仅获得焦点时"
AdvSceneSwitcher.executableTab.entry="当 {{processes}} 正在运行时使用 {{transitions}} 切换到 {{scenes}} {{requiresFocus}}"
AdvSceneSwitcher.executableTab.help="如果进程正在运行,此选项卡将允许您自动切换场景。\n这在窗口名称可能更改或未知的情况下非常有用。\n\n单击突出显示的加号继续."
; Screen Region Tab
AdvSceneSwitcher.screenRegionTab.title="屏幕区域"
AdvSceneSwitcher.screenRegionTab.currentPosition="鼠标当前位置:"
AdvSceneSwitcher.screenRegionTab.showGuideFrames="显示区域边界"
AdvSceneSwitcher.screenRegionTab.hideGuideFrames="隐藏区域边界"
AdvSceneSwitcher.screenRegionTab.excludeScenes.None="没有选择"
AdvSceneSwitcher.screenRegionTab.entry="如果鼠标在 {{minX}} {{minY}} x {{maxX}} {{maxY}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}} unless in {{excludeScenes}}"
AdvSceneSwitcher.screenRegionTab.help="此选项卡允许您根据鼠标光标的当前位置自动切换场景。\n\n单击高亮显示的加号继续."
; Media Tab
AdvSceneSwitcher.mediaTab.title="媒体"
AdvSceneSwitcher.mediaTab.implemented="感谢Exeldro的实现"
AdvSceneSwitcher.mediaTab.states.none=""
AdvSceneSwitcher.mediaTab.states.none=""
AdvSceneSwitcher.mediaTab.states.playing="播放中"
AdvSceneSwitcher.mediaTab.states.opening="正在打开"
AdvSceneSwitcher.mediaTab.states.opening="打开"
AdvSceneSwitcher.mediaTab.states.buffering="缓冲中"
AdvSceneSwitcher.mediaTab.states.Paused="暂停"
AdvSceneSwitcher.mediaTab.states.stopped="停止"
AdvSceneSwitcher.mediaTab.states.ended="结束"
AdvSceneSwitcher.mediaTab.states.error="错误"
AdvSceneSwitcher.mediaTab.states.playedToEnd="播放结束"
AdvSceneSwitcher.mediaTab.states.any="任意"
AdvSceneSwitcher.mediaTab.timeRestriction.none="无"
AdvSceneSwitcher.mediaTab.timeRestriction.shorter="播放时间小于"
@@ -103,6 +431,7 @@ AdvSceneSwitcher.mediaTab.timeRestriction.longer="播放时间大于"
AdvSceneSwitcher.mediaTab.timeRestriction.remainShorter="剩余时间少于"
AdvSceneSwitcher.mediaTab.timeRestriction.remainLonger="剩余时间多于"
AdvSceneSwitcher.mediaTab.entry="当 {{mediaSources}} 状态为 {{states}} 并且 {{timeRestrictions}} {{time}} 时使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
AdvSceneSwitcher.mediaTab.help="此选项卡允许您根据媒体源的状态切换场景。\n例如一旦所选媒体源结束播放您可以自动切换回上一个场景。\n\n单击高亮显示的加号继续."
; File Tab
AdvSceneSwitcher.fileTab.title="文件"
@@ -127,11 +456,13 @@ AdvSceneSwitcher.fileTab.checkfileContent="仅当文件发生修改时"
AdvSceneSwitcher.fileTab.entry="如果 {{fileType}} 文件 {{filePath}} {{browseButton}} 匹配下列规则,使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
AdvSceneSwitcher.fileTab.entry2="{{matchText}}"
AdvSceneSwitcher.fileTab.entry3="{{useRegex}} {{checkModificationDate}} {{checkFileContent}}"
AdvSceneSwitcher.fileTab.help="此选项卡允许您根据远程或本地文件的内容自动切换场景。\n\n单击突出显示的加号继续."
; Random Tab
AdvSceneSwitcher.randomTab.title="随机场景列表"
AdvSceneSwitcher.randomTab.randomDisabledWarning="功能已被禁用 - 可通过在通用页设置\"如果不符合任何切换条件切换到随机场景列表中任意随机场景\"启用"
AdvSceneSwitcher.randomTab.entry="如果没有切换器条件满足,使用转场特效 {{transitions}} 切换到场景 {{scenes}} 并停留 {{delay}}"
AdvSceneSwitcher.randomTab.help="场景切换程序将在此选项卡上随机选择一个条目,以便在配置的时间内切换到该条目。\n请注意同一条目不会连续选择两次。\n\n单击高亮显示的加号继续."
; Time Tab
AdvSceneSwitcher.timeTab.title="时间"
@@ -146,15 +477,12 @@ AdvSceneSwitcher.timeTab.sundays="每周日"
AdvSceneSwitcher.timeTab.afterstart="推流或录制开始后"
AdvSceneSwitcher.timeTab.afterstart.tip="相对于直播或录制开始之后的时间点"
AdvSceneSwitcher.timeTab.entry="{{triggers}} 的 {{time}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
AdvSceneSwitcher.timeTab.help="此选项卡将允许您根据当前本地时间自动切换到其他场景。\n\n请注意场景切换程序仅在您指定的确切时间切换场景。\n请确保您已根据自己的喜好在“常规”选项卡上配置了优先级设置以便不会因其他切换而错过选定的时间点具有较高优先级的方法。\n\n单击突出显示的加号继续."
; Idle Tab
AdvSceneSwitcher.idleTab.title="闲置检测"
AdvSceneSwitcher.idleTab.enable="启用闲置检测"
AdvSceneSwitcher.idleTab.condition1="超过"
AdvSceneSwitcher.idleTab.condition2="没有鼠标或键盘操作"
AdvSceneSwitcher.idleTab.switchToScene="切换到场景"
AdvSceneSwitcher.idleTab.usingTransition1="使用"
AdvSceneSwitcher.idleTab.usingTransition2="转场特效"
AdvSceneSwitcher.idleTab.idleswitch="超过 {{duration}} 如果没有键盘或鼠标输入,则切换到场景 {{scenes}} 使用 {{transitions}}"
AdvSceneSwitcher.idleTab.dontSwitchIfFocus1="如果当前窗口焦点在"
AdvSceneSwitcher.idleTab.dontSwitchIfFocus2="时不切换"
@@ -169,35 +497,148 @@ AdvSceneSwitcher.sceneSequenceTab.loadFail="导入失败"
AdvSceneSwitcher.sceneSequenceTab.loadSuccess="导入失败成功"
AdvSceneSwitcher.sceneSequenceTab.fileType="文本文件 (*.txt)"
AdvSceneSwitcher.sceneSequenceTab.entry="当场景 {{startScenes}} 被激活 {{delay}} 后使用转场特效 {{transitions}} 切换到场景 {{scenes}} {{interruptible}}"
AdvSceneSwitcher.sceneSequenceTab.interruptible="中断"
AdvSceneSwitcher.sceneSequenceTab.interruptibleHint="允许使用其他切换方法中断此场景序列"
AdvSceneSwitcher.sceneSequenceTab.extendEdit="扩展序列"
AdvSceneSwitcher.sceneSequenceTab.extendEntry="之后 {{delay}} 切换到 {{scenes}} 使用 {{transitions}}"
AdvSceneSwitcher.sceneSequenceTab.help="如果某个场景在配置的时间段内处于活动状态,此选项卡将允许您自动切换到其他场景。\n例如您可以自动在两个场景之间来回循环。\n\n单击高亮显示的加号继续."
; Audio Tab
AdvSceneSwitcher.audioTab.title="音频"
AdvSceneSwitcher.audioTab.entry="当{{audioSources}} is {{condition}} {{volumeWidget}} for {{duration}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
AdvSceneSwitcher.audioTab.condition.above="高于"
AdvSceneSwitcher.audioTab.condition.below="低于"
AdvSceneSwitcher.audioTab.ignoreInactiveSource="除非源处于非活动状态"
AdvSceneSwitcher.audioTab.entry="当{{audioSources}} 在 {{condition}} {{volumeWidget}} for {{duration}} 使用转场特效 {{transitions}} 切换到场景 {{scenes}}"
AdvSceneSwitcher.audioTab.multiMatchfallbackCondition="如果多个条目匹配 ..."
AdvSceneSwitcher.audioTab.multiMatchfallback="... for {{duration}} 秒切换到 {{scenes}} 使用 {{transitions}}"
AdvSceneSwitcher.audioTab.help="此选项卡允许您根据源音量切换场景。\n例如如果麦克风音量达到某个阈值您可以自动切换到其他场景。\n\n单击高亮显示的加号继续."
; Video Tab
AdvSceneSwitcher.videoTab.title="视频"
AdvSceneSwitcher.videoTab.getScreenshot="获取所选条目的屏幕截图"
AdvSceneSwitcher.videoTab.getScreenshotHelp="获取当前选定项目的视频源的屏幕截图,并自动将其设置为目标图像"
AdvSceneSwitcher.videoTab.condition.match="完全匹配"
AdvSceneSwitcher.videoTab.condition.match.tooltip="精确匹配要求目标图像和源图像具有相同的分辨率。\n另外每个像素都需要匹配这就是为什么不建议使用使用压缩例如.JPG的图像格式"
AdvSceneSwitcher.videoTab.condition.differ="不匹配"
AdvSceneSwitcher.videoTab.condition.hasNotChanged="没有改变"
AdvSceneSwitcher.videoTab.condition.hasChanged="改变了"
AdvSceneSwitcher.videoTab.entry="当 {{videoSources}} {{condition}} {{filePath}} {{browseButton}} for {{duration}} 切换 {{scenes}} using {{transitions}} {{ignoreInactiveSource}}"
AdvSceneSwitcher.videoTab.ignoreInactiveSource="除非源处于非活动状态"
AdvSceneSwitcher.videoTab.help="<html><head/><body><p>此选项卡将允许您根据选定源的当前视频输出切换场景。<br/>请确保退出 <a href=\"https://obsproject.com/forum/resources/pixel-match-switcher.1202/\"><span style=\" text-decoration: underline; color:#268bd2;\">Pixel Match Switcher</span></a> 以便更好地实现此功能.<br/><br/> 单击高亮显示的加号继续.</p></body></html>"
; Network Tab
AdvSceneSwitcher.networkTab.title="网络"
AdvSceneSwitcher.networkTab.description="此选项卡将允许您远程控制另一个OBS实例的活动场景。\n请注意所有OBS实例上的场景名称必须完全匹配."
AdvSceneSwitcher.networkTab.warning="在本地网络之外运行服务器将允许第三方读取活动场景."
AdvSceneSwitcher.networkTab.DisabledWarning="不幸的是在并行运行obs websocket插件时由于库不兼容不得不在macOS上禁用此功能."
AdvSceneSwitcher.networkTab.server="启动服务器(向所有连接的客户端发送场景切换消息)"
AdvSceneSwitcher.networkTab.server.port="端口"
AdvSceneSwitcher.networkTab.server.lockToIPv4="锁定为仅使用IPv4将服务器"
AdvSceneSwitcher.networkTab.server.sendSceneChange="发送更改场景的消息"
AdvSceneSwitcher.networkTab.server.restrictSendToAutomatedSwitches="仅为自动场景切换发送消息"
AdvSceneSwitcher.networkTab.server.sendPreview="在Studio模式下运行时发送预览场景更改消息"
AdvSceneSwitcher.networkTab.startFailed.message="WebSockets服务器无法启动可能是因为\n-TCP端口%1当前可能正在该系统的其他位置使用可能是由其他应用程序使用。请尝试在WebSocket服务器设置中设置其他TCP端口或停止可能正在使用此端口的任何应用程序。\n-错误消息: %2"
AdvSceneSwitcher.networkTab.server.status.currentStatus="状态"
AdvSceneSwitcher.networkTab.server.status.notRunning="未运行"
AdvSceneSwitcher.networkTab.server.status.starting="启动中"
AdvSceneSwitcher.networkTab.server.status.running="运行中"
AdvSceneSwitcher.networkTab.server.restart="重新启动服务"
AdvSceneSwitcher.networkTab.client="启动客户端(接收场景切换消息)"
AdvSceneSwitcher.networkTab.client.address="主机名或IP地址"
AdvSceneSwitcher.networkTab.client.port="端口"
AdvSceneSwitcher.networkTab.client.status.currentStatus="状态"
AdvSceneSwitcher.networkTab.client.status.disconnected="未连接"
AdvSceneSwitcher.networkTab.client.status.connecting="连接中"
AdvSceneSwitcher.networkTab.client.status.connected="已连接"
AdvSceneSwitcher.networkTab.client.reconnect="强制重新连接"
; Scene Group Tab
AdvSceneSwitcher.sceneGroupTab.title="场景组"
AdvSceneSwitcher.sceneGroupTab.list="场景组"
AdvSceneSwitcher.sceneGroupTab.edit="编辑场景组"
AdvSceneSwitcher.sceneGroupTab.edit.name="名字:"
AdvSceneSwitcher.sceneGroupTab.edit.type="类型: {{type}}"
AdvSceneSwitcher.sceneGroupTab.type.count="计数"
AdvSceneSwitcher.sceneGroupTab.type.time="时间"
AdvSceneSwitcher.sceneGroupTab.type.random="随机"
AdvSceneSwitcher.sceneGroupTab.edit.count="完成后前进到列表中的下一个场景 {{count}} 完全匹配"
AdvSceneSwitcher.sceneGroupTab.edit.time="完成后前进到列表中的下一个场景 {{time}} 过去了"
AdvSceneSwitcher.sceneGroupTab.edit.random="随机选择列表中的下一个场景"
AdvSceneSwitcher.sceneGroupTab.edit.repeat="如果到达“场景结束”列表,则从头开始"
AdvSceneSwitcher.sceneGroupTab.edit.addScene="添加场景"
AdvSceneSwitcher.sceneGroupTab.add="添加场景组"
AdvSceneSwitcher.sceneGroupTab.defaultname="场景组 %1"
AdvSceneSwitcher.sceneGroupTab.exists="场景组或场景名称已存在"
AdvSceneSwitcher.sceneGroupTab.help="可以选择场景组作为目标,就像选择常规场景一样。\n\n名称表明场景组是多个场景的集合。\n场景组将根据配置的设置在其指定场景的列表中前进可以在右侧找到。\n\n您可以将场景组配置为前进到列表中的下一个场景\n在多次选择场景组作为目标后。\n在经过一定时间后。\n也可以是随机的。\n\n例如包含场景的场景组…\n场景1\n场景2\n场景3\n。。。将在第一次选择“场景1”作为目标时激活它。\n第二次将激活“场景2”\n剩余时间将激活“场景3”。\n\n单击下面突出显示的加号以添加新的场景组."
AdvSceneSwitcher.sceneGroupTab.scenes.help="在左侧选择要修改的场景组。\n\n通过选择上面的场景并单击下面的加号选择要添加到此场景组的场景。\n\n可以多次将场景添加到同一场景组."
; Scene Trigger Tab
AdvSceneSwitcher.sceneTriggerTab.title="场景触发器"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.none="--选择触发器--"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneActive="已激活"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneInactive="未激活"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerType.sceneLeave="离开"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.none="--选择动作--"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startRecording="开始录制"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.pauseRecording="暂停录制"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.unpauseRecording="取消暂停录制"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopRecording="停止录制"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopStreaming="停止推流"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startStreaming="开始推流"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startReplayBuffer="启动重播缓冲区"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopReplayBuffer="停止重放缓冲区"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.muteSource="静音源"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.unmuteSource="取消静音源"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startSwitcher="启动场景切换程序"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopSwitcher="停止场景切换"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.startVirtualCamera="启动虚拟摄像机"
AdvSceneSwitcher.sceneTriggerTab.sceneTriggerAction.stopVirtualCamera="停止虚拟摄像机"
AdvSceneSwitcher.sceneTriggerTab.entry="当 {{scenes}} {{triggers}} {{actions}} {{audioSources}} 在 {{duration}} 后"
AdvSceneSwitcher.sceneTriggerTab.help="此选项卡允许您在场景更改时触发操作,如停止录制或流式处理."
; Hotkey
AdvSceneSwitcher.hotkey.startSwitcherHotkey="启动高级场景切换器"
AdvSceneSwitcher.hotkey.stopSwitcherHotkey="停止高级场景切换器"
AdvSceneSwitcher.hotkey.startStopToggleSwitcherHotkey="切换(启动/停止)高级场景切换器"
AdvSceneSwitcher.hotkey.macro.pause="暂停宏 %1"
AdvSceneSwitcher.hotkey.macro.unpause="取消暂停宏 %1"
AdvSceneSwitcher.askBackup="检测到新版本的高级场景切换程序。\n是否要创建旧设置的备份?"
AdvSceneSwitcher.close="关闭"
AdvSceneSwitcher.browse="浏览文件"
AdvSceneSwitcher.selectScene="--选择场景--"
AdvSceneSwitcher.selectPreviousScene="上个场景"
AdvSceneSwitcher.selectCurrentScene="当前场景"
AdvSceneSwitcher.selectAnyScene="任何场景"
AdvSceneSwitcher.currentTransition="当前转场特效"
AdvSceneSwitcher.anyTransition="任何转场特效"
AdvSceneSwitcher.selectTransition="--选择转场特效--"
AdvSceneSwitcher.selectWindow="--选择窗口--"
AdvSceneSwitcher.selectSource="--选择源--"
AdvSceneSwitcher.selectAudioSource="--选择音频源--"
AdvSceneSwitcher.selectVideoSource="--选择视频源--"
AdvSceneSwitcher.selectMediaSource="--选择媒体源--"
AdvSceneSwitcher.selectProcess="--选择进程--"
AdvSceneSwitcher.selectFilter="--select filter--"
AdvSceneSwitcher.selectMacro="--选择宏--"
AdvSceneSwitcher.selectItem="--选择项目--"
AdvSceneSwitcher.enterPath="--输入路径--"
AdvSceneSwitcher.enterText="--输入文本--"
AdvSceneSwitcher.invaildEntriesWillNotBeSaved="无效项将不会被保存"
AdvSceneSwitcher.selectWindowTip="使用 \"OBS\" 来指定OBS窗口\n使用 \"Task Switching\" 来指定 Alt + Tab"
AdvSceneSwitcher.selectWindowTip="使用 \"OBS\" 来指定OBS窗口\n使用 \"任务切换\" 来指定 Alt + Tab"
AdvSceneSwitcher.status.active="运行中"
AdvSceneSwitcher.status.inactive="已停止"
AdvSceneSwitcher.running="插件运行"
AdvSceneSwitcher.stopped="插件停止"
AdvSceneSwitcher.unit.milliseconds="毫秒"
AdvSceneSwitcher.unit.secends="秒"
AdvSceneSwitcher.unit.minutes="分钟"
AdvSceneSwitcher.unit.hours="小时"
AdvSceneSwitcher.duration.condition.none="没有时间限制"
AdvSceneSwitcher.duration.condition.more="时间少于"
AdvSceneSwitcher.duration.condition.equal="时间等于"
AdvSceneSwitcher.duration.condition.less="时间大于"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

1
deps/opencv vendored Submodule

Submodule deps/opencv added at ad6e82942b

1
deps/openvr vendored Submodule

Submodule deps/openvr added at 4c85abcb7f

View File

@@ -1,107 +0,0 @@
# This module can be copied and used by external plugins for OBS
#
# Once done these will be defined:
#
# LIBOBS_FOUND
# LIBOBS_INCLUDE_DIRS
# LIBOBS_LIBRARIES
find_package(PkgConfig QUIET)
if (PKG_CONFIG_FOUND)
pkg_check_modules(_OBS QUIET obs libobs)
endif()
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_lib_suffix 64)
else()
set(_lib_suffix 32)
endif()
if(DEFINED CMAKE_BUILD_TYPE)
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
set(_build_type_base "debug")
else()
set(_build_type_base "release")
endif()
endif()
find_path(LIBOBS_INCLUDE_DIR
NAMES obs.h
HINTS
ENV obsPath${_lib_suffix}
ENV obsPath
${obsPath}
PATHS
/usr/include /usr/local/include /opt/local/include /sw/include
PATH_SUFFIXES
libobs
)
function(find_obs_lib base_name repo_build_path lib_name)
string(TOUPPER "${base_name}" base_name_u)
if(DEFINED _build_type_base)
set(_build_type_${repo_build_path} "${_build_type_base}/${repo_build_path}")
set(_build_type_${repo_build_path}${_lib_suffix} "${_build_type_base}${_lib_suffix}/${repo_build_path}")
endif()
find_library(${base_name_u}_LIB
NAMES ${_${base_name_u}_LIBRARIES} ${lib_name} lib${lib_name}
HINTS
ENV obsPath${_lib_suffix}
ENV obsPath
${obsPath}
${_${base_name_u}_LIBRARY_DIRS}
PATHS
/usr/lib /usr/local/lib /opt/local/lib /sw/lib
PATH_SUFFIXES
lib${_lib_suffix} lib
libs${_lib_suffix} libs
bin${_lib_suffix} bin
../lib${_lib_suffix} ../lib
../libs${_lib_suffix} ../libs
../bin${_lib_suffix} ../bin
# base repo non-msvc-specific search paths
${_build_type_${repo_build_path}}
${_build_type_${repo_build_path}${_lib_suffix}}
build/${repo_build_path}
build${_lib_suffix}/${repo_build_path}
# base repo msvc-specific search paths on windows
build${_lib_suffix}/${repo_build_path}/Debug
build${_lib_suffix}/${repo_build_path}/RelWithDebInfo
build/${repo_build_path}/Debug
build/${repo_build_path}/RelWithDebInfo
)
endfunction()
find_obs_lib(LIBOBS libobs obs)
if(MSVC)
find_obs_lib(W32_PTHREADS deps/w32-pthreads w32-pthreads)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libobs DEFAULT_MSG LIBOBS_LIB LIBOBS_INCLUDE_DIR)
mark_as_advanced(LIBOBS_INCLUDE_DIR LIBOBS_LIB)
if(LIBOBS_FOUND)
if(MSVC)
if (NOT DEFINED W32_PTHREADS_LIB)
message(FATAL_ERROR "Could not find the w32-pthreads library" )
endif()
set(W32_PTHREADS_INCLUDE_DIR ${LIBOBS_INCLUDE_DIR}/../deps/w32-pthreads)
endif()
set(LIBOBS_INCLUDE_DIRS ${LIBOBS_INCLUDE_DIR} ${W32_PTHREADS_INCLUDE_DIR})
set(LIBOBS_LIBRARIES ${LIBOBS_LIB} ${W32_PTHREADS_LIB})
include(${LIBOBS_INCLUDE_DIR}/../cmake/external/ObsPluginHelpers.cmake)
# allows external plugins to easily use/share common dependencies that are often included with libobs (such as FFmpeg)
if(NOT DEFINED INCLUDED_LIBOBS_CMAKE_MODULES)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${LIBOBS_INCLUDE_DIR}/../cmake/Modules/")
set(INCLUDED_LIBOBS_CMAKE_MODULES true)
endif()
else()
message(FATAL_ERROR "Could not find the libobs library" )
endif()

View File

@@ -1,163 +0,0 @@
# Functions for generating external plugins
set(EXTERNAL_PLUGIN_OUTPUT_DIR "${CMAKE_BINARY_DIR}/rundir")
# Fix XCode includes to ignore warnings on system includes
function(target_include_directories_system _target)
if(XCODE)
foreach(_arg ${ARGN})
if("${_arg}" STREQUAL "PRIVATE" OR "${_arg}" STREQUAL "PUBLIC" OR "${_arg}" STREQUAL "INTERFACE")
set(_scope ${_arg})
else()
target_compile_options(${_target} ${_scope} -isystem${_arg})
endif()
endforeach()
else()
target_include_directories(${_target} SYSTEM ${_scope} ${ARGN})
endif()
endfunction()
function(install_external_plugin_data_internal target source_dir target_dir)
install(DIRECTORY ${source_dir}/
DESTINATION "${target}/${target_dir}"
USE_SOURCE_PERMISSIONS)
add_custom_command(TARGET ${target} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${CMAKE_CURRENT_SOURCE_DIR}/${source_dir}" "${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/${target_dir}"
VERBATIM)
endfunction()
# Installs data
# 'target' is the destination target project being installed to
# 'data_loc' specifies the directory of the data
function(install_external_plugin_data target data_loc)
install_external_plugin_data_internal(${target} ${data_loc} "data")
endfunction()
# Installs data in an architecture-specific data directory on windows/linux (data/32bit or data/64bit). Does not apply for mac.
# 'target' is the destination target project being installed to
# 'data_loc' specifies the directory of the data being installed
function(install_external_plugin_arch_data target data_loc)
if(APPLE)
set(_bit_suffix "")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_bit_suffix "/64bit")
else()
set(_bit_suffix "/32bit")
endif()
install_external_plugin_data_internal(${target} ${data_loc} "data${_bit_suffix}")
endfunction()
# Installs data in the target's bin directory
# 'target' is the destination target project being installed to
# 'data_loc' specifies the directory of the data being installed
function(install_external_plugin_data_to_bin target data_loc)
if(APPLE)
set(_bit_suffix "")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_bit_suffix "/64bit")
else()
set(_bit_suffix "/32bit")
endif()
install_external_plugin_data_internal(${target} ${data_loc} "bin${_bit_suffix}")
endfunction()
# Installs an additional binary to a target
# 'target' is the destination target project being installed to
# 'additional_target' specifies the additional binary
function(install_external_plugin_additional target additional_target)
if(APPLE)
set(_bit_suffix "")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_bit_suffix "64bit/")
else()
set(_bit_suffix "32bit/")
endif()
set_target_properties(${additional_target} PROPERTIES
PREFIX "")
install(TARGETS ${additional_target}
LIBRARY DESTINATION "bin"
RUNTIME DESTINATION "bin")
add_custom_command(TARGET ${additional_target} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"$<TARGET_FILE:${additional_target}>"
"${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/bin/${_bit_suffix}$<TARGET_FILE_NAME:${additional_target}>"
VERBATIM)
endfunction()
# Installs the binary of the target
# 'target' is the target project being installed
function(install_external_plugin target)
install_external_plugin_additional(${target} ${target})
endfunction()
# Installs the binary and data of the target
# 'target' is the destination target project being installed to
function(install_external_plugin_with_data target data_loc)
install_external_plugin(${target})
install_external_plugin_data(${target} ${data_loc})
endfunction()
# Installs an additional binary to the data of a target
# 'target' is the destination target project being installed to
# 'additional_target' specifies the additional binary
function(install_external_plugin_bin_to_data target additional_target)
install(TARGETS ${additional_target}
LIBRARY DESTINATION "data"
RUNTIME DESTINATION "data")
add_custom_command(TARGET ${additional_target} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"$<TARGET_FILE:${additional_target}>"
"${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/data/$<TARGET_FILE_NAME:${additional_target}>"
VERBATIM)
endfunction()
# Installs an additional binary in an architecture-specific data directory on windows/linux (data/32bit or data/64bit). Does not apply for mac.
# 'target' is the destination target project being installed to
# 'additional_target' specifies the additional binary
function(install_external_plugin_bin_to_arch_data target additional_target)
if(APPLE)
set(_bit_suffix "")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_bit_suffix "/64bit")
else()
set(_bit_suffix "/32bit")
endif()
install(TARGETS ${additional_target}
LIBRARY DESTINATION "data${_bit_suffix}"
RUNTIME DESTINATION "data${_bit_suffix}")
add_custom_command(TARGET ${additional_target} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"$<TARGET_FILE:${additional_target}>"
"${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/data${_bit_suffix}/$<TARGET_FILE_NAME:${additional_target}>"
VERBATIM)
endfunction()
# Installs an additional file in an architecture-specific data directory on windows/linux (data/32bit or data/64bit). Does not apply for mac.
# 'target' is the destination target project being installed to
# 'additional_target' specifies the additional binary
function(install_external_plugin_data_file_to_arch_data target additional_target file_target)
if(APPLE)
set(_bit_suffix "")
elseif(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_bit_suffix "/64bit")
else()
set(_bit_suffix "/32bit")
endif()
get_filename_component(file_target_name ${file_target} NAME)
install(TARGETS ${additional_target}
LIBRARY DESTINATION "data${_bit_suffix}"
RUNTIME DESTINATION "data${_bit_suffix}")
add_custom_command(TARGET ${additional_target} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy
"${file_target}"
"${EXTERNAL_PLUGIN_OUTPUT_DIR}/$<CONFIGURATION>/${target}/data${_bit_suffix}/${file_target_name}"
VERBATIM)
endfunction()

View File

@@ -56,10 +56,30 @@
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_2">
<layout class="QGridLayout" name="statusLayout">
<item row="4" column="1">
<widget class="QComboBox" name="autoStartEvent"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_64">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.onStartup</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="startupBehavior"/>
</item>
<item row="1" column="0">
<widget class="QWidget" name="placeholder" native="true"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.autoStart</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="checkInterval">
<property name="minimumSize">
@@ -82,6 +102,13 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.hotkeytips</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
@@ -90,66 +117,10 @@
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="toggleStartButton">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.start</string>
</property>
</widget>
<widget class="QWidget" name="placeholder2" native="true"/>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_47">
<item>
<widget class="QLabel" name="pluginRunningText">
<property name="text">
<string>AdvSceneSwitcher.status.inactive</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.hotkeytips</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_64">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.onStartup</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.currentStatus</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>AdvSceneSwitcher.generalTab.status.autoStart</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="autoStartEvent"/>
<widget class="QWidget" name="placeholder3" native="true"/>
</item>
</layout>
</item>
@@ -258,13 +229,6 @@
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_52">
<item>
@@ -313,6 +277,30 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QCheckBox" name="showTrayNotifications">
<property name="text">
<string>AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_48">
<item>
@@ -364,19 +352,6 @@
<item>
<widget class="QListWidget" name="priorityList"/>
</item>
<item>
<spacer name="horizontalSpacer_30">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
@@ -541,6 +516,16 @@
<string>AdvSceneSwitcher.macroTab.macros</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_36">
<item>
<widget class="QLabel" name="macroPriorityWarning">
<property name="text">
<string>AdvSceneSwitcher.macroTab.priorityWarning</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QGridLayout" name="gridLayout_26">
<item row="0" column="0">
@@ -693,13 +678,6 @@
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_65">
<property name="orientation">
@@ -725,7 +703,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_34">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="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">
@@ -736,6 +714,27 @@
<item>
<widget class="QLineEdit" name="macroName"/>
</item>
<item>
<widget class="QPushButton" name="runMacro">
<property name="text">
<string>AdvSceneSwitcher.macroTab.run</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="runMacroInParallel">
<property name="text">
<string>AdvSceneSwitcher.macroTab.runInParallel</string>
</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">
@@ -765,8 +764,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>767</width>
<height>220</height>
<width>792</width>
<height>218</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_35" stretch="10,1">
@@ -864,8 +863,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>767</width>
<height>219</height>
<width>792</width>
<height>218</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_33" stretch="10,1">
@@ -3723,6 +3722,13 @@
<string>AdvSceneSwitcher.networkTab.title</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_30">
<item>
<widget class="QLabel" name="networkTabDescription">
<property name="text">
<string>AdvSceneSwitcher.networkTab.description</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="networkTabWarningLabel">
<property name="text">

View File

@@ -1,17 +1,24 @@
#include <QMainWindow>
#include <QAction>
#include <QFileDialog>
#include <QDirIterator>
#include <regex>
#include <filesystem>
#include <obs-module.h>
#include <obs-frontend-api.h>
#include "headers/advanced-scene-switcher.hpp"
#include "headers/status-control.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
@@ -19,6 +26,7 @@ SwitcherData *switcher = nullptr;
AdvSceneSwitcher::AdvSceneSwitcher(QWidget *parent)
: QDialog(parent), ui(new Ui_AdvSceneSwitcher)
{
switcher->settingsWindowOpened = true;
ui->setupUi(this);
std::lock_guard<std::mutex> lock(switcher->m);
@@ -27,6 +35,13 @@ AdvSceneSwitcher::AdvSceneSwitcher(QWidget *parent)
loadUI();
}
AdvSceneSwitcher::~AdvSceneSwitcher()
{
if (switcher) {
switcher->settingsWindowOpened = false;
}
}
bool translationAvailable()
{
return !!strcmp(obs_module_text("AdvSceneSwitcher.pluginName"),
@@ -36,9 +51,16 @@ bool translationAvailable()
void AdvSceneSwitcher::loadUI()
{
if (!translationAvailable()) {
(void)DisplayMessage(
"Failed to find plug-in's 'data' directory.\n"
"Please check installation instructions!");
QString msg = "Failed to find plug-in's 'data' directory.\n"
"Please check installation instructions!\n\n"
"Data most likely expected at:\n\n";
#ifdef _WIN32
msg += QString::fromStdString(
(std::filesystem::current_path().string()));
msg += "/";
#endif
msg += obs_get_module_data_path(obs_current_module());
(void)DisplayMessage(msg);
}
#if __APPLE__
@@ -65,6 +87,7 @@ void AdvSceneSwitcher::loadUI()
setTabOrder();
restoreWindowGeo();
checkFirstTimeSetup();
loading = false;
}
@@ -72,72 +95,34 @@ void AdvSceneSwitcher::loadUI()
/******************************************************************************
* Saving and loading
******************************************************************************/
void AskBackup(obs_data_t *obj)
{
bool backupSettings = DisplayMessage(
obs_module_text("AdvSceneSwitcher.askBackup"), true);
if (!backupSettings) {
return;
}
QString directory = QFileDialog::getSaveFileName(
nullptr,
obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle"),
QDir::currentPath(),
obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType"));
if (directory.isEmpty()) {
return;
}
QFile file(directory);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return;
}
obs_data_save_json(obj, file.fileName().toUtf8().constData());
}
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
{
if (saving) {
std::lock_guard<std::mutex> lock(switcher->m);
switcher->Prune();
obs_data_t *obj = obs_data_create();
switcher->saveSettings(obj);
obs_data_set_obj(save_data, "advanced-scene-switcher", obj);
obs_data_release(obj);
} else {
switcher->m.lock();
// Stop the scene switcher at least once to
// avoid scene duplication issues with scene collection changes
switcher->Stop();
switcher->m.lock();
obs_data_t *obj =
obs_data_get_obj(save_data, "advanced-scene-switcher");
if (!obj) {
obj = obs_data_create();
}
if (switcher->versionChanged(obj, g_GIT_SHA1)) {
AskBackup(obj);
AskForBackup(obj);
}
switcher->loadSettings(obj);
obs_data_release(obj);
switcher->m.unlock();
// Stop the scene switcher at least once to
// avoid scene duplication issues with scene collection changes
bool start = !switcher->stop;
switcher->Stop();
if (start) {
if (!switcher->stop) {
switcher->Start();
}
}
@@ -166,9 +151,7 @@ void SwitcherData::Thread()
bool setPrevSceneAfterLinger = false;
bool macroMatch = false;
macroSceneSwitched = false;
endTime = std::chrono::high_resolution_clock::now();
auto runTime =
std::chrono::duration_cast<std::chrono::milliseconds>(
endTime - startTime);
@@ -232,12 +215,17 @@ void SwitcherData::Thread()
}
}
// After this point we will call frontend functions
// After this point we will call frontend functions like
// obs_frontend_set_current_scene() and
// obs_frontend_set_current_transition()
//
// During this time SaveSceneSwitcher() could be called
// leading to a deadlock, so we have to unlock()
// leading to a deadlock with the frontend function being stuck
// in QMetaObject::invokeMethod() holding the mutex and
// OBS being stuck in SaveSceneSwitcher().
//
// So we have to unlock() risking race conditions as these are
// less frequent than the above described deadlock
lock.unlock();
if (match) {
@@ -277,6 +265,12 @@ void SwitcherData::setPreconditions()
}
}
currentTitle = title;
// Cursor
std::pair<int, int> cursorPos = getCursorPos();
cursorPosChanged = cursorPos.first != switcher->lastCursorPos.first ||
cursorPos.second != switcher->lastCursorPos.second;
lastCursorPos = getCursorPos();
}
bool SwitcherData::checkForMatch(OBSWeakSource &scene,
@@ -354,8 +348,7 @@ void switchScene(const sceneSwitchInfo &sceneSwitch)
}
obs_source_t *source = obs_weak_source_get_source(sceneSwitch.scene);
obs_source_t *currentSource =
obs_weak_source_get_source(switcher->currentScene);
obs_source_t *currentSource = obs_frontend_get_current_scene();
if (source && source != currentSource) {
transitionData currentTransitionData;
@@ -405,12 +398,18 @@ void SwitcherData::Start()
if (networkConfig.ClientEnabled) {
client.connect(networkConfig.GetClientUri());
}
if (showSystemTrayNotifications) {
DisplayTrayMessage(
obs_module_text("AdvSceneSwitcher.pluginName"),
obs_module_text("AdvSceneSwitcher.running"));
}
}
void ResetMacroCounters()
{
for (auto &m : switcher->macros) {
m.ResetCount();
m->ResetCount();
}
}
@@ -418,8 +417,10 @@ void SwitcherData::Stop()
{
if (th && th->isRunning()) {
stop = true;
transitionCv.notify_one();
cv.notify_one();
cv.notify_all();
abortMacroWait = true;
macroWaitCv.notify_all();
macroTransitionCv.notify_all();
th->wait();
delete th;
th = nullptr;
@@ -430,6 +431,19 @@ void SwitcherData::Stop()
server.stop();
client.disconnect();
for (auto &t : audioHelperThreads) {
if (t.joinable()) {
t.join();
}
}
audioHelperThreads.clear();
if (showSystemTrayNotifications) {
DisplayTrayMessage(
obs_module_text("AdvSceneSwitcher.pluginName"),
obs_module_text("AdvSceneSwitcher.stopped"));
}
}
void SwitcherData::setWaitScene()
@@ -469,6 +483,9 @@ extern "C" void FreeSceneSwitcher()
void handleSceneChange()
{
switcher->lastSceneChangeTime =
std::chrono::high_resolution_clock::now();
// Stop waiting if scene was changed
if (switcher->sceneChangedDuringWait()) {
switcher->cv.notify_one();
@@ -538,6 +555,25 @@ void setReplayBufferSaved()
switcher->replayBufferSaved = true;
}
void setTranstionEnd()
{
switcher->lastTransitionEndTime =
std::chrono::high_resolution_clock::now();
switcher->macroTransitionCv.notify_all();
}
void setStreamStarting()
{
switcher->lastStreamStartingTime =
std::chrono::high_resolution_clock::now();
}
void setStreamStopping()
{
switcher->lastStreamStoppingTime =
std::chrono::high_resolution_clock::now();
}
// Note to future self:
// be careful using switcher->m here as there is potential for deadlocks when using
// frontend functions such as obs_frontend_set_current_scene()
@@ -569,21 +605,60 @@ static void OBSEvent(enum obs_frontend_event event, void *switcher)
case OBS_FRONTEND_EVENT_STREAMING_STOPPED:
resetLiveTime();
break;
#ifdef REPLAYBUFFER_SUPPORTED
case OBS_FRONTEND_EVENT_REPLAY_BUFFER_SAVED:
setReplayBufferSaved();
break;
#endif
case OBS_FRONTEND_EVENT_TRANSITION_STOPPED:
setTranstionEnd();
break;
case OBS_FRONTEND_EVENT_STREAMING_STARTING:
setStreamStarting();
break;
case OBS_FRONTEND_EVENT_STREAMING_STOPPING:
setStreamStopping();
break;
default:
break;
}
}
void LoadPlugins()
{
QFileInfo libPath(
QString(obs_get_module_binary_path(obs_current_module())));
QString pluginDir(libPath.absolutePath() + "/adv-ss-plugins");
#ifdef _WIN32
QString libPattern = "*.dll";
SetDllDirectory(pluginDir.toStdWString().c_str());
#else
QString libPattern = "*.so";
#endif
QDirIterator it(pluginDir, QStringList() << libPattern, QDir::Files);
while (it.hasNext()) {
auto file = it.next();
blog(LOG_INFO, "attempting to load \"%s\"",
file.toStdString().c_str());
auto lib = new QLibrary(file, nullptr);
if (lib->load()) {
blog(LOG_INFO, "successfully loaded \"%s\"",
file.toStdString().c_str());
} else {
blog(LOG_WARNING, "failed to load \"%s\": %s",
file.toStdString().c_str(),
lib->errorString().toStdString().c_str());
}
}
}
AdvSceneSwitcher *ssWindow;
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) {
@@ -591,17 +666,27 @@ extern "C" void InitSceneSwitcher()
}
PlatformInit();
LoadPlugins();
SetupDock();
auto cb = []() {
QMainWindow *window =
(QMainWindow *)obs_frontend_get_main_window();
AdvSceneSwitcher ss(window);
ss.exec();
if (switcher->settingsWindowOpened) {
ssWindow->show();
ssWindow->raise();
ssWindow->activateWindow();
} else {
ssWindow =
new AdvSceneSwitcher(static_cast<QMainWindow *>(
obs_frontend_get_main_window()));
ssWindow->setAttribute(Qt::WA_DeleteOnClose);
ssWindow->show();
}
};
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

@@ -46,6 +46,13 @@ double Duration::TimeRemaining()
return (seconds * 1000 - runTime.count()) / 1000.;
}
void Duration::SetTimeRemaining(double remaining)
{
long long msPassed = (seconds - remaining) * 1000;
_startTime = std::chrono::high_resolution_clock::now() -
std::chrono::milliseconds(msPassed);
}
void Duration::Reset()
{
_startTime = {};

View File

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

View File

@@ -0,0 +1,51 @@
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}/adv-ss-plugins)
endif()
else()
target_link_libraries(
advanced-scene-switcher-opencv
advanced-scene-switcher
obs-frontend-api
${OpenCV_LIBRARIES}
Qt5::Core
Qt5::Widgets
libobs)
install_advss_plugin(advanced-scene-switcher-opencv)
endif()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,184 @@
#pragma once
#include <macro.hpp>
#include <screenshot-helper.hpp>
#include <file-selection.hpp>
#include <QWidget>
#include <QComboBox>
#include <QCheckBox>
#include <QHBoxLayout>
#include <chrono>
#undef NO // MacOS macro that can conflict with OpenCV
#include <opencv2/opencv.hpp>
enum class VideoCondition {
MATCH,
DIFFER,
HAS_NOT_CHANGED,
HAS_CHANGED,
NO_IMAGE,
PATTERN,
OBJECT,
};
struct PatternMatchData {
cv::Mat4b rgbaPattern;
cv::Mat3b rgbPattern;
cv::Mat1b mask;
};
constexpr int minMinNeighbors = 3;
constexpr int maxMinNeighbors = 6;
class MacroConditionVideo : public MacroCondition {
public:
MacroConditionVideo(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
QImage GetMatchImage() { return _matchImage; };
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionVideo>(m);
}
void GetScreenshot();
bool LoadImageFromFile();
bool LoadModelData(std::string &path);
std::string GetModelDataPath() { return _modelDataPath; }
void ResetLastMatch() { _lastMatchResult = false; }
OBSWeakSource _videoSource;
VideoCondition _condition = VideoCondition::MATCH;
std::string _file = obs_module_text("AdvSceneSwitcher.enterPath");
bool _useAlphaAsMask = false;
bool _usePatternForChangedCheck = false;
PatternMatchData _patternData;
double _patternThreshold = 0.8;
cv::CascadeClassifier _objectCascade;
double _scaleFactor = 1.1;
int _minNeighbors = minMinNeighbors;
int _minSizeX = 0;
int _minSizeY = 0;
int _maxSizeX = 0;
int _maxSizeY = 0;
bool _throttleEnabled = false;
int _throttleCount = 3;
private:
bool OutputChanged();
bool ScreenshotContainsPattern();
bool ScreenshotContainsObject();
bool Compare();
bool CheckShouldBeSkipped();
std::unique_ptr<AdvSSScreenshotObj> _screenshotData = nullptr;
QImage _matchImage;
std::string _modelDataPath =
obs_get_module_data_path(obs_current_module()) +
std::string(
"/res/cascadeClassifiers/haarcascade_frontalface_alt.xml");
bool _lastMatchResult = false;
int _runCount = 0;
static bool _registered;
static const std::string id;
};
class ThresholdSlider : public QWidget {
Q_OBJECT
public:
ThresholdSlider(double min = 0., double max = 1.,
const QString &label = "threshold",
const QString &description = "", QWidget *parent = 0);
void SetDoubleValue(double);
public slots:
void NotifyValueChanged(int value);
signals:
void DoubleValueChanged(double value);
private:
void SetDoubleValueText(double);
QLabel *_value;
QSlider *_slider;
double _scale = 100.0;
int _precision = 2;
};
class MacroConditionVideoEdit : public QWidget {
Q_OBJECT
public:
MacroConditionVideoEdit(
QWidget *parent,
std::shared_ptr<MacroConditionVideo> cond = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroCondition> cond)
{
return new MacroConditionVideoEdit(
parent,
std::dynamic_pointer_cast<MacroConditionVideo>(cond));
}
void UpdatePreviewTooltip();
private slots:
void SourceChanged(const QString &text);
void ConditionChanged(int cond);
void ImagePathChanged(const QString &text);
void ImageBrowseButtonClicked();
void UsePatternForChangedCheckChanged(int value);
void PatternThresholdChanged(double);
void UseAlphaAsMaskChanged(int value);
void ModelPathChanged(const QString &text);
void ObjectScaleThresholdChanged(double);
void MinNeighborsChanged(int value);
void MinSizeXChanged(int value);
void MinSizeYChanged(int value);
void MaxSizeXChanged(int value);
void MaxSizeYChanged(int value);
void ThrottleEnableChanged(int value);
void ThrottleCountChanged(int value);
void ShowMatchClicked();
signals:
void HeaderInfoChanged(const QString &);
protected:
QComboBox *_videoSelection;
QComboBox *_condition;
QCheckBox *_usePatternForChangedCheck;
FileSelection *_imagePath;
ThresholdSlider *_patternThreshold;
QCheckBox *_useAlphaAsMask;
FileSelection *_modelDataPath;
QHBoxLayout *_modelPathLayout;
ThresholdSlider *_objectScaleThreshold;
QHBoxLayout *_neighborsControlLayout;
QSpinBox *_minNeighbors;
QLabel *_minNeighborsDescription;
QHBoxLayout *_minSizeControlLayout;
QSpinBox *_minSizeX;
QSpinBox *_minSizeY;
QHBoxLayout *_maxSizeControlLayout;
QSpinBox *_maxSizeX;
QSpinBox *_maxSizeY;
QHBoxLayout *_throttleControlLayout;
QCheckBox *_throttleEnable;
QSpinBox *_throttleCount;
QPushButton *_showMatch;
std::shared_ptr<MacroConditionVideo> _entryData;
private:
void SetWidgetVisibility();
bool _loading = true;
};

View File

@@ -0,0 +1,90 @@
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}/adv-ss-plugins)
endif()
else()
target_link_libraries(
advanced-scene-switcher-openvr
advanced-scene-switcher
obs-frontend-api
${OpenVR_LIBRARIES}
Qt5::Core
Qt5::Widgets
libobs)
install_advss_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,69 @@
#pragma once
#include <macro.hpp>
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QPushButton>
#include <QTimer>
class MacroConditionOpenVR : public MacroCondition {
public:
MacroConditionOpenVR(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionOpenVR>(m);
}
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;
};

49
src/file-selection.cpp Normal file
View File

@@ -0,0 +1,49 @@
#include "headers/file-selection.hpp"
#include <obs-module.h>
#include <QLayout>
#include <QFileDialog>
FileSelection::FileSelection(FileSelection::Type type, QWidget *parent)
: QWidget(parent), _type(type)
{
_filePath = new QLineEdit();
_browseButton =
new QPushButton(obs_module_text("AdvSceneSwitcher.browse"));
QWidget::connect(_filePath, SIGNAL(editingFinished()), this,
SLOT(PathChange()));
QWidget::connect(_browseButton, SIGNAL(clicked()), this,
SLOT(BrowseButtonClicked()));
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(_filePath);
layout->addWidget(_browseButton);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
}
void FileSelection::SetPath(const QString &path)
{
_filePath->setText(path);
}
void FileSelection::BrowseButtonClicked()
{
QString path;
if (_type == FileSelection::Type::WRITE) {
path = QFileDialog::getSaveFileName(this);
} else {
path = QFileDialog::getOpenFileName(this);
}
if (path.isEmpty()) {
return;
}
_filePath->setText(path);
emit PathChanged(path);
}
void FileSelection::PathChange()
{
emit PathChanged(_filePath->text());
}

View File

@@ -1,14 +1,19 @@
#include "headers/advanced-scene-switcher.hpp"
#include "headers/status-control.hpp"
#include "headers/utility.hpp"
#include "headers/version.h"
#include <QFileDialog>
QMetaObject::Connection inactivePluse;
#include <QStandardPaths>
void AdvSceneSwitcher::on_close_clicked()
{
done(0);
close();
}
void AdvSceneSwitcher::reject()
{
close();
}
void AdvSceneSwitcher::UpdateNonMatchingScene(const QString &name)
@@ -140,43 +145,11 @@ void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
switcher->interval = value;
}
void AdvSceneSwitcher::SetStarted()
{
ui->toggleStartButton->setText(
obs_module_text("AdvSceneSwitcher.generalTab.status.stop"));
ui->pluginRunningText->setText(
obs_module_text("AdvSceneSwitcher.status.active"));
ui->pluginRunningText->disconnect(inactivePluse);
currentStatusActive = true;
}
void AdvSceneSwitcher::SetStopped()
{
ui->toggleStartButton->setText(
obs_module_text("AdvSceneSwitcher.generalTab.status.start"));
ui->pluginRunningText->setText(
obs_module_text("AdvSceneSwitcher.status.inactive"));
if (!switcher->disableHints) {
inactivePluse = PulseWidget(ui->pluginRunningText,
QColor(Qt::red), QColor(0, 0, 0, 0),
"QLabel ");
}
currentStatusActive = false;
}
void AdvSceneSwitcher::on_toggleStartButton_clicked()
{
if (switcher->th && switcher->th->isRunning()) {
switcher->Stop();
SetStopped();
} else {
switcher->Start();
SetStarted();
}
}
void AdvSceneSwitcher::closeEvent(QCloseEvent *)
{
if (!switcher) {
return;
}
switcher->windowPos = this->pos();
switcher->windowSize = this->size();
@@ -201,6 +174,15 @@ void AdvSceneSwitcher::on_saveWindowGeo_stateChanged(int state)
switcher->saveWindowGeo = state;
}
void AdvSceneSwitcher::on_showTrayNotifications_stateChanged(int state)
{
if (loading) {
return;
}
switcher->showSystemTrayNotifications = state;
}
void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
{
if (loading) {
@@ -210,13 +192,53 @@ void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
switcher->disableHints = state;
}
QString getDefaultSaveLocation()
{
QString desktopPath = QStandardPaths::writableLocation(
QStandardPaths::DesktopLocation);
auto scName = obs_frontend_get_current_scene_collection();
QString sceneCollectionName(scName);
bfree(scName);
auto timestamp = QDateTime::currentDateTime();
return desktopPath + "/adv-ss-" + sceneCollectionName + "-" +
timestamp.toString("yyyy.MM.dd.hh.mm.ss");
}
void AskForBackup(obs_data_t *obj)
{
bool backupSettings = DisplayMessage(
obs_module_text("AdvSceneSwitcher.askBackup"), true);
if (!backupSettings) {
return;
}
QString path = QFileDialog::getSaveFileName(
nullptr,
obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle"),
getDefaultSaveLocation(),
obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType"));
if (path.isEmpty()) {
return;
}
QFile file(path);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return;
}
obs_data_save_json(obj, file.fileName().toUtf8().constData());
}
void AdvSceneSwitcher::on_exportSettings_clicked()
{
QString directory = QFileDialog::getSaveFileName(
this,
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle")),
QDir::currentPath(),
getDefaultSaveLocation(),
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType")));
if (directory.isEmpty()) {
@@ -379,12 +401,20 @@ void AdvSceneSwitcher::setTabOrder()
void AdvSceneSwitcher::restoreWindowGeo()
{
if (switcher->saveWindowGeo) {
if (switcher->saveWindowGeo && windowPosValid(switcher->windowPos)) {
this->resize(switcher->windowSize);
this->move(switcher->windowPos);
}
}
void AdvSceneSwitcher::checkFirstTimeSetup()
{
if (switcher->firstBoot && !switcher->disableHints) {
DisplayMessage(
obs_module_text("AdvSceneSwitcher.firstBootMessage"));
}
}
void AdvSceneSwitcher::on_tabMoved(int from, int to)
{
if (loading) {
@@ -394,10 +424,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();
@@ -480,6 +508,8 @@ void SwitcherData::saveGeneralSettings(obs_data_t *obj)
static_cast<int>(autoStartEvent));
obs_data_set_bool(obj, "verbose", verbose);
obs_data_set_bool(obj, "showSystemTrayNotifications",
showSystemTrayNotifications);
obs_data_set_bool(obj, "disableHints", disableHints);
obs_data_set_int(obj, "priority0", functionNamesByPriority[0]);
@@ -551,6 +581,8 @@ void SwitcherData::loadGeneralSettings(obs_data_t *obj)
obs_data_get_int(obj, "autoStartEvent"));
verbose = obs_data_get_bool(obj, "verbose");
showSystemTrayNotifications =
obs_data_get_bool(obj, "showSystemTrayNotifications");
disableHints = obs_data_get_bool(obj, "disableHints");
obs_data_set_default_int(obj, "priority0", default_priority_0);
@@ -720,21 +752,6 @@ void populateAutoStartEventSelection(QComboBox *cb)
"AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming"));
}
void AdvSceneSwitcher::updateStatus()
{
if (switcher->th && switcher->th->isRunning()) {
if (currentStatusActive) {
return;
}
SetStarted();
} else {
if (!currentStatusActive) {
return;
}
SetStopped();
}
}
void AdvSceneSwitcher::setupGeneralTab()
{
populateSceneSelection(ui->noMatchSwitchScene, false);
@@ -777,6 +794,8 @@ void AdvSceneSwitcher::setupGeneralTab()
ui->verboseLogging->setChecked(switcher->verbose);
ui->saveWindowGeo->setChecked(switcher->saveWindowGeo);
ui->showTrayNotifications->setChecked(
switcher->showSystemTrayNotifications);
ui->uiHintsDisable->setChecked(switcher->disableHints);
for (int p : switcher->functionNamesByPriority) {
@@ -853,15 +872,17 @@ void AdvSceneSwitcher::setupGeneralTab()
ui->autoStartEvent->setCurrentIndex(
static_cast<int>(switcher->autoStartEvent));
if (switcher->th && switcher->th->isRunning()) {
SetStarted();
} else {
SetStopped();
}
// Set up status control
auto statusControl = new StatusControl(this, true);
ui->statusLayout->addWidget(statusControl->StatusPrefixLabel(), 1, 0);
auto tmp = new QHBoxLayout;
tmp->addWidget(statusControl->StatusLabel());
tmp->addStretch();
ui->statusLayout->addLayout(tmp, 1, 1);
ui->statusLayout->addWidget(statusControl->Button(), 2, 1);
// Hide the now empty invisible shell of the statusControl widget
// as otherwise it could block user input
statusControl->hide();
// Updates the UI status element if the status changed externally
// (e.g. via hotkeys)
QTimer *statusTimer = new QTimer(this);
connect(statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
statusTimer->start(1000);
setWindowTitle(windowTitle() + " - " + g_GIT_TAG);
}

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
@@ -14,6 +16,8 @@
}
class QCloseEvent;
class MacroActionEdit;
class MacroConditionEdit;
/*******************************************************************************
* Advanced Scene Switcher window
@@ -24,15 +28,13 @@ class AdvSceneSwitcher : public QDialog {
public:
std::unique_ptr<Ui_AdvSceneSwitcher> ui;
bool loading = true;
bool currentStatusActive = false;
AdvSceneSwitcher(QWidget *parent);
~AdvSceneSwitcher();
void reject() override;
void closeEvent(QCloseEvent *event) override;
void SetStarted();
void SetStopped();
void SetShowFrames();
void SetHideFrames();
void clearFrames(QListWidget *list);
@@ -47,6 +49,14 @@ public:
bool addNewMacro(std::string &name);
Macro *getSelectedMacro();
void SetEditMacro(Macro &m);
void HighlightAction(int idx);
void HighlightCondition(int idx);
void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0);
void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0);
void ConnectControlSignals(MacroActionEdit *);
void ConnectControlSignals(MacroConditionEdit *);
void SwapActions(Macro *m, int pos1, int pos2);
void SwapConditions(Macro *m, int pos1, int pos2);
void loadUI();
void setupGeneralTab();
@@ -69,6 +79,7 @@ public:
void setupMacroTab();
void setTabOrder();
void restoreWindowGeo();
void checkFirstTimeSetup();
signals:
void MacroAdded(const QString &name);
@@ -94,7 +105,6 @@ public slots:
void on_autoStartEvent_currentIndexChanged(int index);
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
void on_checkInterval_valueChanged(int value);
void on_toggleStartButton_clicked();
void on_tabMoved(int from, int to);
void on_tabWidget_currentChanged(int index);
@@ -103,14 +113,31 @@ public slots:
void on_macroUp_clicked();
void on_macroDown_clicked();
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();
void on_conditionRemove_clicked();
void on_actionAdd_clicked();
void on_actionRemove_clicked();
void showMacroContextMenu(const QPoint &);
void copyMacro();
void ShowMacroContextMenu(const QPoint &);
void ShowMacroActionsContextMenu(const QPoint &);
void ShowMacroConditionsContextMenu(const QPoint &);
void CopyMacro();
void ExpandAllActions();
void ExpandAllConditions();
void CollapseAllActions();
void CollapseAllConditions();
void AddMacroAction(int idx);
void RemoveMacroAction(int idx);
void MoveMacroActionUp(int idx);
void MoveMacroActionDown(int idx);
void AddMacroCondition(int idx);
void RemoveMacroCondition(int idx);
void MoveMacroConditionUp(int idx);
void MoveMacroConditionDown(int idx);
void on_screenRegionSwitches_currentRowChanged(int idx);
void on_showFrame_clicked();
@@ -139,6 +166,7 @@ public slots:
void on_verboseLogging_stateChanged(int state);
void on_saveWindowGeo_stateChanged(int state);
void on_showTrayNotifications_stateChanged(int state);
void on_uiHintsDisable_stateChanged(int state);
void on_exportSettings_clicked();
@@ -239,7 +267,6 @@ public slots:
void on_threadPriority_currentTextChanged(const QString &text);
void updateScreenRegionCursorPos();
void updateStatus();
void on_close_clicked();
@@ -258,8 +285,14 @@ void restoreTransitionOverride(obs_source_t *scene, const transitionData &td);
void switchScene(const sceneSwitchInfo &ssi);
void switchPreviewScene(const OBSWeakSource &ws);
/******************************************************************************
* Settings helper
******************************************************************************/
void AskForBackup(obs_data_t *obj);
/******************************************************************************
* Main SwitcherData
******************************************************************************/
struct SwitcherData;
extern SwitcherData *switcher;
SwitcherData *GetSwitcher();

View File

@@ -22,6 +22,7 @@ public:
bool DurationReached();
double TimeRemaining();
void SetTimeRemaining(double);
void Reset();
std::string ToString();
@@ -41,6 +42,7 @@ public:
void SetValue(double value);
void SetUnit(DurationUnit u);
void SetDuration(Duration d);
QDoubleSpinBox *SpinBox() { return _duration; }
private slots:
void _DurationChanged(double value);

View File

@@ -0,0 +1,30 @@
#pragma once
#include <QLineEdit>
#include <QPushButton>
#include <QWidget>
class FileSelection : public QWidget {
Q_OBJECT
public:
enum class Type {
READ,
WRITE,
};
FileSelection(FileSelection::Type type = FileSelection::Type::READ,
QWidget *parent = 0);
void SetPath(const QString &);
QPushButton *Button() { return _browseButton; }
private slots:
void BrowseButtonClicked();
void PathChange();
signals:
void PathChanged(const QString &);
private:
Type _type;
QLineEdit *_filePath;
QPushButton *_browseButton;
};

View File

@@ -1,6 +1,10 @@
#pragma once
#include <QSpinBox>
#include "macro-action-edit.hpp"
#include "duration-control.hpp"
#include <QSpinBox>
#include <QCheckBox>
#include <QHBoxLayout>
enum class AudioAction {
MUTE,
@@ -11,20 +15,23 @@ enum class AudioAction {
class MacroActionAudio : public MacroAction {
public:
MacroActionAudio(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionAudio>();
return std::make_shared<MacroActionAudio>(m);
}
OBSWeakSource _audioSource;
AudioAction _action = AudioAction::MUTE;
int _volume = 0;
bool _fade = false;
Duration _duration;
private:
static bool _registered;
@@ -52,6 +59,8 @@ private slots:
void SourceChanged(const QString &text);
void ActionChanged(int value);
void VolumeChanged(int value);
void FadeChanged(int value);
void DurationChanged(double seconds);
signals:
void HeaderInfoChanged(const QString &);
@@ -59,9 +68,11 @@ protected:
QComboBox *_audioSources;
QComboBox *_actions;
QSpinBox *_volumePercent;
QCheckBox *_fade;
DurationSelection *_duration;
QHBoxLayout *_fadeLayout;
std::shared_ptr<MacroActionAudio> _entryData;
private:
QHBoxLayout *_mainLayout;
bool _loading = true;
};

View File

@@ -1,20 +1,12 @@
#pragma once
#include <QWidget>
#include <QComboBox>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QLabel>
#include <deque>
#include "macro.hpp"
#include "section.hpp"
struct MacroActionInfo {
using TCreateMethod = std::shared_ptr<MacroAction> (*)();
using TCreateMethod = std::shared_ptr<MacroAction> (*)(Macro *m);
using TCreateWidgetMethod = QWidget *(*)(QWidget *parent,
std::shared_ptr<MacroAction>);
TCreateMethod _createFunc;
TCreateWidgetMethod _createWidgetFunc;
TCreateMethod _createFunc = nullptr;
TCreateWidgetMethod _createWidgetFunc = nullptr;
std::string _name;
};
@@ -22,7 +14,8 @@ class MacroActionFactory {
public:
MacroActionFactory() = delete;
static bool Register(const std::string &id, MacroActionInfo);
static std::shared_ptr<MacroAction> Create(const std::string &id);
static std::shared_ptr<MacroAction> Create(const std::string &id,
Macro *m);
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
std::shared_ptr<MacroAction> action);
static auto GetActionTypes() { return _methods; }
@@ -33,34 +26,23 @@ private:
static std::map<std::string, MacroActionInfo> _methods;
};
class MacroActionEdit : public QWidget {
class MacroActionEdit : public MacroSegmentEdit {
Q_OBJECT
public:
MacroActionEdit(QWidget *parent = nullptr,
std::shared_ptr<MacroAction> * = nullptr,
const std::string &id = "scene_switch",
bool startCollapsed = false);
void UpdateEntryData(const std::string &id, bool collapse);
const std::string &id = "scene_switch");
void UpdateEntryData(const std::string &id);
private slots:
void ActionSelectionChanged(const QString &text);
void HeaderInfoChanged(const QString &);
signals:
void MacroAdded(const QString &name);
void MacroRemoved(const QString &name);
void MacroRenamed(const QString &oldName, const QString newName);
void SceneGroupAdded(const QString &name);
void SceneGroupRemoved(const QString &name);
void SceneGroupRenamed(const QString &oldName, const QString newName);
protected:
QComboBox *_actionSelection;
Section *_section;
QLabel *_headerInfo;
std::shared_ptr<MacroAction> *_entryData;
private:
MacroSegment *Data();
QComboBox *_actionSelection;
std::shared_ptr<MacroAction> *_entryData;
bool _loading = true;
};

View File

@@ -2,6 +2,7 @@
#include <QSpinBox>
#include <QPlainTextEdit>
#include "macro-action-edit.hpp"
#include "file-selection.hpp"
enum class FileAction {
WRITE,
@@ -10,15 +11,16 @@ enum class FileAction {
class MacroActionFile : public MacroAction {
public:
MacroActionFile(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionFile>();
return std::make_shared<MacroActionFile>(m);
}
std::string _file = obs_module_text("AdvSceneSwitcher.enterPath");
@@ -47,16 +49,14 @@ public:
}
private slots:
void FilePathChanged();
void BrowseButtonClicked();
void PathChanged(const QString &text);
void TextChanged();
void ActionChanged(int value);
signals:
void HeaderInfoChanged(const QString &);
protected:
QLineEdit *_filePath;
QPushButton *_browseButton;
FileSelection *_filePath;
QPlainTextEdit *_text;
QComboBox *_actions;
std::shared_ptr<MacroActionFile> _entryData;

View File

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

View File

@@ -3,17 +3,20 @@
#include "hotkey.hpp"
#include <QCheckBox>
#include <QSpinBox>
#include <QHBoxLayout>
class MacroActionHotkey : public MacroAction {
public:
MacroActionHotkey(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionHotkey>();
return std::make_shared<MacroActionHotkey>(m);
}
OBSWeakSource _HotkeySource;
@@ -26,6 +29,12 @@ public:
bool _rightAlt = false;
bool _leftMeta = false;
bool _rightMeta = false;
int _duration = 300; // in ms
#ifdef __APPLE__
bool _onlySendToObs = true;
#else
bool _onlySendToObs = false;
#endif
private:
static bool _registered;
@@ -58,6 +67,8 @@ private slots:
void RAltChanged(int state);
void LMetaChanged(int state);
void RMetaChanged(int state);
void DurationChanged(int ms);
void OnlySendToOBSChanged(int state);
protected:
QComboBox *_keys;
@@ -69,10 +80,14 @@ protected:
QCheckBox *_rightAlt;
QCheckBox *_leftMeta;
QCheckBox *_rightMeta;
QSpinBox *_duration;
QCheckBox *_onlySendToOBS;
QLabel *_noKeyPressSimulationWarning;
std::shared_ptr<MacroActionHotkey> _entryData;
private:
void SetWarningVisibility();
QHBoxLayout *_mainLayout;
bool _loading = true;
};

View File

@@ -1,25 +1,29 @@
#pragma once
#include <QDoubleSpinBox>
#include "macro-action-edit.hpp"
#include "macro-selection.hpp"
#include <QHBoxLayout>
enum class PerformMacroAction {
PAUSE,
UNPAUSE,
RESET_COUNTER,
RUN,
STOP,
};
class MacroActionMacro : public MacroRefAction {
public:
MacroActionMacro(Macro *m) : MacroRefAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionMacro>();
return std::make_shared<MacroActionMacro>(m);
}
PerformMacroAction _action = PerformMacroAction::PAUSE;

View File

@@ -1,7 +1,9 @@
#pragma once
#include <QSpinBox>
#include "macro-action-edit.hpp"
#include <QSpinBox>
#include <QHBoxLayout>
enum class MediaAction {
PLAY,
PAUSE,
@@ -13,15 +15,16 @@ enum class MediaAction {
class MacroActionMedia : public MacroAction {
public:
MacroActionMedia(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionMedia>();
return std::make_shared<MacroActionMedia>(m);
}
OBSWeakSource _mediaSource;

View File

@@ -1,26 +1,32 @@
#pragma once
#include <QDoubleSpinBox>
#include "macro-action-edit.hpp"
#include "file-selection.hpp"
#include <QDoubleSpinBox>
#include <QLabel>
enum class PluginStateAction {
STOP,
NO_MATCH_BEHAVIOUR,
IMPORT_SETTINGS,
};
class MacroActionPluginState : public MacroAction {
public:
MacroActionPluginState(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionPluginState>();
return std::make_shared<MacroActionPluginState>(m);
}
PluginStateAction _action = PluginStateAction::STOP;
int _value = 0;
std::string _settingsPath;
OBSWeakSource _scene;
private:
@@ -49,15 +55,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,55 @@
#pragma once
#include "macro-action-edit.hpp"
#include "scene-selection.hpp"
class MacroActionPreviewScene : public MacroAction {
public:
MacroActionPreviewScene(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionPreviewScene>(m);
}
SceneSelection _scene;
private:
static bool _registered;
static const std::string id;
};
class MacroActionPreviewSceneEdit : public QWidget {
Q_OBJECT
public:
MacroActionPreviewSceneEdit(
QWidget *parent,
std::shared_ptr<MacroActionPreviewScene> entryData = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionPreviewSceneEdit(
parent,
std::dynamic_pointer_cast<MacroActionPreviewScene>(
action));
}
private slots:
void SceneChanged(const SceneSelection &);
signals:
void HeaderInfoChanged(const QString &);
protected:
SceneSelectionWidget *_scenes;
std::shared_ptr<MacroActionPreviewScene> _entryData;
private:
QHBoxLayout *_mainLayout;
bool _loading = true;
};

View File

@@ -0,0 +1,52 @@
#pragma once
#include "macro-action-edit.hpp"
class MacroActionProfile : public MacroAction {
public:
MacroActionProfile(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionProfile>(m);
}
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,64 @@
#pragma once
#include "macro-action-edit.hpp"
#include "macro-selection.hpp"
#include <QPushButton>
#include <QListWidget>
#include <unordered_map>
class MacroActionRandom : public MultiMacroRefAction {
public:
MacroActionRandom(Macro *m) : MultiMacroRefAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionRandom>(m);
}
// TODO: add weights to each macro ...
// std::unordered_map<MacroRef, int> _weights;
private:
MacroRef lastRandomMacro;
static bool _registered;
static const std::string id;
};
class MacroActionRandomEdit : public QWidget {
Q_OBJECT
public:
MacroActionRandomEdit(
QWidget *parent,
std::shared_ptr<MacroActionRandom> entryData = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionRandomEdit(
parent,
std::dynamic_pointer_cast<MacroActionRandom>(action));
}
private slots:
void MacroRemove(const QString &name);
void MacroRename(const QString &oldName, const QString &newName);
void AddMacro();
void RemoveMacro();
protected:
std::shared_ptr<MacroActionRandom> _entryData;
private:
int FindEntry(const std::string &macro);
void SetMacroListSize();
QListWidget *_macroList;
QPushButton *_add;
QPushButton *_remove;
bool _loading = true;
};

View File

@@ -1,8 +1,9 @@
#pragma once
#include <QDoubleSpinBox>
#include <QLabel>
#include "macro-action-edit.hpp"
#include <QComboBox>
#include <QHBoxLayout>
enum class RecordAction {
STOP,
START,
@@ -12,14 +13,15 @@ enum class RecordAction {
class MacroActionRecord : public MacroAction {
public:
MacroActionRecord(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionRecord>();
return std::make_shared<MacroActionRecord>(m);
}
RecordAction _action = RecordAction::STOP;

View File

@@ -1,8 +1,11 @@
#ifdef REPLAYBUFFER_SUPPORTED
#pragma once
#include <QDoubleSpinBox>
#include "macro-action-edit.hpp"
#include "duration-control.hpp"
#include <QHBoxLayout>
enum class ReplayBufferAction {
STOP,
START,
@@ -11,14 +14,15 @@ enum class ReplayBufferAction {
class MacroActionReplayBuffer : public MacroAction {
public:
MacroActionReplayBuffer(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionReplayBuffer>();
return std::make_shared<MacroActionReplayBuffer>(m);
}
ReplayBufferAction _action = ReplayBufferAction::STOP;
@@ -64,3 +68,5 @@ private:
QHBoxLayout *_mainLayout;
bool _loading = true;
};
#endif

View File

@@ -1,5 +1,6 @@
#pragma once
#include "macro-action-edit.hpp"
#include "file-selection.hpp"
#include <QLineEdit>
#include <QPushButton>
@@ -8,15 +9,16 @@
class MacroActionRun : public MacroAction {
public:
MacroActionRun(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionRun>();
return std::make_shared<MacroActionRun>(m);
}
std::string _path = obs_module_text("AdvSceneSwitcher.enterPath");
@@ -43,8 +45,7 @@ public:
}
private slots:
void FilePathChanged();
void BrowseButtonClicked();
void PathChanged(const QString &text);
void AddArg();
void RemoveArg();
void ArgUp();
@@ -56,8 +57,9 @@ protected:
std::shared_ptr<MacroActionRun> _entryData;
private:
QLineEdit *_filePath;
QPushButton *_browseButton;
void SetArgListSize();
FileSelection *_filePath;
QListWidget *_argList;
QPushButton *_addArg;
QPushButton *_removeArg;

View File

@@ -0,0 +1,53 @@
#pragma once
#include "macro-action-edit.hpp"
class MacroActionSceneCollection : public MacroAction {
public:
MacroActionSceneCollection(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSceneCollection>(m);
}
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,
@@ -13,19 +15,20 @@ enum class SceneOrderAction {
class MacroActionSceneOrder : public MacroAction {
public:
MacroActionSceneOrder(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSceneOrder>();
return std::make_shared<MacroActionSceneOrder>(m);
}
SceneSelection _scene;
OBSWeakSource _source;
SceneItemSelection _source;
SceneOrderAction _action = SceneOrderAction::MOVE_UP;
int _position = 0;
@@ -53,7 +56,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 +64,7 @@ signals:
protected:
SceneSelectionWidget *_scenes;
QComboBox *_sources;
SceneItemSelectionWidget *_sources;
QComboBox *_actions;
QSpinBox *_position;
std::shared_ptr<MacroActionSceneOrder> _entryData;

View File

@@ -0,0 +1,39 @@
#pragma once
#include "macro-action-edit.hpp"
class MacroActionSceneSwap : public MacroAction {
public:
MacroActionSceneSwap(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSceneSwap>(m);
}
private:
static bool _registered;
static const std::string id;
};
class MacroActionSceneSwapEdit : public QWidget {
Q_OBJECT
public:
MacroActionSceneSwapEdit(
QWidget *parent,
std::shared_ptr<MacroActionSceneSwap> entryData = nullptr);
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionSceneSwapEdit(
parent, std::dynamic_pointer_cast<MacroActionSceneSwap>(
action));
}
protected:
std::shared_ptr<MacroActionSceneSwap> _entryData;
};

View File

@@ -1,12 +1,14 @@
#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:
MacroActionSwitchScene(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
@@ -14,11 +16,14 @@ public:
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSwitchScene>();
return std::make_shared<MacroActionSwitchScene>(m);
}
SceneSelection _scene;
TransitionSelection _transition;
Duration _duration;
bool _blockUntilTransitionDone = true;
private:
const char *getType() { return "MacroActionSwitchScene"; }
@@ -27,7 +32,7 @@ private:
static const std::string id;
};
class MacroActionSwitchSceneEdit : public SwitchWidget {
class MacroActionSwitchSceneEdit : public QWidget {
Q_OBJECT
public:
@@ -44,12 +49,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,28 +1,31 @@
#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:
MacroActionSceneTransform(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSceneTransform>();
return std::make_shared<MacroActionSceneTransform>(m);
}
std::string GetSettings();
void SetSettings(std::string &);
SceneSelection _scene;
OBSWeakSource _source;
struct obs_transform_info _info;
struct obs_sceneitem_crop _crop;
SceneItemSelection _source;
struct obs_transform_info _info = {};
struct obs_sceneitem_crop _crop = {};
private:
static bool _registered;
@@ -48,7 +51,7 @@ public:
private slots:
void SceneChanged(const SceneSelection &);
void SourceChanged(const QString &text);
void SourceChanged(const SceneItemSelection &);
void GetSettingsClicked();
void SettingsChanged();
signals:
@@ -56,7 +59,7 @@ signals:
protected:
SceneSelectionWidget *_scenes;
QComboBox *_sources;
SceneItemSelectionWidget *_sources;
QPushButton *_getSettings;
QPlainTextEdit *_settings;
std::shared_ptr<MacroActionSceneTransform> _entryData;

View File

@@ -1,28 +1,38 @@
#pragma once
#include <QSpinBox>
#include "macro-action-edit.hpp"
#include "scene-selection.hpp"
#include "scene-item-selection.hpp"
#include <QSpinBox>
enum class SceneVisibilityAction {
SHOW,
HIDE,
};
enum class SceneItemSourceType {
SOURCE,
SOURCE_GROUP,
};
class MacroActionSceneVisibility : public MacroAction {
public:
MacroActionSceneVisibility(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSceneVisibility>();
return std::make_shared<MacroActionSceneVisibility>(m);
}
SceneSelection _scene;
OBSWeakSource _source;
SceneItemSourceType _sourceType = SceneItemSourceType::SOURCE;
SceneItemSelection _source;
std::string _sourceGroup = "";
SceneVisibilityAction _action = SceneVisibilityAction::SHOW;
private:
@@ -49,18 +59,24 @@ public:
private slots:
void SceneChanged(const SceneSelection &);
void SourceChanged(const QString &text);
void SourceTypeChanged(int value);
void SourceChanged(const SceneItemSelection &);
void SourceGroupChanged(const QString &text);
void ActionChanged(int value);
signals:
void HeaderInfoChanged(const QString &);
protected:
SceneSelectionWidget *_scenes;
QComboBox *_sources;
QComboBox *_sourceTypes;
SceneItemSelectionWidget *_sources;
QComboBox *_sourceGroups;
QComboBox *_actions;
std::shared_ptr<MacroActionSceneVisibility> _entryData;
private:
void SetWidgetVisibility();
QHBoxLayout *_mainLayout;
bool _loading = true;
};

View File

@@ -0,0 +1,51 @@
#pragma once
#include "macro-action-edit.hpp"
class MacroActionScreenshot : public MacroAction {
public:
MacroActionScreenshot(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionScreenshot>(m);
}
OBSWeakSource _source;
private:
static bool _registered;
static const std::string id;
};
class MacroActionScreenshotEdit : public QWidget {
Q_OBJECT
public:
MacroActionScreenshotEdit(
QWidget *parent,
std::shared_ptr<MacroActionScreenshot> entryData = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionScreenshotEdit(
parent,
std::dynamic_pointer_cast<MacroActionScreenshot>(
action));
}
private slots:
void SourceChanged(const QString &text);
signals:
void HeaderInfoChanged(const QString &);
protected:
QComboBox *_sources;
std::shared_ptr<MacroActionScreenshot> _entryData;
private:
bool _loading = true;
};

View File

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

View File

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

View File

@@ -1,8 +1,11 @@
#pragma once
#include <QDoubleSpinBox>
#include "macro-action-edit.hpp"
#include "duration-control.hpp"
#include <QDoubleSpinBox>
#include <QComboBox>
#include <QHBoxLayout>
enum class StreamAction {
STOP,
START,
@@ -10,14 +13,15 @@ enum class StreamAction {
class MacroActionStream : public MacroAction {
public:
MacroActionStream(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionStream>();
return std::make_shared<MacroActionStream>(m);
}
StreamAction _action = StreamAction::STOP;

View File

@@ -0,0 +1,50 @@
#pragma once
#include "macro-action-edit.hpp"
#include <QLineEdit>
class MacroActionSystray : public MacroAction {
public:
MacroActionSystray(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionSystray>(m);
}
std::string _msg = "";
private:
static bool _registered;
static const std::string id;
};
class MacroActionSystrayEdit : public QWidget {
Q_OBJECT
public:
MacroActionSystrayEdit(
QWidget *parent,
std::shared_ptr<MacroActionSystray> entryData = nullptr);
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionSystrayEdit(
parent,
std::dynamic_pointer_cast<MacroActionSystray>(action));
}
private slots:
void MessageChanged();
protected:
std::shared_ptr<MacroActionSystray> _entryData;
private:
QLineEdit *_msg;
bool _loading = true;
};

View File

@@ -0,0 +1,73 @@
#pragma once
#include "macro-action-edit.hpp"
#include "duration-control.hpp"
#include "macro-selection.hpp"
#include <QDoubleSpinBox>
#include <QHBoxLayout>
enum class TimerAction {
PAUSE,
CONTINUE,
RESET,
SET_TIME_REMAINING,
};
class MacroActionTimer : public MacroRefAction {
public:
MacroActionTimer(Macro *m) : MacroRefAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionTimer>(m);
}
Duration _duration;
TimerAction _actionType = TimerAction::PAUSE;
private:
static bool _registered;
static const std::string id;
};
class MacroActionTimerEdit : public QWidget {
Q_OBJECT
public:
MacroActionTimerEdit(
QWidget *parent,
std::shared_ptr<MacroActionTimer> entryData = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionTimerEdit(
parent,
std::dynamic_pointer_cast<MacroActionTimer>(action));
}
private slots:
void MacroChanged(const QString &text);
void MacroRemove(const QString &name);
void DurationChanged(double value);
void DurationUnitChanged(DurationUnit unit);
void ActionTypeChanged(int value);
signals:
void HeaderInfoChanged(const QString &);
protected:
void SetWidgetVisibility();
MacroSelection *_macros;
DurationSelection *_duration;
QComboBox *_timerAction;
std::shared_ptr<MacroActionTimer> _entryData;
private:
QHBoxLayout *_mainLayout;
bool _loading = true;
};

View File

@@ -0,0 +1,69 @@
#pragma once
#include "macro-action-edit.hpp"
#include "duration-control.hpp"
#include "transition-selection.hpp"
#include <QCheckBox>
#include <QHBoxLayout>
class MacroActionTransition : public MacroAction {
public:
MacroActionTransition(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionTransition>(m);
}
bool _setDuration = true;
bool _setType = true;
TransitionSelection _transition;
Duration _duration;
private:
static bool _registered;
static const std::string id;
};
class MacroActionTransitionEdit : public QWidget {
Q_OBJECT
public:
MacroActionTransitionEdit(
QWidget *parent,
std::shared_ptr<MacroActionTransition> entryData = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionTransitionEdit(
parent,
std::dynamic_pointer_cast<MacroActionTransition>(
action));
}
private slots:
void SetTypeChanged(int state);
void SetDurationChanged(int state);
void TransitionChanged(const TransitionSelection &);
void DurationChanged(double seconds);
signals:
void HeaderInfoChanged(const QString &);
protected:
QCheckBox *_setType;
QCheckBox *_setDuration;
TransitionSelectionWidget *_transitions;
DurationSelection *_duration;
QHBoxLayout *_typeLayout;
QHBoxLayout *_durationLayout;
std::shared_ptr<MacroActionTransition> _entryData;
private:
bool _loading = true;
};

View File

@@ -1,7 +1,11 @@
#ifdef VCAM_SUPPORTED
#pragma once
#include <QDoubleSpinBox>
#include "macro-action-edit.hpp"
#include <QComboBox>
#include <QHBoxLayout>
enum class VCamAction {
STOP,
START,
@@ -9,14 +13,15 @@ enum class VCamAction {
class MacroActionVCam : public MacroAction {
public:
MacroActionVCam(Macro *m) : MacroAction(m) {}
bool PerformAction();
void LogAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionVCam>();
return std::make_shared<MacroActionVCam>(m);
}
VCamAction _action = VCamAction::STOP;
@@ -53,3 +58,5 @@ private:
QHBoxLayout *_mainLayout;
bool _loading = true;
};
#endif

View File

@@ -1,8 +1,10 @@
#pragma once
#include <QDoubleSpinBox>
#include "macro-action-edit.hpp"
#include "duration-control.hpp"
#include <QDoubleSpinBox>
#include <QHBoxLayout>
enum class WaitType {
FIXED,
RANDOM,
@@ -10,13 +12,14 @@ enum class WaitType {
class MacroActionWait : public MacroAction {
public:
MacroActionWait(Macro *m) : MacroAction(m) {}
bool PerformAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroAction> Create()
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionWait>();
return std::make_shared<MacroActionWait>(m);
}
Duration _duration;
Duration _duration2;

View File

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

View File

@@ -0,0 +1,77 @@
#pragma once
#include "macro.hpp"
#include <QSpinBox>
#include <QComboBox>
#include <QPushButton>
#include <QTimer>
#include <QFrame>
enum class CursorCondition {
REGION,
MOVING,
};
class MacroConditionCursor : public MacroCondition {
public:
MacroConditionCursor(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionCursor>(m);
}
CursorCondition _condition = CursorCondition::REGION;
int _minX = 0, _minY = 0, _maxX = 0, _maxY = 0;
private:
static bool _registered;
static const std::string id;
};
class MacroConditionCursorEdit : public QWidget {
Q_OBJECT
public:
MacroConditionCursorEdit(
QWidget *parent,
std::shared_ptr<MacroConditionCursor> cond = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroCondition> cond)
{
return new MacroConditionCursorEdit(
parent,
std::dynamic_pointer_cast<MacroConditionCursor>(cond));
}
private slots:
void ConditionChanged(int cond);
void MinXChanged(int pos);
void MinYChanged(int pos);
void MaxXChanged(int pos);
void MaxYChanged(int pos);
void UpdateCursorPos();
void ToggleFrame();
protected:
QSpinBox *_minX;
QSpinBox *_minY;
QSpinBox *_maxX;
QSpinBox *_maxY;
QComboBox *_conditions;
QPushButton *_frameToggle;
QLabel *_xPos;
QLabel *_yPos;
std::shared_ptr<MacroConditionCursor> _entryData;
private:
void SetRegionSelectionVisible(bool);
void SetupFrame();
QTimer _timer;
QFrame _frame;
bool _loading = true;
};

View File

@@ -1,27 +1,38 @@
#pragma once
#include "macro.hpp"
#include <QWidget>
#include <QComboBox>
#include <QDateTimeEdit>
#include "duration-control.hpp"
#include <QCheckBox>
#include <QDateTimeEdit>
#include <QComboBox>
enum class DateCondition {
AT,
AFTER,
BEFORE,
BETWEEN,
};
class MacroConditionDate : public MacroCondition {
public:
MacroConditionDate(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionDate>();
return std::make_shared<MacroConditionDate>(m);
}
QDateTime _dateTime;
QDateTime _dateTime2;
bool _ignoreDate = false;
bool _ignoreTime = false;
bool _repeat = false;
Duration _duration;
DateCondition _condition = DateCondition::AT;
private:
static bool _registered;
@@ -45,7 +56,9 @@ public:
}
private slots:
void ConditionChanged(int cond);
void DateTimeChanged(const QDateTime &datetime);
void DateTime2Changed(const QDateTime &datetime);
void IgnoreDateChanged(int state);
void IgnoreTimeChanged(int state);
void RepeatChanged(int state);
@@ -55,7 +68,9 @@ signals:
void HeaderInfoChanged(const QString &);
protected:
QComboBox *_condition;
QDateTimeEdit *_dateTime;
QDateTimeEdit *_dateTime2;
QCheckBox *_ignoreDate;
QCheckBox *_ignoreTime;
QCheckBox *_repeat;
@@ -63,5 +78,6 @@ protected:
std::shared_ptr<MacroConditionDate> _entryData;
private:
void ShowSecondDateSelection(bool visible);
bool _loading = true;
};

View File

@@ -1,19 +1,12 @@
#pragma once
#include "advanced-scene-switcher.hpp"
#include "macro.hpp"
#include "macro-condition-scene.hpp"
#include "section.hpp"
#include "utility.hpp"
#include <QGroupBox>
struct MacroConditionInfo {
using TCreateMethod = std::shared_ptr<MacroCondition> (*)();
using TCreateMethod = std::shared_ptr<MacroCondition> (*)(Macro *m);
using TCreateWidgetMethod =
QWidget *(*)(QWidget *parent, std::shared_ptr<MacroCondition>);
TCreateMethod _createFunc;
TCreateWidgetMethod _createWidgetFunc;
TCreateMethod _createFunc = nullptr;
TCreateWidgetMethod _createWidgetFunc = nullptr;
std::string _name;
bool _useDurationConstraint = true;
};
@@ -22,7 +15,8 @@ class MacroConditionFactory {
public:
MacroConditionFactory() = delete;
static bool Register(const std::string &, MacroConditionInfo);
static std::shared_ptr<MacroCondition> Create(const std::string &);
static std::shared_ptr<MacroCondition> Create(const std::string &,
Macro *m);
static QWidget *CreateWidget(const std::string &id, QWidget *parent,
std::shared_ptr<MacroCondition>);
static auto GetConditionTypes() { return _methods; }
@@ -34,16 +28,16 @@ private:
static std::map<std::string, MacroConditionInfo> _methods;
};
class MacroConditionEdit : public QWidget {
class MacroConditionEdit : public MacroSegmentEdit {
Q_OBJECT
public:
MacroConditionEdit(QWidget *parent = nullptr,
std::shared_ptr<MacroCondition> * = nullptr,
const std::string &id = "scene", bool root = true,
bool startCollapsed = false);
const std::string &id = "scene", bool root = true);
bool IsRootNode();
void UpdateEntryData(const std::string &id, bool collapse);
void SetRootNode(bool);
void UpdateEntryData(const std::string &id);
private slots:
void LogicSelectionChanged(int idx);
@@ -51,25 +45,15 @@ private slots:
void DurationChanged(double seconds);
void DurationConditionChanged(DurationCondition cond);
void DurationUnitChanged(DurationUnit unit);
void HeaderInfoChanged(const QString &);
signals:
void MacroAdded(const QString &name);
void MacroRemoved(const QString &name);
void MacroRenamed(const QString &oldName, const QString newName);
void SceneGroupAdded(const QString &name);
void SceneGroupRemoved(const QString &name);
void SceneGroupRenamed(const QString &oldName, const QString newName);
protected:
private:
MacroSegment *Data();
QComboBox *_logicSelection;
QComboBox *_conditionSelection;
Section *_section;
QLabel *_headerInfo;
DurationConstraintEdit *_dur;
std::shared_ptr<MacroCondition> *_entryData;
private:
bool _isRoot = true;
bool _loading = true;
};

View File

@@ -1,5 +1,7 @@
#pragma once
#include "macro.hpp"
#include "file-selection.hpp"
#include <QWidget>
#include <QComboBox>
#include <QDateTime>
@@ -15,14 +17,15 @@ enum class FileType {
class MacroConditionFile : public MacroCondition {
public:
MacroConditionFile(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionFile>();
return std::make_shared<MacroConditionFile>(m);
}
std::string _file = obs_module_text("AdvSceneSwitcher.enterPath");
@@ -61,8 +64,7 @@ public:
private slots:
void FileTypeChanged(int index);
void FilePathChanged();
void BrowseButtonClicked();
void PathChanged(const QString &text);
void MatchTextChanged();
void UseRegexChanged(int state);
void CheckModificationDateChanged(int state);
@@ -72,8 +74,7 @@ signals:
protected:
QComboBox *_fileType;
QLineEdit *_filePath;
QPushButton *_browseButton;
FileSelection *_filePath;
QPlainTextEdit *_matchText;
QCheckBox *_useRegex;
QCheckBox *_checkModificationDate;

View File

@@ -1,7 +1,10 @@
#pragma once
#include "macro.hpp"
#include <QWidget>
#include <QComboBox>
#include <QPushButton>
#include <QPlainTextEdit>
#include <QCheckBox>
enum class FilterCondition {
ENABLED,
@@ -11,14 +14,15 @@ enum class FilterCondition {
class MacroConditionFilter : public MacroCondition {
public:
MacroConditionFilter(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionFilter>();
return std::make_shared<MacroConditionFilter>(m);
}
OBSWeakSource _source;

View File

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

View File

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

View File

@@ -1,9 +1,11 @@
#pragma once
#include "macro.hpp"
#include "macro-selection.hpp"
#include <QWidget>
#include <QComboBox>
#include <QSpinBox>
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
#include <QTimer>
enum class MacroConditionMacroType {
@@ -19,14 +21,15 @@ enum class CounterCondition {
class MacroConditionMacro : public MacroRefCondition {
public:
MacroConditionMacro(Macro *m) : MacroRefCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionMacro>();
return std::make_shared<MacroConditionMacro>(m);
}
MacroConditionMacroType _type = MacroConditionMacroType::STATE;
@@ -65,6 +68,7 @@ private slots:
void ConditionChanged(int cond);
void ResetClicked();
void UpdateCount();
void UpdatePaused();
signals:
void HeaderInfoChanged(const QString &);
@@ -74,16 +78,17 @@ protected:
QComboBox *_counterConditions;
QSpinBox *_count;
QLabel *_currentCount;
QLabel *_pausedWarning;
QPushButton *_resetCount;
QHBoxLayout *_settingsLine1;
QHBoxLayout *_settingsLine2;
std::unique_ptr<QTimer> _timer;
QTimer _countTimer;
QTimer _pausedTimer;
std::shared_ptr<MacroConditionMacro> _entryData;
private:
void ClearLayouts();
void SetupStateWidgets();
void SetupCountWidgets();
void ResetTimer();
bool _loading = true;
};

View File

@@ -3,8 +3,10 @@
#include <limits>
#include <QWidget>
#include <QComboBox>
#include <QCheckBox>
#include "duration-control.hpp"
#include "scene-selection.hpp"
enum class MediaTimeRestriction {
TIME_RESTRICTION_NONE,
@@ -33,32 +35,47 @@ enum class MediaState {
ANY,
};
enum class MediaSourceType {
SOURCE,
ANY,
ALL,
};
class MacroConditionMedia : public MacroCondition {
public:
MacroConditionMedia(Macro *m) : MacroCondition(m) {}
~MacroConditionMedia();
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionMedia>();
return std::make_shared<MacroConditionMedia>(m);
}
void ClearSignalHandler();
void ResetSignalHandler();
static void MediaStopped(void *data, calldata_t *);
static void MediaEnded(void *data, calldata_t *);
MediaSourceType _sourceType = MediaSourceType::SOURCE;
SceneSelection _scene;
OBSWeakSource _source = nullptr;
std::vector<MacroConditionMedia> _sources;
MediaState _state = MediaState::OBS_MEDIA_STATE_NONE;
MediaTimeRestriction _restriction =
MediaTimeRestriction::TIME_RESTRICTION_NONE;
Duration _time;
bool _onlyMatchonChagne = false;
private:
std::atomic_bool _stopped = {false};
std::atomic_bool _ended = {false};
bool CheckMediaMatch();
bool _stopped = false;
bool _ended = false;
// TODO: Remove _alreadyMatched as it does not make much sense when
// time restrictions for macro conditions are available.
// Trigger scene change only once even if media state might trigger repeatedly
bool _alreadyMatched = false;
// Workaround to enable use of "ended" to specify end of VLC playlist
@@ -87,20 +104,25 @@ public:
private slots:
void SourceChanged(const QString &text);
void SceneChanged(const SceneSelection &);
void StateChanged(int index);
void TimeRestrictionChanged(int index);
void TimeChanged(double seconds);
void TimeUnitChanged(DurationUnit unit);
void OnChangeChanged(int);
signals:
void HeaderInfoChanged(const QString &);
protected:
SceneSelectionWidget *_scenes;
QComboBox *_mediaSources;
QComboBox *_states;
QComboBox *_timeRestrictions;
DurationSelection *_time;
QCheckBox *_onChange;
std::shared_ptr<MacroConditionMedia> _entryData;
private:
void SetWidgetVisibility();
bool _loading = true;
};

View File

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

View File

@@ -1,18 +1,20 @@
#pragma once
#include "macro.hpp"
#include <QWidget>
#include <QComboBox>
#include <QCheckBox>
class MacroConditionProcess : public MacroCondition {
public:
MacroConditionProcess(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionProcess>();
return std::make_shared<MacroConditionProcess>(m);
}
std::string _process;

View File

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

View File

@@ -1,55 +0,0 @@
#pragma once
#include "macro.hpp"
#include <QWidget>
#include <QComboBox>
class MacroConditionRegion : 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<MacroConditionRegion>();
}
int _minX = 0, _minY = 0, _maxX = 0, _maxY = 0;
private:
static bool _registered;
static const std::string id;
};
class MacroConditionRegionEdit : public QWidget {
Q_OBJECT
public:
MacroConditionRegionEdit(
QWidget *parent,
std::shared_ptr<MacroConditionRegion> cond = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroCondition> cond)
{
return new MacroConditionRegionEdit(
parent,
std::dynamic_pointer_cast<MacroConditionRegion>(cond));
}
private slots:
void MinXChanged(int pos);
void MinYChanged(int pos);
void MaxXChanged(int pos);
void MaxYChanged(int pos);
protected:
QSpinBox *_minX;
QSpinBox *_minY;
QSpinBox *_maxX;
QSpinBox *_maxY;
std::shared_ptr<MacroConditionRegion> _entryData;
private:
bool _loading = true;
};

View File

@@ -1,3 +1,5 @@
#ifdef REPLAYBUFFER_SUPPORTED
#pragma once
#include "macro.hpp"
#include <QWidget>
@@ -11,16 +13,17 @@ enum class ReplayBufferState {
class MacroConditionReplayBuffer : public MacroCondition {
public:
MacroConditionReplayBuffer(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionReplayBuffer>();
return std::make_shared<MacroConditionReplayBuffer>(m);
}
ReplayBufferState _state;
ReplayBufferState _state = ReplayBufferState::STOP;
private:
static bool _registered;
@@ -54,3 +57,5 @@ protected:
private:
bool _loading = true;
};
#endif

View File

@@ -1,6 +1,7 @@
#pragma once
#include "macro.hpp"
#include "scene-selection.hpp"
#include "scene-item-selection.hpp"
#include <QWidget>
#include <QComboBox>
@@ -13,19 +14,20 @@ enum class SceneOrderCondition {
class MacroConditionSceneOrder : public MacroCondition {
public:
MacroConditionSceneOrder(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionSceneOrder>();
return std::make_shared<MacroConditionSceneOrder>(m);
}
SceneSelection _scene;
OBSWeakSource _source;
OBSWeakSource _source2;
SceneItemSelection _source;
SceneItemSelection _source2;
int _position = 0;
SceneOrderCondition _condition = SceneOrderCondition::ABOVE;
@@ -53,8 +55,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 +65,8 @@ signals:
protected:
SceneSelectionWidget *_scenes;
QComboBox *_conditions;
QComboBox *_sources;
QComboBox *_sources2;
SceneItemSelectionWidget *_sources;
SceneItemSelectionWidget *_sources2;
QSpinBox *_position;
QLabel *_posInfo;

View File

@@ -0,0 +1,71 @@
#pragma once
#include "macro.hpp"
#include "scene-selection.hpp"
#include "scene-item-selection.hpp"
#include <QSpinBox>
#include <QPlainTextEdit>
#include <QCheckBox>
class MacroConditionSceneTransform : public MacroCondition {
public:
MacroConditionSceneTransform(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionSceneTransform>(m);
}
SceneSelection _scene;
SceneItemSelection _source;
bool _regex = false;
std::string _settings = "";
private:
static bool _registered;
static const std::string id;
};
class MacroConditionSceneTransformEdit : public QWidget {
Q_OBJECT
public:
MacroConditionSceneTransformEdit(
QWidget *parent,
std::shared_ptr<MacroConditionSceneTransform> entryData =
nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroCondition> cond)
{
return new MacroConditionSceneTransformEdit(
parent,
std::dynamic_pointer_cast<MacroConditionSceneTransform>(
cond));
}
private slots:
void SceneChanged(const SceneSelection &);
void SourceChanged(const SceneItemSelection &);
void GetSettingsClicked();
void SettingsChanged();
void RegexChanged(int);
signals:
void HeaderInfoChanged(const QString &);
protected:
SceneSelectionWidget *_scenes;
SceneItemSelectionWidget *_sources;
QPushButton *_getSettings;
QPlainTextEdit *_settings;
QCheckBox *_regex;
std::shared_ptr<MacroConditionSceneTransform> _entryData;
private:
bool _loading = true;
};

View File

@@ -0,0 +1,68 @@
#pragma once
#include "macro.hpp"
#include "scene-selection.hpp"
#include "scene-item-selection.hpp"
#include <QComboBox>
enum class SceneVisibilityCondition {
SHOWN,
HIDDEN,
};
class MacroConditionSceneVisibility : public MacroCondition {
public:
MacroConditionSceneVisibility(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionSceneVisibility>(m);
}
SceneSelection _scene;
SceneItemSelection _source;
SceneVisibilityCondition _condition = SceneVisibilityCondition::SHOWN;
private:
static bool _registered;
static const std::string id;
};
class MacroConditionSceneVisibilityEdit : public QWidget {
Q_OBJECT
public:
MacroConditionSceneVisibilityEdit(
QWidget *parent,
std::shared_ptr<MacroConditionSceneVisibility> cond = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroCondition> cond)
{
return new MacroConditionSceneVisibilityEdit(
parent,
std::dynamic_pointer_cast<MacroConditionSceneVisibility>(
cond));
}
private slots:
void SceneChanged(const SceneSelection &);
void SourceChanged(const SceneItemSelection &);
void ConditionChanged(int cond);
signals:
void HeaderInfoChanged(const QString &);
protected:
SceneSelectionWidget *_scenes;
SceneItemSelectionWidget *_sources;
QComboBox *_conditions;
std::shared_ptr<MacroConditionSceneVisibility> _entryData;
private:
bool _loading = true;
};

View File

@@ -4,28 +4,37 @@
#include <QWidget>
#include <QComboBox>
#include <QCheckBox>
enum class SceneType {
CURRENT,
PREVIOUS,
CHANGED,
NOTCHANGED,
};
class MacroConditionScene : public MacroCondition {
public:
MacroConditionScene(Macro *m) : MacroCondition(m) {}
bool CheckCondition();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
std::string GetShortDesc();
std::string GetId() { return id; };
static std::shared_ptr<MacroCondition> Create()
static std::shared_ptr<MacroCondition> Create(Macro *m)
{
return std::make_shared<MacroConditionScene>();
return std::make_shared<MacroConditionScene>(m);
}
SceneSelection _scene;
SceneType _type;
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{};
static bool _registered;
static const std::string id;
};
@@ -49,14 +58,17 @@ public:
private slots:
void SceneChanged(const SceneSelection &);
void TypeChanged(int value);
void UseTransitionTargetSceneChanged(int state);
signals:
void HeaderInfoChanged(const QString &);
protected:
SceneSelectionWidget *_scenes;
QComboBox *_sceneType;
QCheckBox *_useTransitionTargetScene;
std::shared_ptr<MacroConditionScene> _entryData;
private:
void SetWidgetVisibility();
bool _loading = true;
};

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