diff --git a/CMakeLists.txt b/CMakeLists.txt index b347245d..12ae1715 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -221,6 +221,8 @@ target_sources( src/macro-core/macro-condition-window.hpp src/macro-core/macro-condition.cpp src/macro-core/macro-condition.hpp + src/macro-core/macro-dock.cpp + src/macro-core/macro-dock.hpp src/macro-core/macro-properties.cpp src/macro-core/macro-properties.hpp src/macro-core/macro-ref.cpp diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 05d92152..f164cb0e 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -95,11 +95,17 @@ AdvSceneSwitcher.macroTab.maximize="Maximize" AdvSceneSwitcher.macroTab.minimize="Minimize" AdvSceneSwitcher.macroTab.highlightSettings="Visual settings" AdvSceneSwitcher.macroTab.hotkeySettings="Hotkey settings" +AdvSceneSwitcher.macroTab.dockSettings="Dock settings" AdvSceneSwitcher.macroTab.highlightExecutedMacros="Highlight recently executed macros" AdvSceneSwitcher.macroTab.highlightTrueConditions="Highlight conditions of currently selected macro that evaluated to true recently" AdvSceneSwitcher.macroTab.highlightPerformedActions="Highlight recently performed actions of currently selected macro" AdvSceneSwitcher.macroTab.newMacroRegisterHotkey="Register hotkeys to control the pause state of new macros" AdvSceneSwitcher.macroTab.currentDisableHotkeys="Register hotkeys to control the pause state of selected macro" +AdvSceneSwitcher.macroTab.currentRegisterDock="Register dock widget to control the pause state of selected macro or run it manually" + +AdvSceneSwitcher.macroDock.pause="Pause" +AdvSceneSwitcher.macroDock.unpause="Unpause" +AdvSceneSwitcher.macroDock.run="Run" ; Macro List AdvSceneSwitcher.macroList.deleted="deleted" diff --git a/src/macro-core/macro-dock.cpp b/src/macro-core/macro-dock.cpp new file mode 100644 index 00000000..8c1a7cc2 --- /dev/null +++ b/src/macro-core/macro-dock.cpp @@ -0,0 +1,86 @@ +#include "macro-dock.hpp" +#include "macro.hpp" +#include "utility.hpp" + +#include +#include + +MacroDock::MacroDock(Macro *m, QWidget *parent) + : OBSDock(parent), + _run(new QPushButton( + obs_module_text("AdvSceneSwitcher.macroDock.run"))), + _pauseToggle(new QPushButton()), + _macro(m) +{ + if (_macro) { + setWindowTitle(QString::fromStdString(_macro->Name())); + } else { + setWindowTitle(""); + } + + setFeatures(DockWidgetClosable | DockWidgetMovable | + DockWidgetFloatable); + + QWidget::connect(_run, SIGNAL(clicked()), this, SLOT(RunClicked())); + QWidget::connect(_pauseToggle, SIGNAL(clicked()), this, + SLOT(PauseToggleClicked())); + + QVBoxLayout *layout = new QVBoxLayout; + layout->addWidget(_run); + layout->addWidget(_pauseToggle); + + QWidget::connect(&_timer, SIGNAL(timeout()), this, + SLOT(UpdatePauseText())); + _timer.start(1000); + + UpdatePauseText(); + + // QFrame wrapper is necessary to avoid dock being partially + // transparent + QFrame *wrapper = new QFrame; + wrapper->setFrameShape(QFrame::StyledPanel); + wrapper->setFrameShadow(QFrame::Sunken); + wrapper->setLayout(layout); + setWidget(wrapper); +} + +void MacroDock::SetName(const QString &name) +{ + setWindowTitle(name); +} + +void MacroDock::RunClicked() +{ + if (!_macro) { + return; + } + + auto ret = _macro->PerformActions(); + if (!ret) { + QString err = + obs_module_text("AdvSceneSwitcher.macroTab.runFail"); + DisplayMessage(err.arg(QString::fromStdString(_macro->Name()))); + } +} + +void MacroDock::PauseToggleClicked() +{ + if (!_macro) { + return; + } + + _macro->SetPaused(!_macro->Paused()); + UpdatePauseText(); +} + +void MacroDock::UpdatePauseText() +{ + if (!_macro) { + return; + } + + _pauseToggle->setText( + _macro->Paused() + ? obs_module_text("AdvSceneSwitcher.macroDock.unpause") + : obs_module_text("AdvSceneSwitcher.macroDock.pause")); +} diff --git a/src/macro-core/macro-dock.hpp b/src/macro-core/macro-dock.hpp new file mode 100644 index 00000000..e4744123 --- /dev/null +++ b/src/macro-core/macro-dock.hpp @@ -0,0 +1,28 @@ +#pragma once +#include "obs-dock.hpp" + +#include +#include +#include + +class Macro; + +class MacroDock : public OBSDock { + Q_OBJECT + +public: + MacroDock(Macro *, QWidget *parent); + void SetName(const QString &); + +private slots: + void RunClicked(); + void PauseToggleClicked(); + void UpdatePauseText(); + +private: + QPushButton *_run; + QPushButton *_pauseToggle; + QTimer _timer; + + Macro *_macro; +}; diff --git a/src/macro-core/macro-properties.cpp b/src/macro-core/macro-properties.cpp index c8bf6d7b..a192113c 100644 --- a/src/macro-core/macro-properties.cpp +++ b/src/macro-core/macro-properties.cpp @@ -41,7 +41,9 @@ MacroPropertiesDialog::MacroPropertiesDialog(QWidget *parent, _newMacroRegisterHotkeys(new QCheckBox(obs_module_text( "AdvSceneSwitcher.macroTab.newMacroRegisterHotkey"))), _currentMacroRegisterHotkeys(new QCheckBox(obs_module_text( - "AdvSceneSwitcher.macroTab.currentDisableHotkeys"))) + "AdvSceneSwitcher.macroTab.currentDisableHotkeys"))), + _currentMacroRegisterDock(new QCheckBox(obs_module_text( + "AdvSceneSwitcher.macroTab.currentRegisterDock"))) { setModal(true); setWindowModality(Qt::WindowModality::WindowModal); @@ -64,6 +66,12 @@ MacroPropertiesDialog::MacroPropertiesDialog(QWidget *parent, hotkeyLayout->addWidget(_currentMacroRegisterHotkeys); hotkeyOptions->setLayout(hotkeyLayout); + auto dockOptions = new QGroupBox( + obs_module_text("AdvSceneSwitcher.macroTab.dockSettings")); + QVBoxLayout *dockLayout = new QVBoxLayout; + dockLayout->addWidget(_currentMacroRegisterDock); + dockOptions->setLayout(dockLayout); + QDialogButtonBox *buttonbox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel); buttonbox->setCenterButtons(true); @@ -73,6 +81,7 @@ MacroPropertiesDialog::MacroPropertiesDialog(QWidget *parent, QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(highlightOptions); layout->addWidget(hotkeyOptions); + layout->addWidget(dockOptions); layout->addWidget(buttonbox); setLayout(layout); @@ -83,8 +92,10 @@ MacroPropertiesDialog::MacroPropertiesDialog(QWidget *parent, if (macro && !macro->IsGroup()) { _currentMacroRegisterHotkeys->setChecked( macro->PauseHotkeysEnabled()); + _currentMacroRegisterDock->setChecked(macro->DockEnabled()); } else { hotkeyOptions->hide(); + dockOptions->hide(); } } @@ -102,9 +113,12 @@ bool MacroPropertiesDialog::AskForSettings(QWidget *parent, userInput._highlightActions = dialog._actions->isChecked(); userInput._newMacroRegisterHotkeys = dialog._newMacroRegisterHotkeys->isChecked(); - if (macro) { - macro->EnablePauseHotkeys( - dialog._currentMacroRegisterHotkeys->isChecked()); + if (!macro) { + return true; } + + macro->EnablePauseHotkeys( + dialog._currentMacroRegisterHotkeys->isChecked()); + macro->EnableDock(dialog._currentMacroRegisterDock->isChecked()); return true; } diff --git a/src/macro-core/macro-properties.hpp b/src/macro-core/macro-properties.hpp index 45305597..8558a80b 100644 --- a/src/macro-core/macro-properties.hpp +++ b/src/macro-core/macro-properties.hpp @@ -34,4 +34,5 @@ private: QCheckBox *_newMacroRegisterHotkeys; // Current macro specific settings QCheckBox *_currentMacroRegisterHotkeys; + QCheckBox *_currentMacroRegisterDock; }; diff --git a/src/macro-core/macro.cpp b/src/macro-core/macro.cpp index 296a7424..3483effc 100644 --- a/src/macro-core/macro.cpp +++ b/src/macro-core/macro.cpp @@ -1,6 +1,7 @@ #include "macro.hpp" #include "macro-action-edit.hpp" #include "macro-condition-edit.hpp" +#include "macro-dock.hpp" #include "macro-action-scene-switch.hpp" #include "advanced-scene-switcher.hpp" #include "hotkey.hpp" @@ -9,6 +10,7 @@ #undef max #include #include +#include constexpr int perfLogThreshold = 300; @@ -26,6 +28,7 @@ Macro::~Macro() _die = true; Stop(); ClearHotkeys(); + RemoveDock(); } std::shared_ptr @@ -227,6 +230,7 @@ void Macro::SetName(const std::string &name) { _name = name; SetHotkeysDesc(); + SetDockWidgetName(); } void Macro::ResetTimers() @@ -337,6 +341,12 @@ bool Macro::Save(obs_data_t *obj) const return true; } + obs_data_set_bool(obj, "registerDock", _registerDock); + // The object name is used to restore the position of the dock + if (_registerDock) { + SetDockWidgetName(); + } + obs_data_set_bool(obj, "registerHotkeys", _registerHotkeys); obs_data_array_t *pauseHotkey = obs_hotkey_save(_pauseHotkey); obs_data_set_array(obj, "pauseHotkey", pauseHotkey); @@ -426,6 +436,8 @@ bool Macro::Load(obs_data_t *obj) return true; } + EnableDock(obs_data_get_bool(obj, "registerDock")); + obs_data_set_default_bool(obj, "registerHotkeys", true); _registerHotkeys = obs_data_get_bool(obj, "registerHotkeys"); if (_registerHotkeys) { @@ -567,6 +579,51 @@ bool Macro::PauseHotkeysEnabled() return _registerHotkeys; } +void Macro::EnableDock(bool value) +{ + if (_registerDock == value) { + return; + } + + RemoveDock(); + if (!_registerDock) { + _dock = new MacroDock(this, + static_cast( + obs_frontend_get_main_window())); + _dockAction = + static_cast(obs_frontend_add_dock(_dock)); + SetDockWidgetName(); + } + + _registerDock = value; +} + +void Macro::RemoveDock() +{ + if (_dock) { + _dock->close(); + _dock->deleteLater(); + _dockAction->deleteLater(); + _dock = nullptr; + _dockAction = nullptr; + } +} + +void Macro::SetDockWidgetName() const +{ + if (!_dock) { + return; + } + // Set prefix to avoid dock name conflict + _dock->setObjectName("ADVSS-" + QString::fromStdString(_name)); + _dock->SetName(QString::fromStdString(_name)); + + if (!_dockAction) { + return; + } + _dockAction->setText(QString::fromStdString(_name)); +} + static void pauseCB(void *data, obs_hotkey_id, obs_hotkey_t *, bool pressed) { if (pressed) { diff --git a/src/macro-core/macro.hpp b/src/macro-core/macro.hpp index 9badebe3..578abbad 100644 --- a/src/macro-core/macro.hpp +++ b/src/macro-core/macro.hpp @@ -14,6 +14,8 @@ constexpr auto macro_func = 10; +class MacroDock; + class Macro { public: Macro(const std::string &name = "", const bool addHotkey = false); @@ -78,6 +80,9 @@ public: void EnablePauseHotkeys(bool); bool PauseHotkeysEnabled(); + void EnableDock(bool); + bool DockEnabled() { return _registerDock; } + void ResetTimers(); private: @@ -87,6 +92,8 @@ private: void RunActions(bool &ret, bool ignorePause); void RunActions(bool ignorePause); void SetOnChangeHighlight(); + void SetDockWidgetName() const; + void RemoveDock(); std::string _name = ""; std::deque> _conditions; @@ -111,6 +118,9 @@ private: bool _isCollapsed = false; bool _wasExecutedRecently = false; bool _onChangeTriggered = false; + bool _registerDock = false; + MacroDock *_dock = nullptr; + QAction *_dockAction = nullptr; std::chrono::high_resolution_clock::time_point _lastCheckTime{};