From 1ddd48e0086ebcb074caebefa283ca56d45f3c2e Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Sat, 8 Apr 2023 23:42:22 +0200 Subject: [PATCH] Improve dock handling when changing scene collections Note that the positions of the docks will still not be restored perfectly when changing scene collections. To my understanding this would somehow have to be handled by the QMainWindow which is controlled by OBS. This might have to be revisited at a later date. --- src/macro-core/macro-dock.cpp | 3 + src/macro-core/macro.cpp | 112 ++++++++++++++++++++++++++++------ src/macro-core/macro.hpp | 8 +++ src/status-control.cpp | 3 + 4 files changed, 109 insertions(+), 17 deletions(-) diff --git a/src/macro-core/macro-dock.cpp b/src/macro-core/macro-dock.cpp index 5e3e2191..c887649b 100644 --- a/src/macro-core/macro-dock.cpp +++ b/src/macro-core/macro-dock.cpp @@ -44,6 +44,9 @@ MacroDock::MacroDock(Macro *m, QWidget *parent) wrapper->setFrameShadow(QFrame::Sunken); wrapper->setLayout(layout); setWidget(wrapper); + + setFloating(true); + hide(); } void MacroDock::SetName(const QString &name) diff --git a/src/macro-core/macro.cpp b/src/macro-core/macro.cpp index f5309f83..e7c382a9 100644 --- a/src/macro-core/macro.cpp +++ b/src/macro-core/macro.cpp @@ -267,6 +267,11 @@ void Macro::SetOnChangeHighlight() _onChangeTriggered = true; } +bool Macro::DockIsVisible() const +{ + return _dock && _dockAction && _dock->isVisible(); +} + void Macro::SetPaused(bool pause) { if (_paused && !pause) { @@ -341,13 +346,7 @@ 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, "dockHasRunButton", _dockHasRunButton); - obs_data_set_bool(obj, "dockHasPauseButton", _dockHasPauseButton); + SaveDockSettings(obj); obs_data_set_bool(obj, "registerHotkeys", _registerHotkeys); obs_data_array_t *pauseHotkey = obs_hotkey_save(_pauseHotkey); @@ -438,9 +437,7 @@ bool Macro::Load(obs_data_t *obj) return true; } - _dockHasRunButton = obs_data_get_bool(obj, "dockHasRunButton"); - _dockHasPauseButton = obs_data_get_bool(obj, "dockHasPauseButton"); - EnableDock(obs_data_get_bool(obj, "registerDock")); + LoadDockSettings(obj); obs_data_set_default_bool(obj, "registerHotkeys", true); _registerHotkeys = obs_data_get_bool(obj, "registerHotkeys"); @@ -583,22 +580,103 @@ bool Macro::PauseHotkeysEnabled() return _registerHotkeys; } +void Macro::SaveDockSettings(obs_data_t *obj) const +{ + auto dockSettings = obs_data_create(); + obs_data_set_bool(dockSettings, "register", _registerDock); + // The object name is used to restore the position of the dock + if (_registerDock) { + SetDockWidgetName(); + } + obs_data_set_bool(dockSettings, "hasRunButton", _dockHasRunButton); + obs_data_set_bool(dockSettings, "hasPauseButton", _dockHasPauseButton); + if (_dock) { + auto window = static_cast( + obs_frontend_get_main_window()); + obs_data_set_bool(dockSettings, "isFloating", + _dock->isFloating()); + obs_data_set_bool(dockSettings, "isVisible", DockIsVisible()); + obs_data_set_int(dockSettings, "area", + window->dockWidgetArea(_dock)); + obs_data_set_string( + dockSettings, "geometry", + _dock->saveGeometry().toBase64().constData()); + } + 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; + } + + const bool dockEnabled = obs_data_get_bool(dockSettings, "register"); + _dockIsVisible = obs_data_get_bool(dockSettings, "isVisible"); + if (dockEnabled) { + _dockHasRunButton = + obs_data_get_bool(dockSettings, "hasRunButton"); + _dockHasPauseButton = + obs_data_get_bool(dockSettings, "hasPauseButton"); + _dockIsFloating = obs_data_get_bool(dockSettings, "isFloating"); + _dockArea = static_cast( + obs_data_get_int(dockSettings, "area")); + auto geometryStr = + obs_data_get_string(dockSettings, "geometry"); + if (geometryStr && strlen(geometryStr)) { + _dockGeo = + QByteArray::fromBase64(QByteArray(geometryStr)); + } + } + EnableDock(dockEnabled); + obs_data_release(dockSettings); +} + void Macro::EnableDock(bool value) { if (_registerDock == value) { return; } + // Reset dock regardless RemoveDock(); - if (!_registerDock) { - _dock = new MacroDock(this, - static_cast( - obs_frontend_get_main_window())); - _dockAction = - static_cast(obs_frontend_add_dock(_dock)); - SetDockWidgetName(); + + // Unregister dock + if (_registerDock) { + _dockIsFloating = true; + _dockGeo = QByteArray(); + _registerDock = value; + return; } + // Create new dock widget + auto window = + static_cast(obs_frontend_get_main_window()); + _dock = new MacroDock(this, window); + SetDockWidgetName(); // Used by OBS to restore position + + // Register new dock + _dockAction = static_cast(obs_frontend_add_dock(_dock)); + + // Note that OBSBasic::OBSInit() has precedence over the visibility and + // geometry set here. + // The function calls here are only intended to attempt to restore the + // dock status when switching scene collections. + _dock->setVisible(_dockIsVisible); + if (window->dockWidgetArea(_dock) != _dockArea) { + window->addDockWidget(_dockArea, _dock); + } + if (_dock->isFloating() != _dockIsFloating) { + _dock->setFloating(_dockIsFloating); + } + _dock->restoreGeometry(_dockGeo); _registerDock = value; } diff --git a/src/macro-core/macro.hpp b/src/macro-core/macro.hpp index 5d5276b7..33ec88e5 100644 --- a/src/macro-core/macro.hpp +++ b/src/macro-core/macro.hpp @@ -4,6 +4,7 @@ #include "macro-ref.hpp" #include +#include #include #include #include @@ -96,7 +97,10 @@ private: void RunActions(bool &ret, bool ignorePause); void RunActions(bool ignorePause); void SetOnChangeHighlight(); + bool DockIsVisible() const; void SetDockWidgetName() const; + void SaveDockSettings(obs_data_t *obj) const; + void LoadDockSettings(obs_data_t *obj); void RemoveDock(); std::string _name = ""; @@ -125,6 +129,10 @@ private: bool _registerDock = false; bool _dockHasRunButton = true; bool _dockHasPauseButton = true; + bool _dockIsFloating = true; + bool _dockIsVisible = false; + Qt::DockWidgetArea _dockArea; + QByteArray _dockGeo; MacroDock *_dock = nullptr; QAction *_dockAction = nullptr; diff --git a/src/status-control.cpp b/src/status-control.cpp index d94ffdc2..ccb84f62 100644 --- a/src/status-control.cpp +++ b/src/status-control.cpp @@ -146,6 +146,9 @@ StatusDock::StatusDock(QWidget *parent) : OBSDock(parent) wrapper->setFrameShadow(QFrame::Sunken); wrapper->setLayout(layout); setWidget(wrapper); + + setFloating(true); + hide(); } void SetupDock()