diff --git a/CMakeLists.txt b/CMakeLists.txt index cea7231d..ebdd41f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -123,6 +123,10 @@ target_sources( lib/macro/macro-condition.hpp lib/macro/macro-dock.cpp lib/macro/macro-dock.hpp + lib/macro/macro-dock-settings.hpp + lib/macro/macro-dock-settings.cpp + lib/macro/macro-dock-window.cpp + lib/macro/macro-dock-window.hpp lib/macro/macro-edit.cpp lib/macro/macro-edit.hpp lib/macro/macro-export-import-dialog.cpp diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 1081cc02..4bbd1233 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -231,6 +231,8 @@ AdvSceneSwitcher.macroTab.pauseStateSaveBehavior.persist="The state the macro wa AdvSceneSwitcher.macroTab.pauseStateSaveBehavior.pause="Paused" AdvSceneSwitcher.macroTab.pauseStateSaveBehavior.unpause="Unpaused" AdvSceneSwitcher.macroTab.currentRegisterDock="Register dock widget to control the pause state of selected macro or run it manually" +AdvSceneSwitcher.macroTab.currentIsStandaloneDock="Is standalone dock" +AdvSceneSwitcher.macroTab.currentDockWindowName="Add to macro dock with name:" AdvSceneSwitcher.macroTab.currentDockAddRunButton="Add button to run the macro" AdvSceneSwitcher.macroTab.currentDockAddPauseButton="Add button to pause or unpause the macro" AdvSceneSwitcher.macroTab.currentDockAddStatusLabel="Add status label" diff --git a/lib/macro/macro-dock-settings.cpp b/lib/macro/macro-dock-settings.cpp new file mode 100644 index 00000000..b65df0f0 --- /dev/null +++ b/lib/macro/macro-dock-settings.cpp @@ -0,0 +1,394 @@ +#include "macro-dock-settings.hpp" +#include "macro-dock.hpp" +#include "macro-dock-window.hpp" +#include "macro.hpp" +#include "plugin-state-helpers.hpp" + +#include +#include + +#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(30, 0, 0) +#include + +namespace { + +struct DockMapEntry { + QAction *action = nullptr; + QWidget *dock = nullptr; +}; + +} // namespace + +static std::unordered_map dockIds; +static std::mutex dockMutex; + +static bool obs_frontend_add_dock_by_id(const char *id, const char *title, + QWidget *widget) +{ + std::lock_guard lock(dockMutex); + if (dockIds.count(id) > 0) { + return false; + } + + widget->setObjectName(id); + + auto dock = new QDockWidget(); + dock->setWindowTitle(title); + dock->setWidget(widget); + dock->setFloating(true); + dock->setVisible(false); + dock->setFeatures(QDockWidget::DockWidgetClosable | + QDockWidget::DockWidgetMovable | + QDockWidget::DockWidgetFloatable); + + auto action = static_cast(obs_frontend_add_dock(dock)); + if (!action) { + return false; + } + dockIds[id] = {action, dock}; + return true; +} + +static void obs_frontend_remove_dock(const char *id) +{ + std::lock_guard lock(dockMutex); + auto it = dockIds.find(id); + if (it == dockIds.end()) { + return; + } + it->second.action->deleteLater(); + it->second.dock->deleteLater(); + dockIds.erase(it); +} + +#endif + +namespace advss { + +MacroDockSettings::MacroDockSettings(Macro *macro) : _macro(macro) {} + +MacroDockSettings::~MacroDockSettings() +{ + // Keep the dock widgets in case of shutdown so they can be restored by + // OBS on startup + if (!OBSIsShuttingDown()) { + RemoveDock(); + } +} + +void MacroDockSettings::Save(obs_data_t *obj, bool saveForCopy) const +{ + OBSDataAutoRelease dockSettings = obs_data_create(); + obs_data_set_bool(dockSettings, "register", _registerDock); + obs_data_set_bool(dockSettings, "standaloneDock", _standaloneDock); + obs_data_set_string(dockSettings, "dockWindow", _dockWindow.c_str()); + obs_data_set_bool(dockSettings, "hasRunButton", _hasRunButton); + obs_data_set_bool(dockSettings, "hasPauseButton", _hasPauseButton); + obs_data_set_bool(dockSettings, "hasStatusLabel", _hasStatusLabel); + obs_data_set_bool(dockSettings, "highlightIfConditionsTrue", + _highlight); + _runButtonText.Save(dockSettings, "runButtonText"); + _pauseButtonText.Save(dockSettings, "pauseButtonText"); + _unpauseButtonText.Save(dockSettings, "unpauseButtonText"); + _conditionsTrueStatusText.Save(dockSettings, + "conditionsTrueStatusText"); + _conditionsFalseStatusText.Save(dockSettings, + "conditionsFalseStatusText"); + if (saveForCopy) { + auto uuid = GenerateId(); + obs_data_set_string(dockSettings, "dockId", uuid.c_str()); + + } else { + obs_data_set_string(dockSettings, "dockId", _id.c_str()); + } + obs_data_set_int(dockSettings, "version", 1); + obs_data_set_obj(obj, "dockSettings", dockSettings); +} + +void MacroDockSettings::Load(obs_data_t *obj) +{ + OBSDataAutoRelease dockSettings = obs_data_get_obj(obj, "dockSettings"); + if (!dockSettings) { + // TODO: Remove this fallback + _hasRunButton = obs_data_get_bool(obj, "dockHasRunButton"); + _hasPauseButton = obs_data_get_bool(obj, "dockHasPauseButton"); + _registerDock = obs_data_get_bool(obj, "registerDock"); + ResetDockIfEnabled(); + return; + } + + _macroName = _macro->Name(); + if (!obs_data_has_user_value(dockSettings, "version")) { + assert(_macro); + _id = std::string("ADVSS-") + _macroName; + } else { + _id = obs_data_get_string(dockSettings, "dockId"); + } + + _registerDock = obs_data_get_bool(dockSettings, "register"); + + // TODO: remove these default settings in a future version + obs_data_set_default_bool(dockSettings, "standaloneDock", true); + obs_data_set_default_string(dockSettings, "dockWindow", "Dock"); + obs_data_set_default_string( + dockSettings, "runButtonText", + obs_module_text("AdvSceneSwitcher.macroDock.run")); + obs_data_set_default_string( + dockSettings, "pauseButtonText", + obs_module_text("AdvSceneSwitcher.macroDock.pause")); + obs_data_set_default_string( + dockSettings, "unpauseButtonText", + obs_module_text("AdvSceneSwitcher.macroDock.unpause")); + _standaloneDock = obs_data_get_bool(dockSettings, "standaloneDock"); + _dockWindow = obs_data_get_string(dockSettings, "dockWindow"); + _runButtonText.Load(dockSettings, "runButtonText"); + _pauseButtonText.Load(dockSettings, "pauseButtonText"); + _unpauseButtonText.Load(dockSettings, "unpauseButtonText"); + _conditionsTrueStatusText.Load(dockSettings, + "conditionsTrueStatusText"); + _conditionsFalseStatusText.Load(dockSettings, + "conditionsFalseStatusText"); + if (_registerDock) { + _hasRunButton = obs_data_get_bool(dockSettings, "hasRunButton"); + _hasPauseButton = + obs_data_get_bool(dockSettings, "hasPauseButton"); + _hasStatusLabel = + obs_data_get_bool(dockSettings, "hasStatusLabel"); + _highlight = obs_data_get_bool(dockSettings, + "highlightIfConditionsTrue"); + } + + ResetDockIfEnabled(); +} + +void MacroDockSettings::EnableDock(bool enable) +{ + // Only apply "on change" to avoid recreation of the dock widget + if (_registerDock == enable) { + return; + } + + RemoveDock(); + + if (!enable) { + _registerDock = enable; + return; + } + + assert(_macro); + _macroName = _macro->Name(); + _dock = new MacroDock(GetWeakMacroByName(_macroName.c_str()), + _runButtonText, _pauseButtonText, + _unpauseButtonText, _conditionsTrueStatusText, + _conditionsFalseStatusText, _highlight); + + if (!_standaloneDock) { + auto window = GetDockWindowByName(_dockWindow); + if (!window) { + return; + } + window->AddMacroDock(_dock, QString::fromStdString(_macroName)); + _registerDock = enable; + return; + } + + if (!obs_frontend_add_dock_by_id(_id.c_str(), _macroName.c_str(), + _dock)) { + blog(LOG_INFO, "failed to add macro dock for macro %s", + _macroName.c_str()); + _dock->deleteLater(); + _dock = nullptr; + _registerDock = false; + return; + } + + _registerDock = enable; +} + +void MacroDockSettings::SetIsStandaloneDock(bool value) +{ + if (_standaloneDock == value) { + return; + } + + RemoveDock(); + _standaloneDock = value; + ResetDockIfEnabled(); +} + +void MacroDockSettings::SetDockWindowName(const std::string &name) +{ + if (_dockWindow == name) { + return; + } + + RemoveDock(); + _dockWindow = name; + ResetDockIfEnabled(); +} + +void MacroDockSettings::SetHasRunButton(bool value) +{ + _hasRunButton = value; + if (!_dock) { + return; + } + + _dock->ShowRunButton(value); +} + +void MacroDockSettings::SetHasPauseButton(bool value) +{ + _hasPauseButton = value; + if (!_dock) { + return; + } + + _dock->ShowPauseButton(value); +} + +void MacroDockSettings::SetHasStatusLabel(bool value) +{ + _hasStatusLabel = value; + if (!_dock) { + return; + } + + _dock->ShowStatusLabel(value); +} + +void MacroDockSettings::SetHighlightEnable(bool value) +{ + _highlight = value; + if (!_dock) { + return; + } + + _dock->EnableHighlight(value); +} + +void MacroDockSettings::SetRunButtonText(const std::string &text) +{ + _runButtonText = text; + if (!_dock) { + return; + } + + _dock->SetRunButtonText(text); +} + +void MacroDockSettings::SetPauseButtonText(const std::string &text) +{ + _pauseButtonText = text; + if (!_dock) { + return; + } + + _dock->SetPauseButtonText(text); +} + +void MacroDockSettings::SetUnpauseButtonText(const std::string &text) +{ + _unpauseButtonText = text; + if (!_dock) { + return; + } + + _dock->SetUnpauseButtonText(text); +} + +void MacroDockSettings::SetConditionsTrueStatusText(const std::string &text) +{ + _conditionsTrueStatusText = text; + if (!_dock) { + return; + } + + _dock->SetConditionsTrueText(text); +} + +StringVariable MacroDockSettings::ConditionsTrueStatusText() const +{ + return _conditionsTrueStatusText; +} + +void MacroDockSettings::SetConditionsFalseStatusText(const std::string &text) +{ + _conditionsFalseStatusText = text; + if (!_dock) { + return; + } + + _dock->SetConditionsFalseText(text); +} + +StringVariable MacroDockSettings::ConditionsFalseStatusText() const +{ + return _conditionsFalseStatusText; +} + +void MacroDockSettings::HandleMacroNameChange() +{ + const auto newName = _macro->Name(); + + if (!_standaloneDock) { + auto window = GetDockWindowByName(_dockWindow); + if (!window) { + return; + } + + window->RenameMacro(_macroName, newName); + _macroName = newName; + return; + } + + if (_macroName != newName) { + RemoveDock(); + _id = GenerateId(); + _macroName = newName; + } + + ResetDockIfEnabled(); +} + +void MacroDockSettings::ResetDockIfEnabled() +{ + if (_registerDock) { + _registerDock = false; + EnableDock(true); + } +} + +void MacroDockSettings::RemoveDock() +{ + if (_standaloneDock) { + obs_frontend_remove_dock(_id.c_str()); + _dock = nullptr; + return; + } + + auto window = GetDockWindowByName(_dockWindow); + if (window) { + window->RemoveMacroDock(_dock); + } + + if (_dock) { + _dock = nullptr; + } +} + +std::string MacroDockSettings::GenerateId() +{ +#if LIBOBS_API_VER > MAKE_SEMANTIC_VERSION(30, 0, 0) + auto uuid = os_generate_uuid(); + auto id = std::string("advss-macro-dock-") + std::string(uuid); + bfree(uuid); + return id; + +#else + static std::atomic_int16_t idCounter = 0; + return std::to_string(++idCounter); +#endif +} + +} // namespace advss diff --git a/lib/macro/macro-dock-settings.hpp b/lib/macro/macro-dock-settings.hpp new file mode 100644 index 00000000..c4328819 --- /dev/null +++ b/lib/macro/macro-dock-settings.hpp @@ -0,0 +1,76 @@ +#pragma once +#include "obs-module-helper.hpp" +#include "variable-string.hpp" + +namespace advss { + +class Macro; +class MacroDock; + +class MacroDockSettings { +public: + MacroDockSettings(Macro *macro); + ~MacroDockSettings(); + + void Save(obs_data_t *obj, bool saveForCopy) const; + void Load(obs_data_t *obj); + + void EnableDock(bool); + bool DockEnabled() const { return _registerDock; } + + bool IsStandaloneDock() const { return _standaloneDock; } + void SetIsStandaloneDock(bool value); + std::string DockWindowName() const { return _dockWindow; } + void SetDockWindowName(const std::string &name); + + void SetHasRunButton(bool value); + bool HasRunButton() const { return _hasRunButton; } + void SetHasPauseButton(bool value); + bool HasPauseButton() const { return _hasPauseButton; } + void SetHasStatusLabel(bool value); + bool HasStatusLabel() const { return _hasStatusLabel; } + void SetHighlightEnable(bool value); + bool HighlightEnabled() const { return _highlight; } + StringVariable RunButtonText() const { return _runButtonText; } + void SetRunButtonText(const std::string &text); + StringVariable PauseButtonText() const { return _pauseButtonText; } + void SetPauseButtonText(const std::string &text); + StringVariable UnpauseButtonText() const { return _unpauseButtonText; } + void SetUnpauseButtonText(const std::string &text); + void SetConditionsTrueStatusText(const std::string &text); + StringVariable ConditionsTrueStatusText() const; + void SetConditionsFalseStatusText(const std::string &text); + StringVariable ConditionsFalseStatusText() const; + + void HandleMacroNameChange(); + +private: + void ResetDockIfEnabled(); + void RemoveDock(); + static std::string GenerateId(); + + bool _registerDock = false; + bool _standaloneDock = true; + std::string _dockWindow = "Dock"; + bool _hasRunButton = true; + bool _hasPauseButton = true; + bool _hasStatusLabel = false; + bool _highlight = false; + StringVariable _runButtonText = + obs_module_text("AdvSceneSwitcher.macroDock.run"); + StringVariable _pauseButtonText = + obs_module_text("AdvSceneSwitcher.macroDock.pause"); + StringVariable _unpauseButtonText = + obs_module_text("AdvSceneSwitcher.macroDock.unpause"); + StringVariable _conditionsTrueStatusText = + obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.true"); + StringVariable _conditionsFalseStatusText = + obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.false"); + std::string _id = GenerateId(); + std::string _macroName = ""; + + Macro *_macro = nullptr; + MacroDock *_dock = nullptr; +}; + +} // namespace advss diff --git a/lib/macro/macro-dock.cpp b/lib/macro/macro-dock.cpp index 7731a8f7..fa346c20 100644 --- a/lib/macro/macro-dock.cpp +++ b/lib/macro/macro-dock.cpp @@ -30,9 +30,10 @@ MacroDock::MacroDock(std::weak_ptr m, auto macro = _macro.lock(); if (macro) { - _run->setVisible(macro->DockHasRunButton()); - _pauseToggle->setVisible(macro->DockHasPauseButton()); - _statusText->setVisible(macro->DockHasStatusLabel()); + const auto &settings = macro->GetDockSettings(); + _run->setVisible(settings.HasRunButton()); + _pauseToggle->setVisible(settings.HasPauseButton()); + _statusText->setVisible(settings.HasStatusLabel()); } QWidget::connect(_run, SIGNAL(clicked()), this, SLOT(RunClicked())); diff --git a/lib/macro/macro-settings.cpp b/lib/macro/macro-settings.cpp index d2bb46d5..090934e7 100644 --- a/lib/macro/macro-settings.cpp +++ b/lib/macro/macro-settings.cpp @@ -94,6 +94,9 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent, _currentInputs(new MacroInputSelection()), _currentMacroRegisterDock(new QCheckBox(obs_module_text( "AdvSceneSwitcher.macroTab.currentRegisterDock"))), + _currentMacroIsStandaloneDock(new QCheckBox(obs_module_text( + "AdvSceneSwitcher.macroTab.currentIsStandaloneDock"))), + _currentMacroDockWindowName(new QLineEdit(this)), _currentMacroDockAddRunButton(new QCheckBox(obs_module_text( "AdvSceneSwitcher.macroTab.currentDockAddRunButton"))), _currentMacroDockAddPauseButton(new QCheckBox(obs_module_text( @@ -198,6 +201,15 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent, int row = 0; _dockLayout->addWidget(_currentMacroRegisterDock, row, 1, 1, 2); row++; + _dockLayout->addWidget(_currentMacroIsStandaloneDock, row, 1, 1, 2); + row++; + _dockLayout->addWidget( + new QLabel(obs_module_text( + "AdvSceneSwitcher.macroTab.currentDockWindowName")), + row, 1); + _dockLayout->addWidget(_currentMacroDockWindowName, row, 2); + _dockWindowNameRow = row; + row++; _dockLayout->addWidget(_currentMacroDockAddRunButton, row, 1, 1, 2); row++; _dockLayout->addWidget( @@ -252,6 +264,8 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent, connect(_currentMacroRegisterDock, &QCheckBox::stateChanged, this, &MacroSettingsDialog::DockEnableChanged); + connect(_currentMacroIsStandaloneDock, &QCheckBox::stateChanged, this, + &MacroSettingsDialog::IsStandaloneDockChanged); connect(_currentMacroDockAddRunButton, &QCheckBox::stateChanged, this, &MacroSettingsDialog::RunButtonEnableChanged); connect(_currentMacroDockAddPauseButton, &QCheckBox::stateChanged, this, @@ -329,55 +343,37 @@ MacroSettingsDialog::MacroSettingsDialog(QWidget *parent, _currentSkipOnStartup->setChecked(macro->SkipExecOnStart()); _currentStopActionsIfNotDone->setChecked(macro->StopActionsIfNotDone()); _currentInputs->SetInputs(macro->GetInputVariables()); - const bool dockEnabled = macro->DockEnabled(); + const auto &dockSettings = macro->GetDockSettings(); + const bool dockEnabled = dockSettings.DockEnabled(); _currentMacroRegisterDock->setChecked(dockEnabled); - _currentMacroDockAddRunButton->setChecked(macro->DockHasRunButton()); + _currentMacroIsStandaloneDock->setChecked( + dockSettings.IsStandaloneDock()); + _currentMacroDockWindowName->setText( + QString::fromStdString(dockSettings.DockWindowName())); + _currentMacroDockAddRunButton->setChecked(dockSettings.HasRunButton()); _currentMacroDockAddPauseButton->setChecked( - macro->DockHasPauseButton()); + dockSettings.HasPauseButton()); _currentMacroDockAddStatusLabel->setChecked( - macro->DockHasStatusLabel()); + dockSettings.HasStatusLabel()); _currentMacroDockHighlightIfConditionsTrue->setChecked( - macro->DockHighlightEnabled()); - _runButtonText->setText(macro->RunButtonText()); - _pauseButtonText->setText(macro->PauseButtonText()); - _unpauseButtonText->setText(macro->UnpauseButtonText()); - _conditionsTrueStatusText->setText(macro->ConditionsTrueStatusText()); - _conditionsFalseStatusText->setText(macro->ConditionsFalseStatusText()); + dockSettings.HighlightEnabled()); + _runButtonText->setText(dockSettings.RunButtonText()); + _pauseButtonText->setText(dockSettings.PauseButtonText()); + _unpauseButtonText->setText(dockSettings.UnpauseButtonText()); + _conditionsTrueStatusText->setText( + dockSettings.ConditionsTrueStatusText()); + _conditionsFalseStatusText->setText( + dockSettings.ConditionsFalseStatusText()); - _currentMacroDockAddRunButton->setVisible(dockEnabled); - _currentMacroDockAddPauseButton->setVisible(dockEnabled); - _currentMacroDockAddStatusLabel->setVisible(dockEnabled); - _currentMacroDockHighlightIfConditionsTrue->setVisible(dockEnabled); - SetGridLayoutRowVisible(_dockLayout, _runButtonTextRow, - dockEnabled && macro->DockHasRunButton()); - SetGridLayoutRowVisible(_dockLayout, _pauseButtonTextRow, - dockEnabled && macro->DockHasPauseButton()); - SetGridLayoutRowVisible(_dockLayout, _unpauseButtonTextRow, - dockEnabled && macro->DockHasPauseButton()); - SetGridLayoutRowVisible(_dockLayout, _conditionsTrueTextRow, - dockEnabled && macro->DockHasStatusLabel()); - SetGridLayoutRowVisible(_dockLayout, _conditionsFalseTextRow, - dockEnabled && macro->DockHasStatusLabel()); + DockEnableChanged(dockEnabled); MinimizeSizeOfColumn(_dockLayout, 0); - Resize(); - // Try to set sensible initial size for the dialog window - QSize contentSize = contentWidget->sizeHint(); - resize(contentSize.width() + layout->contentsMargins().left() + - layout->contentsMargins().right() + - dialogLayout->contentsMargins().left() + - dialogLayout->contentsMargins().right() + - scrollArea->verticalScrollBar()->sizeHint().width() + 20, - contentSize.height() + dialogLayout->spacing() + - buttonbox->sizeHint().height() + - dialogLayout->contentsMargins().top() + - dialogLayout->contentsMargins().bottom() + - scrollArea->horizontalScrollBar()->sizeHint().height() + - 20); + Resize(); } void MacroSettingsDialog::DockEnableChanged(int enabled) { + _currentMacroIsStandaloneDock->setVisible(enabled); _currentMacroDockAddRunButton->setVisible(enabled); _currentMacroDockAddPauseButton->setVisible(enabled); _currentMacroDockAddStatusLabel->setVisible(enabled); @@ -401,6 +397,12 @@ void MacroSettingsDialog::DockEnableChanged(int enabled) Resize(); } +void MacroSettingsDialog::IsStandaloneDockChanged(int enabled) +{ + SetGridLayoutRowVisible(_dockLayout, _dockWindowNameRow, !enabled); + Resize(); +} + void MacroSettingsDialog::RunButtonEnableChanged(int enabled) { SetGridLayoutRowVisible(_dockLayout, _runButtonTextRow, enabled); @@ -479,29 +481,29 @@ bool MacroSettingsDialog::AskForSettings(QWidget *parent, macro->SetStopActionsIfNotDone( dialog._currentStopActionsIfNotDone->isChecked()); - // Only apply "on change" to avoid recreation of the dock widget - const bool enableDock = dialog._currentMacroRegisterDock->isChecked(); - if (macro->DockEnabled() != enableDock) { - macro->EnableDock( - dialog._currentMacroRegisterDock->isChecked()); - } - - macro->SetDockHasRunButton( + auto &dockSettings = macro->GetDockSettings(); + dockSettings.EnableDock(dialog._currentMacroRegisterDock->isChecked()); + dockSettings.SetIsStandaloneDock( + dialog._currentMacroIsStandaloneDock->isChecked()); + dockSettings.SetDockWindowName( + dialog._currentMacroDockWindowName->text().toStdString()); + dockSettings.SetHasRunButton( dialog._currentMacroDockAddRunButton->isChecked()); - macro->SetDockHasPauseButton( + dockSettings.SetHasPauseButton( dialog._currentMacroDockAddPauseButton->isChecked()); - macro->SetDockHasStatusLabel( + dockSettings.SetHasStatusLabel( dialog._currentMacroDockAddStatusLabel->isChecked()); - macro->SetHighlightEnable( + dockSettings.SetHighlightEnable( dialog._currentMacroDockHighlightIfConditionsTrue->isChecked()); - macro->SetRunButtonText(dialog._runButtonText->text().toStdString()); - macro->SetPauseButtonText( + dockSettings.SetRunButtonText( + dialog._runButtonText->text().toStdString()); + dockSettings.SetPauseButtonText( dialog._pauseButtonText->text().toStdString()); - macro->SetUnpauseButtonText( + dockSettings.SetUnpauseButtonText( dialog._unpauseButtonText->text().toStdString()); - macro->SetConditionsTrueStatusText( + dockSettings.SetConditionsTrueStatusText( dialog._conditionsTrueStatusText->text().toStdString()); - macro->SetConditionsFalseStatusText( + dockSettings.SetConditionsFalseStatusText( dialog._conditionsFalseStatusText->text().toStdString()); macro->SetInputVariables(dialog._currentInputs->GetInputs()); return true; diff --git a/lib/macro/macro-settings.hpp b/lib/macro/macro-settings.hpp index f9e7ef8a..84050751 100644 --- a/lib/macro/macro-settings.hpp +++ b/lib/macro/macro-settings.hpp @@ -41,6 +41,7 @@ public: Macro *macro); private slots: void DockEnableChanged(int); + void IsStandaloneDockChanged(int); void RunButtonEnableChanged(int); void PauseButtonEnableChanged(int); void StatusLabelEnableChanged(int); @@ -69,6 +70,8 @@ private: QCheckBox *_currentStopActionsIfNotDone; MacroInputSelection *_currentInputs; QCheckBox *_currentMacroRegisterDock; + QCheckBox *_currentMacroIsStandaloneDock; + QLineEdit *_currentMacroDockWindowName; QCheckBox *_currentMacroDockAddRunButton; QCheckBox *_currentMacroDockAddPauseButton; QCheckBox *_currentMacroDockAddStatusLabel; @@ -81,6 +84,7 @@ private: QGroupBox *_dockOptions; QGridLayout *_dockLayout; + int _dockWindowNameRow = -1; int _runButtonTextRow = -1; int _pauseButtonTextRow = -1; int _unpauseButtonTextRow = -1; diff --git a/lib/macro/macro.cpp b/lib/macro/macro.cpp index afeeb501..00e72486 100644 --- a/lib/macro/macro.cpp +++ b/lib/macro/macro.cpp @@ -1,7 +1,6 @@ #include "macro.hpp" #include "macro-action-factory.hpp" #include "macro-condition-factory.hpp" -#include "macro-dock.hpp" #include "macro-helpers.hpp" #include "macro-settings.hpp" #include "plugin-state-helpers.hpp" @@ -15,69 +14,12 @@ #include #include #include -#include - -#if LIBOBS_API_VER < MAKE_SEMANTIC_VERSION(30, 0, 0) -#include - -namespace { - -struct DockMapEntry { - QAction *action = nullptr; - QWidget *dock = nullptr; -}; - -} // namespace - -static std::unordered_map dockIds; -static std::mutex dockMutex; - -static bool obs_frontend_add_dock_by_id(const char *id, const char *title, - QWidget *widget) -{ - std::lock_guard lock(dockMutex); - if (dockIds.count(id) > 0) { - return false; - } - - widget->setObjectName(id); - - auto dock = new QDockWidget(); - dock->setWindowTitle(title); - dock->setWidget(widget); - dock->setFloating(true); - dock->setVisible(false); - dock->setFeatures(QDockWidget::DockWidgetClosable | - QDockWidget::DockWidgetMovable | - QDockWidget::DockWidgetFloatable); - - auto action = static_cast(obs_frontend_add_dock(dock)); - if (!action) { - return false; - } - dockIds[id] = {action, dock}; - return true; -} - -static void obs_frontend_remove_dock(const char *id) -{ - std::lock_guard lock(dockMutex); - auto it = dockIds.find(id); - if (it == dockIds.end()) { - return; - } - it->second.action->deleteLater(); - it->second.dock->deleteLater(); - dockIds.erase(it); -} - -#endif namespace advss { static std::deque> macros; -Macro::Macro(const std::string &name) +Macro::Macro(const std::string &name) : _dockSettings(this) { SetName(name); } @@ -99,12 +41,6 @@ Macro::~Macro() _die = true; Stop(); ClearHotkeys(); - - // Keep the dock widgets in case of shutdown so they can be restored by - // OBS on startup - if (!OBSIsShuttingDown()) { - RemoveDock(); - } } std::shared_ptr @@ -412,15 +348,9 @@ bool Macro::ShouldRunActions() const void Macro::SetName(const std::string &name) { - const bool nameChanged = _name == name; _name = name; - SetHotkeysDesc(); - - if (nameChanged) { - _dockId = GenerateDockId(); - } - EnableDock(_registerDock); + _dockSettings.HandleMacroNameChange(); } void Macro::ResetTimers() @@ -819,7 +749,7 @@ bool Macro::Save(obs_data_t *obj, bool saveForCopy) const _useCustomConditionCheckInterval); _customConditionCheckInterval.Save(obj, "customConditionCheckInterval"); - SaveDockSettings(obj, saveForCopy); + _dockSettings.Save(obj, saveForCopy); SaveSplitterPos(_actionConditionSplitterPosition, obj, "macroActionConditionSplitterPosition"); @@ -905,7 +835,7 @@ bool Macro::Load(obs_data_t *obj) obs_data_get_bool(obj, "useCustomConditionCheckInterval"); _customConditionCheckInterval.Load(obj, "customConditionCheckInterval"); - LoadDockSettings(obj); + _dockSettings.Load(obj); LoadSplitterPos(_actionConditionSplitterPosition, obj, "macroActionConditionSplitterPosition"); @@ -1095,224 +1025,6 @@ bool Macro::PauseHotkeysEnabled() const return _registerHotkeys; } -void Macro::SaveDockSettings(obs_data_t *obj, bool saveForCopy) const -{ - auto dockSettings = obs_data_create(); - obs_data_set_bool(dockSettings, "register", _registerDock); - obs_data_set_bool(dockSettings, "hasRunButton", _dockHasRunButton); - obs_data_set_bool(dockSettings, "hasPauseButton", _dockHasPauseButton); - obs_data_set_bool(dockSettings, "hasStatusLabel", _dockHasStatusLabel); - obs_data_set_bool(dockSettings, "highlightIfConditionsTrue", - _dockHighlight); - _runButtonText.Save(dockSettings, "runButtonText"); - _pauseButtonText.Save(dockSettings, "pauseButtonText"); - _unpauseButtonText.Save(dockSettings, "unpauseButtonText"); - _conditionsTrueStatusText.Save(dockSettings, - "conditionsTrueStatusText"); - _conditionsFalseStatusText.Save(dockSettings, - "conditionsFalseStatusText"); - if (saveForCopy) { - auto uuid = GenerateDockId(); - obs_data_set_string(dockSettings, "dockId", uuid.c_str()); - - } else { - obs_data_set_string(dockSettings, "dockId", _dockId.c_str()); - } - obs_data_set_int(dockSettings, "version", 1); - obs_data_set_obj(obj, "dockSettings", dockSettings); - obs_data_release(dockSettings); -} - -void Macro::LoadDockSettings(obs_data_t *obj) -{ - auto dockSettings = obs_data_get_obj(obj, "dockSettings"); - if (!dockSettings) { - // TODO: Remove this fallback - _dockHasRunButton = obs_data_get_bool(obj, "dockHasRunButton"); - _dockHasPauseButton = - obs_data_get_bool(obj, "dockHasPauseButton"); - EnableDock(obs_data_get_bool(obj, "registerDock")); - return; - } - - if (!obs_data_has_user_value(dockSettings, "version")) { - _dockId = std::string("ADVSS-") + _name; - } else { - _dockId = obs_data_get_string(dockSettings, "dockId"); - } - - const bool dockEnabled = obs_data_get_bool(dockSettings, "register"); - - // TODO: remove these default settings in a future version - obs_data_set_default_string( - dockSettings, "runButtonText", - obs_module_text("AdvSceneSwitcher.macroDock.run")); - obs_data_set_default_string( - dockSettings, "pauseButtonText", - obs_module_text("AdvSceneSwitcher.macroDock.pause")); - obs_data_set_default_string( - dockSettings, "unpauseButtonText", - obs_module_text("AdvSceneSwitcher.macroDock.unpause")); - _runButtonText.Load(dockSettings, "runButtonText"); - _pauseButtonText.Load(dockSettings, "pauseButtonText"); - _unpauseButtonText.Load(dockSettings, "unpauseButtonText"); - _conditionsTrueStatusText.Load(dockSettings, - "conditionsTrueStatusText"); - _conditionsFalseStatusText.Load(dockSettings, - "conditionsFalseStatusText"); - if (dockEnabled) { - _dockHasRunButton = - obs_data_get_bool(dockSettings, "hasRunButton"); - _dockHasPauseButton = - obs_data_get_bool(dockSettings, "hasPauseButton"); - _dockHasStatusLabel = - obs_data_get_bool(dockSettings, "hasStatusLabel"); - _dockHighlight = obs_data_get_bool(dockSettings, - "highlightIfConditionsTrue"); - } - EnableDock(dockEnabled); - obs_data_release(dockSettings); -} - -void Macro::EnableDock(bool value) -{ - // Reset dock regardless - RemoveDock(); - - if (!value) { - _registerDock = value; - return; - } - - _dock = new MacroDock(GetWeakMacroByName(_name.c_str()), _runButtonText, - _pauseButtonText, _unpauseButtonText, - _conditionsTrueStatusText, - _conditionsFalseStatusText, _dockHighlight); - - if (!obs_frontend_add_dock_by_id(_dockId.c_str(), _name.c_str(), - _dock)) { - blog(LOG_INFO, "failed to add macro dock for macro %s", - _name.c_str()); - _dock->deleteLater(); - _dock = nullptr; - _registerDock = false; - return; - } - - _registerDock = value; -} - -void Macro::SetDockHasRunButton(bool value) -{ - _dockHasRunButton = value; - if (!_dock) { - return; - } - _dock->ShowRunButton(value); -} - -void Macro::SetDockHasPauseButton(bool value) -{ - _dockHasPauseButton = value; - if (!_dock) { - return; - } - _dock->ShowPauseButton(value); -} - -void Macro::SetDockHasStatusLabel(bool value) -{ - _dockHasStatusLabel = value; - if (!_dock) { - return; - } - _dock->ShowStatusLabel(value); -} - -void Macro::SetHighlightEnable(bool value) -{ - _dockHighlight = value; - if (!_dock) { - return; - } - _dock->EnableHighlight(value); -} - -void Macro::SetRunButtonText(const std::string &text) -{ - _runButtonText = text; - if (!_dock) { - return; - } - _dock->SetRunButtonText(text); -} - -void Macro::SetPauseButtonText(const std::string &text) -{ - _pauseButtonText = text; - if (!_dock) { - return; - } - _dock->SetPauseButtonText(text); -} - -void Macro::SetUnpauseButtonText(const std::string &text) -{ - _unpauseButtonText = text; - if (!_dock) { - return; - } - _dock->SetUnpauseButtonText(text); -} - -void Macro::SetConditionsTrueStatusText(const std::string &text) -{ - _conditionsTrueStatusText = text; - if (!_dock) { - return; - } - _dock->SetConditionsTrueText(text); -} - -StringVariable Macro::ConditionsTrueStatusText() const -{ - return _conditionsTrueStatusText; -} - -void Macro::SetConditionsFalseStatusText(const std::string &text) -{ - _conditionsFalseStatusText = text; - if (!_dock) { - return; - } - _dock->SetConditionsFalseText(text); -} - -StringVariable Macro::ConditionsFalseStatusText() const -{ - return _conditionsFalseStatusText; -} - -void Macro::RemoveDock() -{ - obs_frontend_remove_dock(_dockId.c_str()); - _dock = nullptr; -} - -std::string Macro::GenerateDockId() -{ -#if LIBOBS_API_VER > MAKE_SEMANTIC_VERSION(30, 0, 0) - auto uuid = os_generate_uuid(); - auto id = std::string("advss-macro-dock-") + std::string(uuid); - bfree(uuid); - return id; - -#else - static std::atomic_int16_t idCounter = 0; - return std::to_string(++idCounter); -#endif -} - static void pauseCB(void *data, obs_hotkey_id, obs_hotkey_t *, bool pressed) { if (pressed) { diff --git a/lib/macro/macro.hpp b/lib/macro/macro.hpp index e67e7dbe..ceec43b8 100644 --- a/lib/macro/macro.hpp +++ b/lib/macro/macro.hpp @@ -1,6 +1,7 @@ #pragma once #include "macro-action.hpp" #include "macro-condition.hpp" +#include "macro-dock-settings.hpp" #include "macro-helpers.hpp" #include "macro-input.hpp" #include "macro-ref.hpp" @@ -20,7 +21,6 @@ namespace advss { -class MacroDock; class GlobalMacroSettings; class Macro { @@ -147,26 +147,7 @@ public: bool PauseHotkeysEnabled() const; // Docks - void EnableDock(bool); - bool DockEnabled() const { return _registerDock; } - void SetDockHasRunButton(bool value); - bool DockHasRunButton() const { return _dockHasRunButton; } - void SetDockHasPauseButton(bool value); - bool DockHasPauseButton() const { return _dockHasPauseButton; } - void SetDockHasStatusLabel(bool value); - bool DockHasStatusLabel() const { return _dockHasStatusLabel; } - void SetHighlightEnable(bool value); - bool DockHighlightEnabled() const { return _dockHighlight; } - StringVariable RunButtonText() const { return _runButtonText; } - void SetRunButtonText(const std::string &text); - StringVariable PauseButtonText() const { return _pauseButtonText; } - void SetPauseButtonText(const std::string &text); - StringVariable UnpauseButtonText() const { return _unpauseButtonText; } - void SetUnpauseButtonText(const std::string &text); - void SetConditionsTrueStatusText(const std::string &text); - StringVariable ConditionsTrueStatusText() const; - void SetConditionsFalseStatusText(const std::string &text); - StringVariable ConditionsFalseStatusText() const; + MacroDockSettings &GetDockSettings() { return _dockSettings; } private: void SetupHotkeys(); @@ -182,11 +163,6 @@ private: bool RunActions(bool ignorePause); bool RunElseActions(bool ignorePause); - void SaveDockSettings(obs_data_t *obj, bool saveForCopy) const; - void LoadDockSettings(obs_data_t *obj); - void RemoveDock(); - static std::string GenerateDockId(); - std::string _name = ""; bool _die = false; bool _stop = false; @@ -236,23 +212,7 @@ private: QList _actionConditionSplitterPosition; QList _elseActionSplitterPosition; - bool _registerDock = false; - bool _dockHasRunButton = true; - bool _dockHasPauseButton = true; - bool _dockHasStatusLabel = false; - bool _dockHighlight = false; - StringVariable _runButtonText = - obs_module_text("AdvSceneSwitcher.macroDock.run"); - StringVariable _pauseButtonText = - obs_module_text("AdvSceneSwitcher.macroDock.pause"); - StringVariable _unpauseButtonText = - obs_module_text("AdvSceneSwitcher.macroDock.unpause"); - StringVariable _conditionsTrueStatusText = - obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.true"); - StringVariable _conditionsFalseStatusText = - obs_module_text("AdvSceneSwitcher.macroDock.statusLabel.false"); - MacroDock *_dock = nullptr; - std::string _dockId = GenerateDockId(); + MacroDockSettings _dockSettings; }; void LoadMacros(obs_data_t *obj);