Compare commits

..

18 Commits

Author SHA1 Message Date
WarmUpTill
daf16357c9 Fix output volume check of audio condition not working
Only the percent based selection was not working properly since the
calculation was off by a factor of 100.
2024-03-03 20:54:15 +01:00
WarmUpTill
8080abc93c Fix crash when opening setting window 2024-03-03 20:54:15 +01:00
WarmUpTill
902715bd3e Save settings when switching to new macro
This should ensure that settings are saved more frequently and less data
is lost in case the plugin crashes with the settings dialog opened.
2024-03-03 20:54:15 +01:00
WarmUpTill
8271a6e8db CI: Don't attempt to rename files if not required 2024-03-02 16:38:24 +01:00
WarmUpTill
6c121a093b Add "Log" action
This action will allow you to write custom messages to the OBS log
2024-03-02 15:27:02 +01:00
WarmUpTill
ab0cce9eaa Add log level which prints performed actions 2024-03-02 15:27:02 +01:00
WarmUpTill
9acbead87b Update BUILDING.md 2024-03-02 15:27:02 +01:00
WarmUpTill
03e71e9183 Add support to resolve variables on action queue add 2024-03-02 15:27:02 +01:00
WarmUpTill
f8dadd38b4 Add ResolveVariables()
Settings will be set to fixed values based on the values of the
variables used.
2024-03-02 15:27:02 +01:00
WarmUpTill
2928775f5b Add option to resolve variables on queue add 2024-03-02 15:27:02 +01:00
WarmUpTill
673ac8078b Update lastVariableChange when using settings dialog to change value 2024-03-02 15:27:02 +01:00
WarmUpTill
234ae27205 Fix crash when running RunPostLoadSteps()
RunPostLoadSteps() could be called with "stale" post load steps as
RunPostLoadSteps() was never called when a copy of an action or
condition was created
2024-03-02 15:27:02 +01:00
WarmUpTill
a740a29798 Cleanup includes 2024-03-02 15:27:02 +01:00
WarmUpTill
341a58b8e4 Add window action
It allows to set the focus window and close windows.
Only supported on Windows for now.
2024-03-02 14:03:00 +01:00
Michael Kirsch
ba9a16e718 Force LF for formatter script for WSL 2024-02-29 20:31:50 +01:00
WarmUpTill
2b2bab8fbc Backup setting on exit to plugin config dir
Only one version of the settings file will be kept per scene collection
and plugin version combination
2024-02-28 12:53:02 +01:00
WarmUpTill
f50f31ec4c Allow stop of current macro when using run button 2024-02-26 20:56:26 +01:00
WarmUpTill
3a1c353ea3 Use git tag as version identifier in package scripts 2024-02-24 22:51:24 +01:00
160 changed files with 1799 additions and 420 deletions

2
.gitattributes vendored Normal file
View File

@@ -0,0 +1,2 @@
/build-aux/*.zsh eol=lf
/build-aux/.functions/* eol=lf

View File

@@ -163,9 +163,13 @@ ${_usage_host:-}"
local product_name
local product_version
local git_tag="$(git describe --tags)"
read -r product_name product_version <<< \
"$(jq -r '. | {name, version} | join(" ")' ${buildspec_file})"
log_info "Using git tag as version identifier '${git_tag}'"
product_version="${git_tag}"
if [[ ${host_os} == macos ]] {
autoload -Uz check_packages read_codesign read_codesign_installer read_codesign_pass
@@ -247,15 +251,21 @@ ${_usage_host:-}"
cmake --build build_${target##*-} --config ${config} -t package_source ${cmake_args}
popd
local output_name="${product_name}-${product_version}-${target##*-}-linux-gnu"
if (( package )) {
log_group "Packaging ${product_name}..."
pushd ${project_root}
cmake --build build_${target##*-} --config ${config} -t package ${cmake_args}
if [ ! -e ${project_root}/release/${output_name}.deb ]; then
mv ${project_root}/release/*.deb ${project_root}/release/${output_name}.deb
mv ${project_root}/release/*.ddeb ${project_root}/release/${output_name}.ddeb
fi
popd
}
log_group "Archiving ${product_name}..."
local output_name="${product_name}-${product_version}-${target##*-}-linux-gnu"
local _tarflags='cJf'
if (( _loglevel > 1 || ${+CI} )) _tarflags="v${_tarflags}"

View File

@@ -48,6 +48,10 @@ function Package {
$ProductName = $BuildSpec.name
$ProductVersion = $BuildSpec.version
$GitOutput = git describe --tags
Log-Information "Using git tag as version identifier '${GitOutput}'"
$ProductVersion = $GitOutput
$OutputName = "${ProductName}-${ProductVersion}-windows-${Target}"
if ( ! $SkipDeps ) {

0
.github/test vendored Normal file
View File

1
.gitignore vendored
View File

@@ -14,6 +14,7 @@
!/tests
!.clang-format
!.cmake-format.json
!.gitattributes
!.gitignore
!BUILDING.md
!buildspec.json

View File

@@ -4,11 +4,13 @@ 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/Building-OBS-Studio) 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.
Both methods require [CMake](https://cmake.org/download/).
The plugin can be compiled for OBS 25 and above, although using the latest version of OBS is recommended to support all features.
The plugin can be compiled for OBS 27 and above, although using the latest version of OBS is recommended to support all features.
## Compiling in tree (recommended for development)
This section assumes that you have a working [OBS Studio development environment](https://obsproject.com/wiki/Building-OBS-Studio).
Add the "SceneSwitcher" source directory to your obs-studio source directory under obs-studio/UI/frontend-plugins/:
```
cd obs-studio/UI/frontend-plugins/
@@ -46,12 +48,12 @@ cmake -DOpenCV_DIR="C:/Users/BuildUser/Documents/OBS/opencv/build/" -DLeptonica_
First you will need to clone the plugin sources by running the following command:
```
git clone --recursive https://github.com/WarmUpTill/SceneSwitcher.git
cd SceneSwitcher
```
Next you will need [CMake](https://cmake.org/download/) and run the command with suitable arguments for your particular platform.
Next you will need [CMake](https://cmake.org/download/) and run it with suitable arguments for your particular platform.
For example, on Windows you might want to run this command:
```
cd SceneSwitcher
cmake --preset windows-x64
```
Next, you can build the plugin and install the files into a folder named release using the following commands:
@@ -72,7 +74,7 @@ cd SceneSwitcher
cmake -DOpenCV_DIR="C:/Users/BuildUser/Documents/OBS/opencv/build/" -DLeptonica_DIR="C:/Users/BuildUser/Documents/OBS/leptonica/build" -DTesseract_DIR="C:/Users/BuildUser/Documents/OBS/tesseract/build/lib/cmake/tesseract" --preset windows-x64
```
You can rely on the CI scripts to build the dependencies for you, although it is not guaranteed that they will work in every environment:
You can rely on the CI scripts to build the dependencies for you, although it is not guaranteed that they will function in every environment:
| Platform | Command |
| ----------- | ----------- |
@@ -83,10 +85,10 @@ You can rely on the CI scripts to build the dependencies for you, although it is
# Contributing
Contributions to the plugin are always welcome and if you need any assistance do not hesitate to reach out.
Contributions to the plugin are always welcome and if you need any assistance do not hesitate to reach out!
If you would like to expand upon the macro system by adding a new condition or action type have a look at the examples in `plugins/base`.
In general changes in the `lib/legacy` folder should be avoided.
In general changes in the `lib/legacy` folder should be avoided, if possible.
## Macro condition
Macro conditions should inherit from the `MacroCondition` class and must implement the following functions:
@@ -97,12 +99,12 @@ public:
MacroConditionExample(Macro *m) : MacroCondition(m) {}
// This function should perform the condition check
bool CheckCondition();
// This function should store the required condition data to "obj"
// This function should store the required condition data to "data"
// For example called on OBS shutdown
bool Save(obs_data_t *obj);
// This function should load the condition data from "obj"
bool Save(obs_data_t *data);
// This function should load the condition data from "data"
// For example called on OBS startup
bool Load(obs_data_t *obj);
bool Load(obs_data_t *data);
// This function should return a unique id for this condition type
// The _id is defined below
std::string GetId() { return _id; };
@@ -120,7 +122,7 @@ private:
static const std::string _id;
};
```
When defining the widget used to control the settings of the condition type, it is important to add a static `Create()` method.
When defining the widget used to control the settings of the condition type, a static `Create()` method is required.
It will be called whenever a new condition MacroConditionExample is created. (See `MacroConditionFactory::Register()`)
```
class MacroConditionExampleEdit : public QWidget {
@@ -151,7 +153,7 @@ bool MacroConditionExample::_registered = MacroConditionFactory::Register(
MacroConditionExample::id, // Unique string identifying this condition type
{
MacroConditionExample::Create, // Function called to create the object performing the condition
MacroConditionExampleEdit::Create, // Function called to create the widget configure the condition
MacroConditionExampleEdit::Create, // Function called to create the widget to configure the settings
"AdvSceneSwitcher.condition.example", // User facing name of the condition type (will be translated)
true // Condition type supports duration modifiers (default true)
}
@@ -167,16 +169,18 @@ The differences are highlighted in the comments below.
class MacroActionExample : public MacroAction {
public:
MacroActionExample(Macro *m) : MacroAction(m) {}
static std::shared_ptr<MacroAction> Create(Macro *m);
// Used to create a copy of the action (used for action queues)
std::shared_ptr<MacroAction> Copy() const;
// This function should perform the action
// If false is returned the macro will aborted
bool PerformAction();
bool Save(obs_data_t *obj);
bool Load(obs_data_t *obj);
bool Save(obs_data_t *data);
bool Load(obs_data_t *data);
std::string GetId() { return _id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionExample>(m);
}
// Optional:
// Might be called when action is inserted to action queue
void ResolveVariablesToFixedValues();
private:
static bool _registered;
@@ -207,11 +211,11 @@ MacroActionFactory::Register(
MacroActionExample::id, // Unique string identifying this action type
{
MacroActionExample::Create, // Function called to create the object performing the action
MacroActionExampleEdit::Create, // Function called to create the widget configure the action
MacroActionExampleEdit::Create, // Function called to create the widget to configure the settings
"AdvSceneSwitcher.action.example" // User facing name of the action type
}
);
```
## External dependencies
If your intention is to add macro functionality which depends on external libraries, which is likely not to exist on all user setups, have a look at the folders in the `plugins/` directory, which are not named base.
For example `plugins/video` will only be loaded if the `OpenCV` dependencies are met.
If your intention is to add macro functionality which depends on external libraries, which might not exist on all user environments, have a look at the folders in the `plugins/` directory, which are not named `base`.
For example, `plugins/video` will only be loaded if the `OpenCV` dependencies are met.

View File

@@ -147,6 +147,8 @@ target_sources(
${LIB_NAME}
PRIVATE lib/utils/action-queue.cpp
lib/utils/action-queue.hpp
lib/utils/backup.cpp
lib/utils/backup.hpp
lib/utils/curl-helper.cpp
lib/utils/curl-helper.hpp
lib/utils/duration-control.cpp

View File

@@ -75,7 +75,7 @@ AdvSceneSwitcher.macroTab.edit.action="Aktions-Typ:"
AdvSceneSwitcher.macroTab.add="Neues Makro hinzufügen"
AdvSceneSwitcher.macroTab.name="Name:"
AdvSceneSwitcher.macroTab.run="Makro ausführen"
AdvSceneSwitcher.macroTab.runFail="Ausführen von \"%1\" fehlgeschlagen!\nEntweder ist eine der Aktionen fehlgeschlagen oder das Makro wird bereits ausgeführt."
AdvSceneSwitcher.macroTab.runFail="Ausführen von \"%1\" fehlgeschlagen!\nEntweder ist eine der Aktionen fehlgeschlagen oder das Makro wird bereits ausgeführt.\nSoll die aktuelle Ausführung gestoppt werden?"
AdvSceneSwitcher.macroTab.runInParallel="Parallel zu anderen Makros ausführen"
AdvSceneSwitcher.macroTab.onChange="Nur bei Änderung ausführen"
AdvSceneSwitcher.macroTab.defaultname="Makro %1"

View File

@@ -26,6 +26,10 @@ AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchToRandom="Switch to an
AdvSceneSwitcher.generalTab.generalBehavior.onNoMet.switchTo="Switch to:"
AdvSceneSwitcher.generalTab.generalBehavior.cooldown="After performing actions skip performing actions for"
AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint="During this time potential matches will be ignored!"
AdvSceneSwitcher.generalTab.generalBehavior.logLevel="Log level:"
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default="Default"
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.printActions="Log performed actions"
AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose="Verbose logging"
AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging="Enable verbose logging"
AdvSceneSwitcher.generalTab.generalBehavior.saveWindowGeo="Save window position and size"
AdvSceneSwitcher.generalTab.generalBehavior.showTrayNotifications="Show system tray notifications"
@@ -94,7 +98,7 @@ AdvSceneSwitcher.macroTab.name="Name:"
AdvSceneSwitcher.macroTab.run="Run macro"
AdvSceneSwitcher.macroTab.run.tooltip="Run all macro actions regardless of condition.\nIf else actions are available, hold Shift and click the button to execute them instead."
AdvSceneSwitcher.macroTab.runElse="Run macro (else)"
AdvSceneSwitcher.macroTab.runFail="Running \"%1\" failed!\nEither one of the actions failed or the macro is running already."
AdvSceneSwitcher.macroTab.runFail="Running \"%1\" failed!\nEither one of the actions failed or the macro is running already.\nDo you want to stop it?"
AdvSceneSwitcher.macroTab.runInParallel="Run macro in parallel to other macros"
AdvSceneSwitcher.macroTab.onChange="Perform actions only on condition change"
AdvSceneSwitcher.macroTab.defaultname="Macro %1"
@@ -962,6 +966,15 @@ AdvSceneSwitcher.action.queue.type.start="Start"
AdvSceneSwitcher.action.queue.type.stop="Stop"
AdvSceneSwitcher.action.queue.entry.add="{{actions}}actions of macro{{macros}}to queue{{queues}}"
AdvSceneSwitcher.action.queue.entry.other="{{actions}}queue{{queues}}"
AdvSceneSwitcher.action.window="Window"
AdvSceneSwitcher.action.window.type.setFocusWindow="Focus window"
AdvSceneSwitcher.action.window.type.maximizeWindow="Maximize window"
AdvSceneSwitcher.action.window.type.minimizeWindow="Minimize window"
AdvSceneSwitcher.action.window.type.closeWindow="Close window"
AdvSceneSwitcher.action.window.entry="{{actions}}{{windows}}{{regex}}"
AdvSceneSwitcher.action.log="Log"
AdvSceneSwitcher.action.log.placeholder="My log message!"
AdvSceneSwitcher.action.log.entry="Write to OBS log:{{logMessage}}"
; Hotkey
AdvSceneSwitcher.hotkey.startSwitcherHotkey="Start the Advanced Scene Switcher"
@@ -1034,6 +1047,7 @@ AdvSceneSwitcher.actionQueues.configure="Configure action queue settings"
AdvSceneSwitcher.actionQueues.invalid="Invalid action queue selection"
AdvSceneSwitcher.actionQueues.name="Name:"
AdvSceneSwitcher.actionQueues.runOnStartup="Run action queue when starting the plugin"
AdvSceneSwitcher.actionQueues.resolveVariablesOnAdd="Resolve variables when action is inserted into the queue"
AdvSceneSwitcher.actionQueues.running="Queue is running"
AdvSceneSwitcher.actionQueues.stopped="Queue is stopped"
AdvSceneSwitcher.actionQueues.start="Start action queue"

View File

@@ -72,7 +72,6 @@ AdvSceneSwitcher.macroTab.edit.action="Tipo de acción:"
AdvSceneSwitcher.macroTab.add="Agregar nueva macro"
AdvSceneSwitcher.macroTab.name="Nombre:"
AdvSceneSwitcher.macroTab.run="Ejecutar macro"
AdvSceneSwitcher.macroTab.runFail="Error al ejecutar \"%1\" si se ha producido un error en una de las acciones o si la macro ya se está ejecutando."
AdvSceneSwitcher.macroTab.runInParallel="Ejecutar macro en paralelo a otras macros"
AdvSceneSwitcher.macroTab.onChange="Realizar acciones solo en el cambio de condición"
AdvSceneSwitcher.macroTab.defaultname="Macro %1"

View File

@@ -78,7 +78,6 @@ AdvSceneSwitcher.macroTab.edit.action="Type d'action :"
AdvSceneSwitcher.macroTab.add="Ajouter une nouvelle macro"
AdvSceneSwitcher.macroTab.name="Nom :"
AdvSceneSwitcher.macroTab.run="Exécuter la macro"
AdvSceneSwitcher.macroTab.runFail="Échec de l'exécution de \"%1\" !\nSoit l'une des actions a échoué, soit la macro est déjà en cours d'exécution."
AdvSceneSwitcher.macroTab.runInParallel="Exécuter la macro en parallèle avec d'autres macros"
AdvSceneSwitcher.macroTab.onChange="Exécuter des actions uniquement en cas de changement de condition"
AdvSceneSwitcher.macroTab.defaultname="Macro %1"

View File

@@ -72,7 +72,6 @@ AdvSceneSwitcher.macroTab.edit.action="Eylem türü:"
AdvSceneSwitcher.macroTab.add="Yeni Makro ekle"
AdvSceneSwitcher.macroTab.name="İsim:"
AdvSceneSwitcher.macroTab.run="Makro Çalıştırma"
AdvSceneSwitcher.macroTab.runFail="\"%1\" çalıştırılamadı!\n Eylemlerden biri başarısız oldu veya makro zaten çalışıyor."
AdvSceneSwitcher.macroTab.runInParallel="Makroyu diğer makrolara paralel olarak çalıştırın"
AdvSceneSwitcher.macroTab.onChange="Eylemleri yalnızca koşul değişikliğinde gerçekleştirin"
AdvSceneSwitcher.macroTab.defaultname="Makro %1"

View File

@@ -77,7 +77,6 @@ AdvSceneSwitcher.macroTab.edit.action="动作类型:"
AdvSceneSwitcher.macroTab.add="添加新宏"
AdvSceneSwitcher.macroTab.name="名称:"
AdvSceneSwitcher.macroTab.run="运行宏"
AdvSceneSwitcher.macroTab.runFail="运行 \"%1\" 失败!\n其中一个操作失败或者宏已在运行."
AdvSceneSwitcher.macroTab.runInParallel="与其他宏同时运行宏"
AdvSceneSwitcher.macroTab.onChange="仅在条件更改时执行操作"
AdvSceneSwitcher.macroTab.defaultname="宏 %1"

View File

@@ -163,12 +163,31 @@
<item>
<layout class="QHBoxLayout" name="horizontalLayout_52">
<item>
<widget class="QCheckBox" name="verboseLogging">
<widget class="QLabel" name="label_21">
<property name="text">
<string>AdvSceneSwitcher.generalTab.generalBehavior.verboseLogging</string>
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="logLevel">
<item>
<property name="text">
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel.default</string>
</property>
</item>
<item>
<property name="text">
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel.printActions</string>
</property>
</item>
<item>
<property name="text">
<string>AdvSceneSwitcher.generalTab.generalBehavior.logLevel.verbose</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_49">
<property name="orientation">
@@ -5078,7 +5097,7 @@
<tabstop>checkInterval</tabstop>
<tabstop>startupBehavior</tabstop>
<tabstop>autoStartEvent</tabstop>
<tabstop>verboseLogging</tabstop>
<tabstop>logLevel</tabstop>
<tabstop>saveWindowGeo</tabstop>
<tabstop>showTrayNotifications</tabstop>
<tabstop>uiHintsDisable</tabstop>

View File

@@ -1,4 +1,5 @@
#include "advanced-scene-switcher.hpp"
#include "backup.hpp"
#include "curl-helper.hpp"
#include "log-helper.hpp"
#include "macro-helpers.hpp"
@@ -17,7 +18,6 @@
#include <obs-frontend-api.h>
#include <QAction>
#include <QDirIterator>
#include <QFileDialog>
#include <QMainWindow>
#include <QTextStream>
#include <regex>
@@ -143,7 +143,6 @@ bool AdvSceneSwitcher::eventFilter(QObject *obj, QEvent *event)
/******************************************************************************
* Saving and loading
******************************************************************************/
static void AskForBackup(const QString &json);
static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
{
@@ -192,34 +191,6 @@ static void SaveSceneSwitcher(obs_data_t *save_data, bool saving, void *)
}
}
static void AskForBackup(const QString &json)
{
const bool backupWasConfirmed = DisplayMessage(
obs_module_text("AdvSceneSwitcher.askBackup"), true, false);
if (!backupWasConfirmed) {
return;
}
QString path = QFileDialog::getSaveFileName(
nullptr,
obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle"),
GetDefaultSettingsSaveLocation(),
obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType"));
if (path.isEmpty()) {
return;
}
QFile file(path);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return;
}
auto out = QTextStream(&file);
out << json;
}
/******************************************************************************
* Main switcher thread
******************************************************************************/
@@ -635,6 +606,8 @@ static void handleShutdown()
// TODO: Look for a way to possibly resolve this
obs_frontend_save();
}
BackupSettingsOfCurrentVersion();
}
static void handleSceneCollectionChanging()

View File

@@ -55,6 +55,7 @@ public slots:
void NoMatchDelayDurationChanged(const Duration &);
void CooldownDurationChanged(const Duration &);
void on_startupBehavior_currentIndexChanged(int index);
void on_logLevel_currentIndexChanged(int index);
void on_autoStartEvent_currentIndexChanged(int index);
void on_noMatchSwitchScene_currentTextChanged(const QString &text);
void on_checkInterval_valueChanged(int value);
@@ -62,7 +63,6 @@ public slots:
void on_tabWidget_currentChanged(int index);
void on_exportSettings_clicked();
void on_importSettings_clicked();
void on_verboseLogging_stateChanged(int state);
void on_saveWindowGeo_stateChanged(int state);
void on_showTrayNotifications_stateChanged(int state);
void on_uiHintsDisable_stateChanged(int state);

View File

@@ -112,6 +112,14 @@ void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
static_cast<SwitcherData::StartupBehavior>(index);
}
void AdvSceneSwitcher::on_logLevel_currentIndexChanged(int value)
{
if (loading) {
return;
}
switcher->logLevel = static_cast<SwitcherData::LogLevel>(value);
}
void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
{
if (loading) {
@@ -157,15 +165,6 @@ void AdvSceneSwitcher::closeEvent(QCloseEvent *)
obs_frontend_save();
}
void AdvSceneSwitcher::on_verboseLogging_stateChanged(int state)
{
if (loading) {
return;
}
switcher->verbose = state;
}
void AdvSceneSwitcher::on_saveWindowGeo_stateChanged(int state)
{
if (loading) {
@@ -598,7 +597,7 @@ void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
obs_data_set_int(obj, "autoStartEvent",
static_cast<int>(autoStartEvent));
obs_data_set_bool(obj, "verbose", verbose);
obs_data_set_int(obj, "logLevel", static_cast<int>(logLevel));
obs_data_set_bool(obj, "showSystemTrayNotifications",
showSystemTrayNotifications);
obs_data_set_bool(obj, "disableHints", disableHints);
@@ -649,7 +648,7 @@ void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
autoStartEvent =
static_cast<AutoStart>(obs_data_get_int(obj, "autoStartEvent"));
verbose = obs_data_get_bool(obj, "verbose");
logLevel = static_cast<LogLevel>(obs_data_get_int(obj, "logLevel"));
showSystemTrayNotifications =
obs_data_get_bool(obj, "showSystemTrayNotifications");
disableHints = obs_data_get_bool(obj, "disableHints");
@@ -940,7 +939,8 @@ void AdvSceneSwitcher::SetupGeneralTab()
SIGNAL(DurationChanged(const Duration &)), this,
SLOT(CooldownDurationChanged(const Duration &)));
ui->verboseLogging->setChecked(switcher->verbose);
ui->logLevel->setCurrentIndex(static_cast<int>(switcher->logLevel));
ui->saveWindowGeo->setChecked(switcher->saveWindowGeo);
ui->showTrayNotifications->setChecked(
switcher->showSystemTrayNotifications);

View File

@@ -104,7 +104,7 @@ void SwitcherData::checkAudioSwitchFallback(OBSWeakSource &scene,
scene = audioFallback.getScene();
transition = audioFallback.transition;
if (verbose) {
if (VerboseLoggingEnabled()) {
audioFallback.logMatch();
}
}
@@ -165,7 +165,7 @@ bool SwitcherData::checkAudioSwitch(OBSWeakSource &scene,
transition = s.transition;
match = true;
if (verbose) {
if (VerboseLoggingEnabled()) {
s.logMatch();
}

View File

@@ -119,7 +119,7 @@ bool SwitcherData::checkExeSwitch(OBSWeakSource &scene,
scene = s.getScene();
transition = s.transition;
if (verbose) {
if (VerboseLoggingEnabled()) {
s.logMatch();
}
break;

View File

@@ -274,7 +274,7 @@ bool SwitcherData::checkFileContent(OBSWeakSource &scene,
transition = s.transition;
match = true;
if (verbose) {
if (VerboseLoggingEnabled()) {
s.logMatch();
}
break;

View File

@@ -53,7 +53,7 @@ bool SwitcherData::checkIdleSwitch(OBSWeakSource &scene,
match = true;
idleData.alreadySwitched = true;
if (verbose) {
if (VerboseLoggingEnabled()) {
idleData.logMatch();
}
} else {

View File

@@ -193,7 +193,7 @@ bool SwitcherData::checkMediaSwitch(OBSWeakSource &scene,
scene = mediaSwitch.getScene();
transition = mediaSwitch.transition;
if (verbose) {
if (VerboseLoggingEnabled()) {
mediaSwitch.logMatch();
}
}

View File

@@ -253,7 +253,7 @@ void WSServer::sendMessage(SceneSwitchInfo sceneSwitch, bool preview)
}
}
if (switcher->verbose) {
if (VerboseLoggingEnabled()) {
blog(LOG_INFO, "server sent message:\n%s", message.c_str());
}
}
@@ -305,7 +305,7 @@ std::string processMessage(std::string payload)
std::string ret = "message ok";
auto transition = GetWeakTransitionByName(transitionName.c_str());
if (switcher->verbose && !transition) {
if (VerboseLoggingEnabled() && !transition) {
ret += " - ignoring invalid transition: '" + transitionName +
"'";
}
@@ -481,7 +481,7 @@ void WSClient::onMessage(connection_hdl hdl, client::message_ptr message)
errorCodeMessage.c_str());
}
if (switcher->verbose) {
if (VerboseLoggingEnabled()) {
blog(LOG_INFO, "client sent message:\n%s", response.c_str());
}
}

View File

@@ -76,7 +76,7 @@ bool SwitcherData::checkRandom(OBSWeakSource &scene, OBSWeakSource &transition,
lastRandomScene = r.scene;
lastRandomSceneGroup = r.group;
if (verbose) {
if (VerboseLoggingEnabled()) {
r.logMatch();
}
break;

View File

@@ -183,7 +183,7 @@ bool SwitcherData::checkScreenRegionSwitch(OBSWeakSource &scene,
transition = s.transition;
minRegionSize = regionSize;
if (verbose) {
if (VerboseLoggingEnabled()) {
s.logMatch();
}
break;

View File

@@ -225,13 +225,13 @@ bool SwitcherData::checkSceneSequence(OBSWeakSource &scene,
scene = s.getScene();
transition = s.transition;
setPrevSceneAfterLinger = s.usePreviousScene;
if (verbose) {
if (VerboseLoggingEnabled()) {
s.logMatch();
}
}
s.advanceActiveSequence();
if (verbose) {
if (VerboseLoggingEnabled()) {
s.logAdvanceSequence();
}

View File

@@ -142,7 +142,7 @@ bool SwitcherData::checkTimeSwitch(OBSWeakSource &scene,
transition = s.transition;
match = true;
if (verbose) {
if (VerboseLoggingEnabled()) {
s.logMatch();
}
break;

View File

@@ -168,7 +168,7 @@ void SwitcherData::checkDefaultSceneTransitions()
for (auto &t : defaultSceneTransitions) {
if (t.checkMatch(currentScene)) {
if (verbose) {
if (VerboseLoggingEnabled()) {
t.logMatch();
}
t.setTransition();
@@ -427,7 +427,8 @@ DefTransitionSwitchWidget::DefTransitionSwitchWidget(QWidget *parent,
{
QHBoxLayout *mainLayout = new QHBoxLayout;
std::unordered_map<std::string, QWidget *> widgetPlaceholders = {
{"{{scenes}}", scenes}, {"{{transitions}}", transitions}};
{"{{scenes}}", scenes},
{"{{transitions}}", transitions}};
PlaceWidgets(
obs_module_text(
"AdvSceneSwitcher.transitionTab.defaultTransitionEntry"),

View File

@@ -148,7 +148,7 @@ bool SwitcherData::checkVideoSwitch(OBSWeakSource &scene,
match = true;
scene = s.getScene();
transition = s.transition;
if (verbose) {
if (VerboseLoggingEnabled()) {
s.logMatch();
}
}

View File

@@ -249,7 +249,7 @@ bool SwitcherData::checkWindowTitleSwitch(OBSWeakSource &scene,
}
if (match) {
if (verbose) {
if (VerboseLoggingEnabled()) {
s.logMatch();
}
break;

View File

@@ -3,6 +3,7 @@
#include "macro-helpers.hpp"
#include "macro-properties.hpp"
#include "macro.hpp"
#include "plugin-state-helpers.hpp"
#include "section.hpp"
#include "switch-button.hpp"
@@ -88,6 +89,7 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
*_entryData = MacroActionFactory::Create(id, macro);
(*_entryData)->SetIndex(idx);
(*_entryData)->PostLoad();
RunPostLoadSteps();
}
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
@@ -185,9 +187,10 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
auto data = obs_data_create();
macro->Actions().at(idx - 1)->Save(data);
macro->Actions().at(idx)->Load(data);
macro->Actions().at(idx)->PostLoad();
obs_data_release(data);
}
macro->Actions().at(idx)->PostLoad();
RunPostLoadSteps();
macro->UpdateActionIndices();
ui->actionsList->Insert(
idx,
@@ -475,6 +478,7 @@ void AdvSceneSwitcher::AddMacroElseAction(int idx)
macro->ElseActions().at(idx)->Load(data);
}
macro->ElseActions().at(idx)->PostLoad();
RunPostLoadSteps();
macro->UpdateElseActionIndices();
ui->elseActionsList->Insert(
idx, new MacroActionEdit(

View File

@@ -88,32 +88,32 @@ void MacroActionMacro::LogAction() const
}
switch (_action) {
case Action::PAUSE:
vblog(LOG_INFO, "paused \"%s\"", macro->Name().c_str());
ablog(LOG_INFO, "paused \"%s\"", macro->Name().c_str());
break;
case Action::UNPAUSE:
vblog(LOG_INFO, "unpaused \"%s\"", macro->Name().c_str());
ablog(LOG_INFO, "unpaused \"%s\"", macro->Name().c_str());
break;
case Action::RESET_COUNTER:
vblog(LOG_INFO, "reset counter for \"%s\"",
ablog(LOG_INFO, "reset counter for \"%s\"",
macro->Name().c_str());
break;
case Action::RUN:
vblog(LOG_INFO, "run nested macro \"%s\"",
ablog(LOG_INFO, "run nested macro \"%s\"",
macro->Name().c_str());
break;
case Action::STOP:
vblog(LOG_INFO, "stopped macro \"%s\"", macro->Name().c_str());
ablog(LOG_INFO, "stopped macro \"%s\"", macro->Name().c_str());
break;
case Action::DISABLE_ACTION:
vblog(LOG_INFO, "disabled action %d of macro \"%s\"",
ablog(LOG_INFO, "disabled action %d of macro \"%s\"",
_actionIndex.GetValue(), macro->Name().c_str());
break;
case Action::ENABLE_ACTION:
vblog(LOG_INFO, "enabled action %d of macro \"%s\"",
ablog(LOG_INFO, "enabled action %d of macro \"%s\"",
_actionIndex.GetValue(), macro->Name().c_str());
break;
case Action::TOGGLE_ACTION:
vblog(LOG_INFO, "toggled action %d of macro \"%s\"",
ablog(LOG_INFO, "toggled action %d of macro \"%s\"",
_actionIndex.GetValue(), macro->Name().c_str());
break;
default:
@@ -145,6 +145,21 @@ std::string MacroActionMacro::GetShortDesc() const
return _macro.Name();
}
std::shared_ptr<MacroAction> MacroActionMacro::Create(Macro *m)
{
return std::make_shared<MacroActionMacro>(m);
}
std::shared_ptr<MacroAction> MacroActionMacro::Copy() const
{
return std::make_shared<MacroActionMacro>(*this);
}
void MacroActionMacro::ResolveVariablesToFixedValues()
{
_actionIndex.ResolveVariables();
}
static inline void populateActionSelection(QComboBox *list)
{
for (auto entry : actionTypes) {

View File

@@ -16,10 +16,9 @@ public:
bool Load(obs_data_t *obj);
std::string GetShortDesc() const;
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionMacro>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
void ResolveVariablesToFixedValues();
enum class Action {
PAUSE,

View File

@@ -69,20 +69,20 @@ void MacroActionQueue::LogAction() const
}
switch (_action) {
case Action::ADD_TO_QUEUE:
vblog(LOG_INFO, "queued actions of \"%s\" to \"%s\"",
ablog(LOG_INFO, "queued actions of \"%s\" to \"%s\"",
GetMacroName(macro.get()).c_str(),
GetActionQueueName(_queue).c_str());
break;
case Action::START_QUEUE:
vblog(LOG_INFO, "start queue \"%s\"",
ablog(LOG_INFO, "start queue \"%s\"",
GetActionQueueName(_queue).c_str());
break;
case Action::STOP_QUEUE:
vblog(LOG_INFO, "stop queue \"%s\"",
ablog(LOG_INFO, "stop queue \"%s\"",
GetActionQueueName(_queue).c_str());
break;
case Action::CLEAR_QUEUE:
vblog(LOG_INFO, "cleared queue \"%s\"",
ablog(LOG_INFO, "cleared queue \"%s\"",
GetActionQueueName(_queue).c_str());
break;
default:
@@ -114,6 +114,16 @@ std::string MacroActionQueue::GetShortDesc() const
return GetActionQueueName(_queue);
}
std::shared_ptr<MacroAction> MacroActionQueue::Create(Macro *m)
{
return std::make_shared<MacroActionQueue>(m);
}
std::shared_ptr<MacroAction> MacroActionQueue::Copy() const
{
return std::make_shared<MacroActionQueue>(*this);
}
static inline void populateActionSelection(QComboBox *list)
{
for (const auto &[_, name] : actionTypes) {

View File

@@ -16,10 +16,8 @@ public:
bool Load(obs_data_t *obj);
std::string GetShortDesc() const;
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionQueue>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
enum class Action {
ADD_TO_QUEUE,

View File

@@ -198,7 +198,8 @@ void MacroActionVariable::SetToSceneItemName(Variable *var)
struct AskForInputParams {
AskForInputParams(const QString &prompt_, const QString &placeholder_)
: prompt(prompt_), placeholder(placeholder_){};
: prompt(prompt_),
placeholder(placeholder_){};
QString prompt;
QString placeholder;
std::optional<std::string> result;
@@ -422,6 +423,16 @@ std::string MacroActionVariable::GetShortDesc() const
return GetWeakVariableName(_variable);
}
std::shared_ptr<MacroAction> MacroActionVariable::Create(Macro *m)
{
return std::make_shared<MacroActionVariable>(m);
}
std::shared_ptr<MacroAction> MacroActionVariable::Copy() const
{
return std::make_shared<MacroActionVariable>(*this);
}
void MacroActionVariable::SetSegmentIndexValue(int value)
{
DecrementCurrentSegmentVariableRef();
@@ -485,6 +496,19 @@ int MacroActionVariable::GetSegmentIndexValue() const
return -1;
}
void MacroActionVariable::ResolveVariablesToFixedValues()
{
_strValue.ResolveVariables();
_findStr.ResolveVariables();
_replaceStr.ResolveVariables();
_mathExpression.ResolveVariables();
_inputPrompt.ResolveVariables();
_inputPlaceholder.ResolveVariables();
_envVariableName.ResolveVariables();
_scene.ResolveVariables();
_sceneItemIndex.ResolveVariables();
}
void MacroActionVariable::DecrementCurrentSegmentVariableRef()
{
auto segment = _macroSegment.lock();

View File

@@ -20,12 +20,11 @@ public:
bool PostLoad() override;
std::string GetShortDesc() const;
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionVariable>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
void SetSegmentIndexValue(int);
int GetSegmentIndexValue() const;
void ResolveVariablesToFixedValues();
enum class Type {
SET_FIXED_VALUE,

View File

@@ -25,7 +25,7 @@ bool MacroAction::Load(obs_data_t *obj)
void MacroAction::LogAction() const
{
vblog(LOG_INFO, "performed action %s", GetId().c_str());
ablog(LOG_INFO, "performed action %s", GetId().c_str());
}
void MacroAction::SetEnabled(bool value)
@@ -38,6 +38,8 @@ bool MacroAction::Enabled() const
return _enabled;
}
void MacroAction::ResolveVariablesToFixedValues() {}
std::string_view MacroAction::GetDefaultID()
{
return "scene_switch";

View File

@@ -8,10 +8,17 @@ class EXPORT MacroAction : public MacroSegment {
public:
MacroAction(Macro *m, bool supportsVariableValue = false);
virtual ~MacroAction() = default;
virtual std::shared_ptr<MacroAction> Copy() const = 0;
virtual bool PerformAction() = 0;
virtual void LogAction() const;
virtual bool Save(obs_data_t *obj) const = 0;
virtual bool Load(obs_data_t *obj) = 0;
virtual void LogAction() const;
// Used to resolve variables before actions are added to action queues
virtual void ResolveVariablesToFixedValues();
void SetEnabled(bool);
bool Enabled() const;

View File

@@ -3,6 +3,7 @@
#include "macro-properties.hpp"
#include "macro.hpp"
#include "path-helpers.hpp"
#include "plugin-state-helpers.hpp"
#include "section.hpp"
#include "ui-helpers.hpp"
#include "utility.hpp"
@@ -254,6 +255,7 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
(*_entryData)->SetIndex(idx);
(*_entryData)->SetLogicType(logic);
(*_entryData)->PostLoad();
RunPostLoadSteps();
}
auto widget =
MacroConditionFactory::CreateWidget(id, this, *_entryData);
@@ -325,6 +327,7 @@ void AdvSceneSwitcher::AddMacroCondition(int idx)
obs_data_release(data);
}
macro->Conditions().at(idx)->PostLoad();
RunPostLoadSteps();
(*cond)->SetLogicType(logic);
macro->UpdateConditionIndices();
ui->conditionsList->Insert(

View File

@@ -96,11 +96,15 @@ void MacroRunButton::Pressed()
bool ret = _elseStateActive ? macro->PerformActions(false, true, true)
: macro->PerformActions(true, true, true);
if (ret) {
return;
}
if (!ret) {
QString err =
obs_module_text("AdvSceneSwitcher.macroTab.runFail");
DisplayMessage(err.arg(QString::fromStdString(macro->Name())));
QString err = obs_module_text("AdvSceneSwitcher.macroTab.runFail");
const bool abortMacro = DisplayMessage(
err.arg(QString::fromStdString(macro->Name())), true);
if (abortMacro) {
macro->Stop();
}
}

View File

@@ -4,7 +4,6 @@
#include "section.hpp"
#include "ui-helpers.hpp"
#include <obs.hpp>
#include <QApplication>
#include <QEvent>
#include <QLabel>

View File

@@ -11,7 +11,7 @@
#include <QFrame>
#include <QVBoxLayout>
#include <QTimer>
#include <obs.hpp>
#include <obs-data.h>
class QLabel;
@@ -116,8 +116,8 @@ private:
void ShowDropLine(DropLineState);
// The reason for using two separate frame widget each with their own
// stylesheet and changing their visibility vs. using a single frame
// The reason for using two separate frame widgets, each with their own
// stylesheet, and changing their visibility vs. using a single frame
// and changing the stylesheet at runtime is that the operation of
// adjusting the stylesheet is very expensive and can take multiple
// hundred milliseconds per widget.

View File

@@ -13,6 +13,7 @@
#include "utility.hpp"
#include "version.h"
#include <obs-frontend-api.h>
#include <QColor>
#include <QGraphicsOpacityEffect>
#include <QMenu>
@@ -729,6 +730,7 @@ void AdvSceneSwitcher::MacroSelectionChanged()
return;
}
SetEditMacro(*macro);
obs_frontend_save();
}
void AdvSceneSwitcher::HighlightOnChange()

View File

@@ -13,7 +13,7 @@
#include <memory>
#include <map>
#include <thread>
#include <obs-data.h>
#include <obs.hpp>
#include <obs-module-helper.hpp>
namespace advss {

View File

@@ -141,7 +141,9 @@ public:
bool showSystemTrayNotifications = false;
bool transitionOverrideOverride = false;
bool adjustActiveTransitionType = true;
bool verbose = false;
enum class LogLevel { DEFAULT, PRINT_ACTION, VERBOSE };
LogLevel logLevel = LogLevel::DEFAULT;
/* --- End of General tab section --- */

View File

@@ -33,6 +33,7 @@ void ActionQueue::Save(obs_data_t *obj) const
{
obs_data_set_string(obj, "name", _name.c_str());
obs_data_set_bool(obj, "runOnStartup", _runOnStartup);
obs_data_set_bool(obj, "resolveVariablesOnAdd", _resolveVariablesOnAdd);
}
void ActionQueue::Load(obs_data_t *obj)
@@ -40,6 +41,8 @@ void ActionQueue::Load(obs_data_t *obj)
std::lock_guard<std::mutex> lock(_mutex);
_name = obs_data_get_string(obj, "name");
_runOnStartup = obs_data_get_bool(obj, "runOnStartup");
_resolveVariablesOnAdd =
obs_data_get_bool(obj, "resolveVariablesOnAdd");
if (_runOnStartup) {
Start();
@@ -80,10 +83,21 @@ void ActionQueue::Clear()
_actions.clear();
}
void ActionQueue::Add(const std::shared_ptr<MacroAction> &actions)
void ActionQueue::Add(const std::shared_ptr<MacroAction> &action)
{
std::lock_guard<std::mutex> lock(_mutex);
_actions.emplace_back(actions);
if (_resolveVariablesOnAdd) {
auto copy = action->Copy();
copy->GetMacro();
OBSDataAutoRelease data = obs_data_create();
action->Save(data);
copy->Load(data);
copy->PostLoad();
copy->ResolveVariablesToFixedValues();
_actions.emplace_back(copy);
} else {
_actions.emplace_back(action);
}
_cv.notify_all();
}
@@ -120,8 +134,11 @@ void ActionQueue::RunActions()
continue;
}
vblog(LOG_INFO, "Performing action '%s' in queue '%s'",
action->GetId().c_str(), _name.c_str());
if (ActionLoggingEnabled()) {
blog(LOG_INFO, "Performing action '%s' in queue '%s'",
action->GetId().c_str(), _name.c_str());
action->LogAction();
}
action->PerformAction();
}
}
@@ -139,6 +156,7 @@ ActionQueueSettingsDialog::ActionQueueSettingsDialog(QWidget *parent,
_clear(new QPushButton(
obs_module_text("AdvSceneSwitcher.actionQueues.clear"))),
_runOnStartup(new QCheckBox()),
_resolveVariablesOnAdd(new QCheckBox()),
_queue(settings)
{
QWidget::connect(_startStopToggle, SIGNAL(clicked()), this,
@@ -146,6 +164,7 @@ ActionQueueSettingsDialog::ActionQueueSettingsDialog(QWidget *parent,
QWidget::connect(_clear, SIGNAL(clicked()), this, SLOT(ClearClicked()));
_runOnStartup->setChecked(settings._runOnStartup);
_resolveVariablesOnAdd->setChecked(settings._resolveVariablesOnAdd);
UpdateLabels();
auto layout = new QGridLayout();
@@ -167,6 +186,14 @@ ActionQueueSettingsDialog::ActionQueueSettingsDialog(QWidget *parent,
_runOnStartup->setToolTip(
obs_module_text("AdvSceneSwitcher.actionQueues.runOnStartup"));
++row;
layout->addWidget(
new QLabel(obs_module_text(
"AdvSceneSwitcher.actionQueues.resolveVariablesOnAdd")),
row, 0);
layout->addWidget(_resolveVariablesOnAdd, row, 1);
_resolveVariablesOnAdd->setToolTip(obs_module_text(
"AdvSceneSwitcher.actionQueues.resolveVariablesOnAdd"));
++row;
layout->addWidget(_queueRunStatus, row, 0);
layout->addWidget(_startStopToggle, row, 1);
++row;
@@ -194,6 +221,8 @@ bool ActionQueueSettingsDialog::AskForSettings(QWidget *parent,
settings._name = dialog._name->text().toStdString();
settings._runOnStartup = dialog._runOnStartup->isChecked();
settings._resolveVariablesOnAdd =
dialog._resolveVariablesOnAdd->isChecked();
return true;
}

View File

@@ -38,6 +38,7 @@ private:
void RunActions();
bool _runOnStartup = true;
bool _resolveVariablesOnAdd = true;
std::atomic_bool _stop = {false};
std::mutex _mutex;
std::condition_variable _cv;
@@ -66,6 +67,7 @@ private:
QLabel *_queueSize;
QPushButton *_clear;
QCheckBox *_runOnStartup;
QCheckBox *_resolveVariablesOnAdd;
ActionQueue &_queue;
};

86
lib/utils/backup.cpp Normal file
View File

@@ -0,0 +1,86 @@
#include "backup.hpp"
#include "log-helper.hpp"
#include "obs-module-helper.hpp"
#include "path-helpers.hpp"
#include "plugin-state-helpers.hpp"
#include "ui-helpers.hpp"
#include "version.h"
#include <obs-frontend-api.h>
#include <obs-module.h>
#include <QFileDialog>
#include <QTextStream>
#include <util/config-file.h>
namespace advss {
void AskForBackup(const QString &json)
{
const bool backupWasConfirmed = DisplayMessage(
obs_module_text("AdvSceneSwitcher.askBackup"), true, false);
if (!backupWasConfirmed) {
return;
}
QString path = QFileDialog::getSaveFileName(
nullptr,
obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle"),
GetDefaultSettingsSaveLocation(),
obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType"));
if (path.isEmpty()) {
return;
}
QFile file(path);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return;
}
auto out = QTextStream(&file);
out << json;
}
void BackupSettingsOfCurrentVersion()
{
auto sceneCollectionName = obs_frontend_get_current_scene_collection();
const std::string fileName =
std::string("settings-backup-") +
(sceneCollectionName ? sceneCollectionName : "-") + "-" +
g_GIT_TAG + ".json";
bfree(sceneCollectionName);
auto settingsFile = obs_module_config_path(fileName.c_str());
if (!settingsFile) {
return;
}
QString dirPath = QFileInfo(settingsFile).absolutePath();
QDir dir(dirPath);
if (!dir.exists()) {
if (!dir.mkpath(dirPath)) {
blog(LOG_WARNING,
"failed to create directory to save automated backup");
bfree(settingsFile);
return;
}
}
QFile file(settingsFile);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
bfree(settingsFile);
return;
}
OBSDataAutoRelease data = obs_data_create();
SavePluginSettings(data);
auto settings = obs_data_get_json(data);
QString settingsString = QString(settings ? settings : "");
auto out = QTextStream(&file);
out << settingsString;
bfree(settingsFile);
}
} // namespace advss

9
lib/utils/backup.hpp Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#include <QString>
namespace advss {
void AskForBackup(const QString &json);
void BackupSettingsOfCurrentVersion();
} // namespace advss

View File

@@ -1,9 +1,9 @@
#include "curl-helper.hpp"
#include "log-helper.hpp"
#include <QDir>
#include <QFileInfo>
#include <curl/curl.h>
#include <obs.hpp>
namespace advss {

View File

@@ -165,4 +165,9 @@ void Duration::SetUnit(Unit u)
_value = _value * (prevMultiplier / newMultiplier);
}
void Duration::ResolveVariables()
{
_value.ResolveVariables();
}
} // namespace advss

View File

@@ -34,8 +34,10 @@ public:
// Only use this function if you intend to convert old settings formats
EXPORT void SetUnit(Unit u);
EXPORT void ResolveVariables();
private:
NumberVariable<double> _value = 0.;
DoubleVariable _value = 0.;
Unit _unit = Unit::SECONDS;
std::chrono::high_resolution_clock::time_point _startTime;

View File

@@ -5,7 +5,16 @@ namespace advss {
bool VerboseLoggingEnabled()
{
return GetSwitcher() && GetSwitcher()->verbose;
return GetSwitcher() &&
GetSwitcher()->logLevel == SwitcherData::LogLevel::VERBOSE;
}
bool ActionLoggingEnabled()
{
return GetSwitcher() &&
(GetSwitcher()->logLevel ==
SwitcherData::LogLevel::PRINT_ACTION ||
GetSwitcher()->logLevel == SwitcherData::LogLevel::VERBOSE);
}
} // namespace advss

View File

@@ -3,14 +3,26 @@
namespace advss {
// Print log with "[adv-ss] " prefix
#define blog(level, msg, ...) blog(level, "[adv-ss] " msg, ##__VA_ARGS__)
// Print log with "[adv-ss] " if log level is set to "verbose"
#define vblog(level, msg, ...) \
do { \
if (VerboseLoggingEnabled()) { \
blog(level, msg, ##__VA_ARGS__); \
} \
} while (0)
// Print log with "[adv-ss] " if log level is set to "action" or "verbose"
#define ablog(level, msg, ...) \
do { \
if (ActionLoggingEnabled()) { \
blog(level, msg, ##__VA_ARGS__); \
} \
} while (0)
// Returns true if log level is set to "verbose"
EXPORT bool VerboseLoggingEnabled();
// Returns true if log level is set to "action" or "verbose"
EXPORT bool ActionLoggingEnabled();
} // namespace advss

View File

@@ -3,6 +3,11 @@
namespace advss {
void SavePluginSettings(obs_data_t *obj)
{
GetSwitcher()->SaveSettings(obj);
}
void LoadPluginSettings(obs_data_t *obj)
{
GetSwitcher()->LoadSettings(obj);

View File

@@ -5,6 +5,7 @@
namespace advss {
void SavePluginSettings(obs_data_t *);
EXPORT void LoadPluginSettings(obs_data_t *);
EXPORT void AddSaveStep(std::function<void(obs_data_t *)>);

View File

@@ -181,6 +181,12 @@ std::string SceneSelection::ToString(bool resolve) const
return "";
}
void SceneSelection::ResolveVariables()
{
_scene = GetScene();
_type = Type::SCENE;
}
SceneSelection SceneSelectionWidget::CurrentSelection()
{
SceneSelection s;

View File

@@ -26,6 +26,7 @@ public:
EXPORT Type GetType() const { return _type; }
EXPORT OBSWeakSource GetScene(bool advance = true) const;
EXPORT std::string ToString(bool resolve = false) const;
EXPORT void ResolveVariables();
private:
OBSWeakSource _scene;

View File

@@ -2,7 +2,6 @@
#include "export-symbol-helper.hpp"
#include <deque>
#include <obs.hpp>
#include <QComboBox>
#include <QStringList>
#include <string>

View File

@@ -88,6 +88,11 @@ void SourceSelection::SetSource(OBSWeakSource source)
_source = source;
}
void SourceSelection::ResolveVariables()
{
SetSource(GetSource());
}
std::string SourceSelection::ToString(bool resolve) const
{
switch (_type) {

View File

@@ -19,6 +19,7 @@ public:
EXPORT Type GetType() const { return _type; }
EXPORT OBSWeakSource GetSource() const;
EXPORT void SetSource(OBSWeakSource);
EXPORT void ResolveVariables();
EXPORT std::string ToString(bool resolve = false) const;
EXPORT bool operator==(const SourceSelection &) const;

View File

@@ -1,7 +1,7 @@
#pragma once
#include "filter-combo-box.hpp"
#include <obs.hpp>
#include <obs-data.h>
#include <mutex>
#include <optional>
#include <QEnterEvent>

View File

@@ -3,7 +3,6 @@
#include "obs-module-helper.hpp"
#include <obs-frontend-api.h>
#include <obs.hpp>
#include <QGraphicsColorizeEffect>
#include <QMainWindow>
#include <QPropertyAnimation>

View File

@@ -1,8 +1,6 @@
#pragma once
#include "variable.hpp"
#include <obs.hpp>
namespace advss {
template<typename T> class NumberVariable {
@@ -24,6 +22,7 @@ public:
Type GetType() const { return _type; }
bool IsFixedType() const { return _type == Type::FIXED_VALUE; }
std::weak_ptr<Variable> GetVariable() const { return _variable; }
void ResolveVariables();
private:
Type _type = Type::FIXED_VALUE;

View File

@@ -93,3 +93,9 @@ template<typename T> NumberVariable<T>::operator T() const
{
return GetValue();
}
template<typename T> void NumberVariable<T>::ResolveVariables()
{
_value = GetValue();
_type = Type::FIXED_VALUE;
}

View File

@@ -50,6 +50,12 @@ void StringVariable::Save(obs_data_t *obj, const char *name) const
obs_data_set_string(obj, name, _value.c_str());
}
void StringVariable::ResolveVariables()
{
Resolve();
_value = _resolvedValue;
}
const char *StringVariable::c_str()
{
Resolve();

View File

@@ -2,7 +2,7 @@
#include "variable.hpp"
#include <string>
#include <obs.hpp>
#include <obs-data.h>
namespace advss {
@@ -27,6 +27,8 @@ public:
EXPORT void Load(obs_data_t *obj, const char *name);
EXPORT void Save(obs_data_t *obj, const char *name) const;
EXPORT void ResolveVariables();
private:
void Resolve() const;

View File

@@ -102,7 +102,6 @@ static void removeVariableRow(QTableWidget *table, const QString &name)
static void updateVaribleStatus(QTableWidget *table)
{
auto lock = LockContext();
for (int row = 0; row < table->rowCount(); row++) {
auto item = table->item(row, 0);
if (!item) {

View File

@@ -267,6 +267,7 @@ bool VariableSettingsDialog::AskForSettings(QWidget *parent, Variable &settings)
dialog._defaultValue->toPlainText().toStdString();
settings._saveAction =
static_cast<Variable::SaveAction>(dialog._save->currentIndex());
lastVariableChange = std::chrono::high_resolution_clock::now();
return true;
}
@@ -274,7 +275,6 @@ static bool AskForSettingsWrapper(QWidget *parent, Item &settings)
{
Variable &VariableSettings = dynamic_cast<Variable &>(settings);
if (VariableSettingsDialog::AskForSettings(parent, VariableSettings)) {
lastVariableChange = std::chrono::high_resolution_clock::now();
return true;
}
return false;

View File

@@ -17,6 +17,8 @@ target_sources(
macro-action-hotkey.hpp
macro-action-http.cpp
macro-action-http.hpp
macro-action-log.cpp
macro-action-log.hpp
macro-action-media.cpp
macro-action-media.hpp
macro-action-osc.cpp
@@ -69,6 +71,8 @@ target_sources(
macro-action-wait.hpp
macro-action-websocket.cpp
macro-action-websocket.hpp
macro-action-window.cpp
macro-action-window.hpp
macro-condition-audio.cpp
macro-condition-audio.hpp
macro-condition-cursor.cpp

View File

@@ -244,7 +244,7 @@ void MacroActionAudio::LogAction() const
auto it = actionTypes.find(_action);
if (it != actionTypes.end()) {
auto &[_, action] = *it;
vblog(LOG_INFO,
ablog(LOG_INFO,
"performed action \"%s\" for source \"%s\" with volume %f with fade %d %f",
action.c_str(), _audioSource.ToString(true).c_str(),
GetVolume(), _fade, _duration.Seconds());
@@ -328,6 +328,27 @@ std::string MacroActionAudio::GetShortDesc() const
return _audioSource.ToString();
}
std::shared_ptr<MacroAction> MacroActionAudio::Create(Macro *m)
{
return std::make_shared<MacroActionAudio>(m);
}
std::shared_ptr<MacroAction> MacroActionAudio::Copy() const
{
return std::make_shared<MacroActionAudio>(*this);
}
void MacroActionAudio::ResolveVariablesToFixedValues()
{
_audioSource.ResolveVariables();
_syncOffset.ResolveVariables();
_balance.ResolveVariables();
_volume.ResolveVariables();
_volumeDB.ResolveVariables();
_duration.ResolveVariables();
_rate.ResolveVariables();
}
static inline void populateActionSelection(QComboBox *list)
{
for (const auto &[action, name] : actionTypes) {

View File

@@ -20,10 +20,9 @@ public:
bool Load(obs_data_t *obj);
std::string GetShortDesc() const;
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionAudio>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
void ResolveVariablesToFixedValues();
SourceSelection _audioSource;
@@ -44,15 +43,15 @@ public:
Action _action = Action::MUTE;
FadeType _fadeType = FadeType::DURATION;
NumberVariable<int> _syncOffset = 0;
IntVariable _syncOffset = 0;
obs_monitoring_type _monitorType = OBS_MONITORING_TYPE_NONE;
NumberVariable<double> _balance = 0.5;
DoubleVariable _balance = 0.5;
bool _useDb = false;
NumberVariable<int> _volume = 0;
NumberVariable<double> _volumeDB = 0.0;
IntVariable _volume = 0;
DoubleVariable _volumeDB = 0.0;
bool _fade = false;
Duration _duration;
NumberVariable<double> _rate = 100.;
DoubleVariable _rate = 100.;
bool _wait = false;
bool _abortActiveFade = false;

View File

@@ -1,6 +1,7 @@
#include "macro-action-clipboard.hpp"
#include "curl-helper.hpp"
#include <obs.hpp>
#include <QApplication>
#include <QClipboard>
#include <QImage>
@@ -92,6 +93,16 @@ static void copyImageFromUrl(void *param)
setMimeTypeParams(params, clipboard);
}
std::shared_ptr<MacroAction> MacroActionClipboard::Create(Macro *m)
{
return std::make_shared<MacroActionClipboard>(m);
}
std::shared_ptr<MacroAction> MacroActionClipboard::Copy() const
{
return std::make_shared<MacroActionClipboard>(*this);
}
bool MacroActionClipboard::PerformAction()
{
switch (_action) {
@@ -158,6 +169,12 @@ bool MacroActionClipboard::Load(obs_data_t *obj)
return true;
}
void MacroActionClipboard::ResolveVariablesToFixedValues()
{
_text.ResolveVariables();
_url.ResolveVariables();
}
static inline void populateActionSelection(QComboBox *list)
{
for (const auto &[action, name] : actionTypes) {

View File

@@ -22,16 +22,16 @@ struct ClipboardImageQueueParams : ClipboardQueueParams {
class MacroActionClipboard : public MacroAction {
public:
MacroActionClipboard(Macro *m) : MacroAction(m) {}
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionClipboard>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
std::string GetId() const { return id; };
bool PerformAction();
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
void ResolveVariablesToFixedValues();
enum class Action {
COPY_TEXT,
COPY_IMAGE,

View File

@@ -14,9 +14,11 @@ bool MacroActionFile::_registered = MacroActionFactory::Register(
{MacroActionFile::Create, MacroActionFileEdit::Create,
"AdvSceneSwitcher.action.file"});
const static std::map<FileAction, std::string> actionTypes = {
{FileAction::WRITE, "AdvSceneSwitcher.action.file.type.write"},
{FileAction::APPEND, "AdvSceneSwitcher.action.file.type.append"},
static const std::map<MacroActionFile::Action, std::string> actionTypes = {
{MacroActionFile::Action::WRITE,
"AdvSceneSwitcher.action.file.type.write"},
{MacroActionFile::Action::APPEND,
"AdvSceneSwitcher.action.file.type.append"},
};
bool MacroActionFile::PerformAction()
@@ -25,10 +27,10 @@ bool MacroActionFile::PerformAction()
QFile file(path);
bool open = false;
switch (_action) {
case FileAction::WRITE:
case Action::WRITE:
open = file.open(QIODevice::WriteOnly);
break;
case FileAction::APPEND:
case Action::APPEND:
open = file.open(QIODevice::WriteOnly | QIODevice::Append);
break;
default:
@@ -45,7 +47,7 @@ void MacroActionFile::LogAction() const
{
auto it = actionTypes.find(_action);
if (it != actionTypes.end()) {
vblog(LOG_INFO, "performed action \"%s\" for file \"%s\"",
ablog(LOG_INFO, "performed action \"%s\" for file \"%s\"",
it->second.c_str(), _file.c_str());
} else {
blog(LOG_WARNING, "ignored unknown file action %d",
@@ -67,7 +69,7 @@ bool MacroActionFile::Load(obs_data_t *obj)
MacroAction::Load(obj);
_file.Load(obj, "file");
_text.Load(obj, "text");
_action = static_cast<FileAction>(obs_data_get_int(obj, "action"));
_action = static_cast<Action>(obs_data_get_int(obj, "action"));
return true;
}
@@ -76,21 +78,36 @@ std::string MacroActionFile::GetShortDesc() const
return _file.UnresolvedValue();
}
std::shared_ptr<MacroAction> MacroActionFile::Create(Macro *m)
{
return std::make_shared<MacroActionFile>(m);
}
std::shared_ptr<MacroAction> MacroActionFile::Copy() const
{
return std::make_shared<MacroActionFile>(*this);
}
void MacroActionFile::ResolveVariablesToFixedValues()
{
_file.ResolveVariables();
_text.ResolveVariables();
}
static inline void populateActionSelection(QComboBox *list)
{
for (auto entry : actionTypes) {
list->addItem(obs_module_text(entry.second.c_str()));
for (const auto &[_, name] : actionTypes) {
list->addItem(obs_module_text(name.c_str()));
}
}
MacroActionFileEdit::MacroActionFileEdit(
QWidget *parent, std::shared_ptr<MacroActionFile> entryData)
: QWidget(parent)
: QWidget(parent),
_filePath(new FileSelection(FileSelection::Type::WRITE)),
_text(new VariableTextEdit(this)),
_actions(new QComboBox())
{
_filePath = new FileSelection(FileSelection::Type::WRITE);
_text = new VariableTextEdit(this);
_actions = new QComboBox();
populateActionSelection(_actions);
QWidget::connect(_actions, SIGNAL(currentIndexChanged(int)), this,
@@ -166,7 +183,7 @@ void MacroActionFileEdit::ActionChanged(int value)
}
auto lock = LockContext();
_entryData->_action = static_cast<FileAction>(value);
_entryData->_action = static_cast<MacroActionFile::Action>(value);
}
} // namespace advss

View File

@@ -7,11 +7,6 @@
namespace advss {
enum class FileAction {
WRITE,
APPEND,
};
class MacroActionFile : public MacroAction {
public:
MacroActionFile(Macro *m) : MacroAction(m) {}
@@ -21,14 +16,18 @@ public:
bool Load(obs_data_t *obj);
std::string GetShortDesc() const;
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionFile>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
void ResolveVariablesToFixedValues();
StringVariable _file = obs_module_text("AdvSceneSwitcher.enterPath");
StringVariable _text = obs_module_text("AdvSceneSwitcher.enterText");
FileAction _action = FileAction::WRITE;
enum class Action {
WRITE,
APPEND,
};
Action _action = Action::WRITE;
private:
static bool _registered;
@@ -58,13 +57,12 @@ private slots:
signals:
void HeaderInfoChanged(const QString &);
protected:
private:
FileSelection *_filePath;
VariableTextEdit *_text;
QComboBox *_actions;
std::shared_ptr<MacroActionFile> _entryData;
private:
std::shared_ptr<MacroActionFile> _entryData;
bool _loading = true;
};

View File

@@ -94,7 +94,7 @@ void MacroActionFilter::LogAction() const
{
auto it = actionTypes.find(_action);
if (it != actionTypes.end()) {
vblog(LOG_INFO,
ablog(LOG_INFO,
"performed action \"%s\" for filter \"%s\" on source \"%s\"",
it->second.c_str(), _filter.ToString().c_str(),
_source.ToString(true).c_str());
@@ -158,6 +158,24 @@ std::string MacroActionFilter::GetShortDesc() const
return "";
}
std::shared_ptr<MacroAction> MacroActionFilter::Create(Macro *m)
{
return std::make_shared<MacroActionFilter>(m);
}
std::shared_ptr<MacroAction> MacroActionFilter::Copy() const
{
return std::make_shared<MacroActionFilter>(*this);
}
void MacroActionFilter::ResolveVariablesToFixedValues()
{
_source.ResolveVariables();
_filter.ResolveVariables();
_settingsString.ResolveVariables();
_manualSettingValue.ResolveVariables();
}
static inline void populateActionSelection(QComboBox *list)
{
for (auto entry : actionTypes) {

View File

@@ -20,10 +20,9 @@ public:
bool Load(obs_data_t *obj);
std::string GetShortDesc() const;
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionFilter>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
void ResolveVariablesToFixedValues();
enum class Action {
ENABLE,

View File

@@ -371,7 +371,7 @@ bool MacroActionHotkey::PerformAction()
void MacroActionHotkey::LogAction() const
{
vblog(LOG_INFO, "sent hotkey type %d", static_cast<int>(_action));
ablog(LOG_INFO, "sent hotkey type %d", static_cast<int>(_action));
}
bool MacroActionHotkey::Save(obs_data_t *obj) const
@@ -425,6 +425,16 @@ bool MacroActionHotkey::Load(obs_data_t *obj)
return true;
}
std::shared_ptr<MacroAction> MacroActionHotkey::Create(Macro *m)
{
return std::make_shared<MacroActionHotkey>(m);
}
std::shared_ptr<MacroAction> MacroActionHotkey::Copy() const
{
return std::make_shared<MacroActionHotkey>(*this);
}
static inline void populateKeySelection(QComboBox *list)
{
list->addItems({"No key",

View File

@@ -18,10 +18,8 @@ public:
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionHotkey>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
enum class Action {
OBS_HOTKEY,

View File

@@ -95,7 +95,7 @@ void MacroActionHttp::LogAction() const
{
auto it = methods.find(_method);
if (it != methods.end()) {
vblog(LOG_INFO,
ablog(LOG_INFO,
"sent http request \"%s\" to \"%s\" with data \"%s\"",
it->second.c_str(), _url.c_str(), _data.c_str());
} else {
@@ -133,6 +133,24 @@ std::string MacroActionHttp::GetShortDesc() const
return _url.UnresolvedValue();
}
std::shared_ptr<MacroAction> MacroActionHttp::Create(Macro *m)
{
return std::make_shared<MacroActionHttp>(m);
}
std::shared_ptr<MacroAction> MacroActionHttp::Copy() const
{
return std::make_shared<MacroActionHttp>(*this);
}
void MacroActionHttp::ResolveVariablesToFixedValues()
{
_url.ResolveVariables();
_data.ResolveVariables();
_headers.ResolveVariables();
_timeout.ResolveVariables();
}
static inline void populateMethodSelection(QComboBox *list)
{
for (auto entry : methods) {

View File

@@ -20,10 +20,9 @@ public:
bool Load(obs_data_t *obj);
std::string GetShortDesc() const;
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionHttp>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
void ResolveVariablesToFixedValues();
enum class Method {
GET = 0,

View File

@@ -0,0 +1,89 @@
#include "macro-action-log.hpp"
#include "layout-helpers.hpp"
namespace advss {
const std::string MacroActionLog::id = "log";
bool MacroActionLog::_registered = MacroActionFactory::Register(
MacroActionLog::id, {MacroActionLog::Create, MacroActionLogEdit::Create,
"AdvSceneSwitcher.action.log"});
bool MacroActionLog::PerformAction()
{
blog(LOG_INFO, "%s", std::string(_logMessage).c_str());
return true;
}
bool MacroActionLog::Save(obs_data_t *obj) const
{
MacroAction::Save(obj);
_logMessage.Save(obj, "logMessage");
return true;
}
bool MacroActionLog::Load(obs_data_t *obj)
{
MacroAction::Load(obj);
_logMessage.Load(obj, "logMessage");
return true;
}
std::shared_ptr<MacroAction> MacroActionLog::Create(Macro *m)
{
return std::make_shared<MacroActionLog>(m);
}
std::shared_ptr<MacroAction> MacroActionLog::Copy() const
{
return std::make_shared<MacroActionLog>(*this);
}
void MacroActionLog::ResolveVariablesToFixedValues()
{
_logMessage.ResolveVariables();
}
MacroActionLogEdit::MacroActionLogEdit(
QWidget *parent, std::shared_ptr<MacroActionLog> entryData)
: QWidget(parent),
_logMessage(new VariableTextEdit(this, 5, 1, 1))
{
QWidget::connect(_logMessage, SIGNAL(textChanged()), this,
SLOT(LogMessageChanged()));
auto layout = new QHBoxLayout();
PlaceWidgets(obs_module_text("AdvSceneSwitcher.action.log.entry"),
layout, {{"{{logMessage}}", _logMessage}}, false);
setLayout(layout);
_entryData = entryData;
UpdateEntryData();
_loading = false;
}
void MacroActionLogEdit::UpdateEntryData()
{
if (!_entryData) {
return;
}
_logMessage->setPlainText(_entryData->_logMessage);
adjustSize();
updateGeometry();
}
void MacroActionLogEdit::LogMessageChanged()
{
if (_loading || !_entryData) {
return;
}
auto lock = LockContext();
_entryData->_logMessage = _logMessage->toPlainText().toStdString();
adjustSize();
updateGeometry();
}
} // namespace advss

View File

@@ -0,0 +1,50 @@
#pragma once
#include "macro-action-edit.hpp"
#include "variable-text-edit.hpp"
namespace advss {
class MacroActionLog : public MacroAction {
public:
MacroActionLog(Macro *m) : MacroAction(m) {}
bool PerformAction();
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
void ResolveVariablesToFixedValues();
StringVariable _logMessage =
obs_module_text("AdvSceneSwitcher.action.log.placeholder");
private:
static bool _registered;
static const std::string id;
};
class MacroActionLogEdit : public QWidget {
Q_OBJECT
public:
MacroActionLogEdit(QWidget *parent,
std::shared_ptr<MacroActionLog> entryData = nullptr);
void UpdateEntryData();
static QWidget *Create(QWidget *parent,
std::shared_ptr<MacroAction> action)
{
return new MacroActionLogEdit(
parent,
std::dynamic_pointer_cast<MacroActionLog>(action));
}
private slots:
void LogMessageChanged();
private:
VariableTextEdit *_logMessage;
std::shared_ptr<MacroActionLog> _entryData;
bool _loading = true;
};
} // namespace advss

View File

@@ -38,6 +38,16 @@ static const std::map<MacroActionMedia::SelectionType, std::string>
"AdvSceneSwitcher.action.media.selectionType.sceneItem"},
};
std::shared_ptr<MacroAction> MacroActionMedia::Create(Macro *m)
{
return std::make_shared<MacroActionMedia>(m);
}
std::shared_ptr<MacroAction> MacroActionMedia::Copy() const
{
return std::make_shared<MacroActionMedia>(*this);
}
std::string MacroActionMedia::GetShortDesc() const
{
if (_selection == SelectionType::SOURCE) {
@@ -112,7 +122,7 @@ void MacroActionMedia::LogAction() const
{
auto it = actionTypes.find(_action);
if (it != actionTypes.end()) {
vblog(LOG_INFO, "performed action \"%s\" for source \"%s\"",
ablog(LOG_INFO, "performed action \"%s\" for source \"%s\"",
it->second.c_str(),
_selection == SelectionType::SOURCE
? _mediaSource.ToString(true).c_str()
@@ -150,6 +160,15 @@ bool MacroActionMedia::Load(obs_data_t *obj)
return true;
}
void MacroActionMedia::ResolveVariablesToFixedValues()
{
_seekDuration.ResolveVariables();
_seekPercentage.ResolveVariables();
_mediaSource.ResolveVariables();
_sceneItem.ResolveVariables();
_scene.ResolveVariables();
}
static inline void populateActionSelection(QComboBox *list)
{
for (const auto &[_, name] : actionTypes) {

View File

@@ -11,10 +11,8 @@ namespace advss {
class MacroActionMedia : public MacroAction {
public:
MacroActionMedia(Macro *m) : MacroAction(m) {}
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionMedia>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
std::string GetId() const { return id; };
std::string GetShortDesc() const;
@@ -22,6 +20,7 @@ public:
void LogAction() const;
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
void ResolveVariablesToFixedValues();
enum class Action {
PLAY,

View File

@@ -1,5 +1,6 @@
#include "macro-action-osc.hpp"
#include <obs.hpp>
#include <QGroupBox>
#include <system_error>
@@ -146,7 +147,7 @@ bool MacroActionOSC::PerformAction()
void MacroActionOSC::LogAction() const
{
vblog(LOG_INFO, "sending OSC message '%s' to %s %s %d",
ablog(LOG_INFO, "sending OSC message '%s' to %s %s %d",
_message.ToString().c_str(),
_protocol == Protocol::UDP ? "UDP" : "TCP", _ip.c_str(),
_port.GetValue());
@@ -172,6 +173,21 @@ bool MacroActionOSC::Load(obs_data_t *obj)
return true;
}
std::shared_ptr<MacroAction> MacroActionOSC::Create(Macro *m)
{
return std::make_shared<MacroActionOSC>(m);
}
std::shared_ptr<MacroAction> MacroActionOSC::Copy() const
{
auto result = Create(GetMacro());
OBSDataAutoRelease data = obs_data_create();
Save(data);
result->Load(data);
result->PostLoad();
return result;
}
void MacroActionOSC::SetProtocol(Protocol p)
{
_protocol = p;
@@ -190,6 +206,13 @@ void MacroActionOSC::SetPortNr(IntVariable port)
_reconnect = true;
}
void MacroActionOSC::ResolveVariablesToFixedValues()
{
_ip.ResolveVariables();
_port.ResolveVariables();
_message.ResolveVariables();
}
static void populateProtocolSelection(QComboBox *list)
{
list->addItem("TCP");

View File

@@ -15,10 +15,8 @@ public:
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionOSC>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
enum class Protocol {
TCP,
@@ -31,6 +29,7 @@ public:
StringVariable GetIP() const { return _ip; }
void SetPortNr(IntVariable);
IntVariable GetPortNr() { return _port; }
void ResolveVariablesToFixedValues();
OSCMessage _message;

View File

@@ -174,14 +174,14 @@ void MacroActionPluginState::LogAction() const
blog(LOG_INFO, "stop() called by macro");
break;
case PluginStateAction::NO_MATCH_BEHAVIOUR:
vblog(LOG_INFO, "setting no match to %d", _value);
ablog(LOG_INFO, "setting no match to %d", _value);
break;
case PluginStateAction::IMPORT_SETTINGS:
vblog(LOG_INFO, "importing settings from %s",
ablog(LOG_INFO, "importing settings from %s",
_settingsPath.c_str());
break;
case PluginStateAction::TERMINATE:
vblog(LOG_INFO, "sending terminate signal to OBS in 10s");
ablog(LOG_INFO, "sending terminate signal to OBS in 10s");
break;
default:
blog(LOG_WARNING, "ignored unknown pluginState action %d",
@@ -212,10 +212,25 @@ bool MacroActionPluginState::Load(obs_data_t *obj)
return true;
}
std::shared_ptr<MacroAction> MacroActionPluginState::Create(Macro *m)
{
return std::make_shared<MacroActionPluginState>(m);
}
std::shared_ptr<MacroAction> MacroActionPluginState::Copy() const
{
return std::make_shared<MacroActionPluginState>(*this);
}
void MacroActionPluginState::ResolveVariablesToFixedValues()
{
_settingsPath = std::string(_settingsPath);
}
static inline void populateActionSelection(QComboBox *list)
{
for (auto entry : actionTypes) {
list->addItem(obs_module_text(entry.second.c_str()));
for (const auto &[_, name] : actionTypes) {
list->addItem(obs_module_text(name.c_str()));
}
}
@@ -223,8 +238,8 @@ static inline void populateValueSelection(QComboBox *list,
PluginStateAction action)
{
if (action == PluginStateAction::NO_MATCH_BEHAVIOUR) {
for (auto entry : noMatchValues) {
list->addItem(obs_module_text(entry.second.c_str()));
for (const auto &[_, name] : noMatchValues) {
list->addItem(obs_module_text(name.c_str()));
}
}
}

View File

@@ -2,6 +2,7 @@
#include "macro-action-edit.hpp"
#include "file-selection.hpp"
#include <obs.hpp>
#include <QDoubleSpinBox>
#include <QLabel>
@@ -22,10 +23,9 @@ public:
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionPluginState>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
void ResolveVariablesToFixedValues();
PluginStateAction _action = PluginStateAction::STOP;
int _value = 0;

View File

@@ -21,7 +21,7 @@ bool MacroActionProfile::PerformAction()
void MacroActionProfile::LogAction() const
{
vblog(LOG_INFO, "set profile type to \"%s\"", _profile.c_str());
ablog(LOG_INFO, "set profile type to \"%s\"", _profile.c_str());
}
bool MacroActionProfile::Save(obs_data_t *obj) const
@@ -43,6 +43,16 @@ std::string MacroActionProfile::GetShortDesc() const
return _profile;
}
std::shared_ptr<MacroAction> MacroActionProfile::Create(Macro *m)
{
return std::make_shared<MacroActionProfile>(m);
}
std::shared_ptr<MacroAction> MacroActionProfile::Copy() const
{
return std::make_shared<MacroActionProfile>(*this);
}
MacroActionProfileEdit::MacroActionProfileEdit(
QWidget *parent, std::shared_ptr<MacroActionProfile> entryData)
: QWidget(parent)

View File

@@ -14,10 +14,8 @@ public:
bool Load(obs_data_t *obj);
std::string GetShortDesc() const;
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionProfile>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
std::string _profile;

View File

@@ -75,7 +75,7 @@ void MacroActionProjector::LogAction() const
{
auto it = selectionTypes.find(_type);
if (it != selectionTypes.end()) {
vblog(LOG_INFO,
ablog(LOG_INFO,
"performed projector action \"%s\" with"
"source \"%s\","
"scene \"%s\","
@@ -119,6 +119,22 @@ bool MacroActionProjector::Load(obs_data_t *obj)
return true;
}
std::shared_ptr<MacroAction> MacroActionProjector::Create(Macro *m)
{
return std::make_shared<MacroActionProjector>(m);
}
std::shared_ptr<MacroAction> MacroActionProjector::Copy() const
{
return std::make_shared<MacroActionProjector>(*this);
}
void MacroActionProjector::ResolveVariablesToFixedValues()
{
_source.ResolveVariables();
_scene.ResolveVariables();
}
void MacroActionProjector::SetMonitor(int idx)
{
_monitor = idx;

View File

@@ -13,10 +13,9 @@ public:
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionProjector>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
void ResolveVariablesToFixedValues();
void SetMonitor(int);
int GetMonitor() const;

View File

@@ -64,7 +64,7 @@ bool MacroActionRandom::PerformAction()
void MacroActionRandom::LogAction() const
{
vblog(LOG_INFO, "running random macro");
ablog(LOG_INFO, "running random macro");
}
bool MacroActionRandom::Save(obs_data_t *obj) const
@@ -83,6 +83,16 @@ bool MacroActionRandom::Load(obs_data_t *obj)
return true;
}
std::shared_ptr<MacroAction> MacroActionRandom::Create(Macro *m)
{
return std::make_shared<MacroActionRandom>(m);
}
std::shared_ptr<MacroAction> MacroActionRandom::Copy() const
{
return std::make_shared<MacroActionRandom>(*this);
}
MacroActionRandomEdit::MacroActionRandomEdit(
QWidget *parent, std::shared_ptr<MacroActionRandom> entryData)
: QWidget(parent),

View File

@@ -16,10 +16,8 @@ public:
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionRandom>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
bool _allowRepeat = false;

View File

@@ -97,7 +97,7 @@ void MacroActionRecord::LogAction() const
{
auto it = actionTypes.find(_action);
if (it != actionTypes.end()) {
vblog(LOG_INFO, "performed action \"%s\"", it->second.c_str());
ablog(LOG_INFO, "performed action \"%s\"", it->second.c_str());
} else {
blog(LOG_WARNING, "ignored unknown recording action %d",
static_cast<int>(_action));
@@ -122,10 +122,26 @@ bool MacroActionRecord::Load(obs_data_t *obj)
return true;
}
std::shared_ptr<MacroAction> MacroActionRecord::Create(Macro *m)
{
return std::make_shared<MacroActionRecord>(m);
}
std::shared_ptr<MacroAction> MacroActionRecord::Copy() const
{
return std::make_shared<MacroActionRecord>(*this);
}
void MacroActionRecord::ResolveVariablesToFixedValues()
{
_folder.ResolveVariables();
_fileFormat.ResolveVariables();
}
static inline void populateActionSelection(QComboBox *list)
{
for (auto entry : actionTypes) {
list->addItem(obs_module_text(entry.second.c_str()));
for (const auto &[_, name] : actionTypes) {
list->addItem(obs_module_text(name.c_str()));
}
}

View File

@@ -17,10 +17,9 @@ public:
bool Save(obs_data_t *obj) const;
bool Load(obs_data_t *obj);
std::string GetId() const { return id; };
static std::shared_ptr<MacroAction> Create(Macro *m)
{
return std::make_shared<MacroActionRecord>(m);
}
static std::shared_ptr<MacroAction> Create(Macro *m);
std::shared_ptr<MacroAction> Copy() const;
void ResolveVariablesToFixedValues();
enum class Action {
STOP,

View File

@@ -47,7 +47,7 @@ void MacroActionReplayBuffer::LogAction() const
{
auto it = actionTypes.find(_action);
if (it != actionTypes.end()) {
vblog(LOG_INFO, "performed action \"%s\"", it->second.c_str());
ablog(LOG_INFO, "performed action \"%s\"", it->second.c_str());
} else {
blog(LOG_WARNING, "ignored unknown replay buffer action %d",
static_cast<int>(_action));
@@ -69,10 +69,20 @@ bool MacroActionReplayBuffer::Load(obs_data_t *obj)
return true;
}
std::shared_ptr<MacroAction> MacroActionReplayBuffer::Create(Macro *m)
{
return std::make_shared<MacroActionReplayBuffer>(m);
}
std::shared_ptr<MacroAction> MacroActionReplayBuffer::Copy() const
{
return std::make_shared<MacroActionReplayBuffer>(*this);
}
static inline void populateActionSelection(QComboBox *list)
{
for (auto entry : actionTypes) {
list->addItem(obs_module_text(entry.second.c_str()));
for (const auto &[_, name] : actionTypes) {
list->addItem(obs_module_text(name.c_str()));
}
}

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