From 90d96e92c2c36be9737c6daa05d2060b97b96ca8 Mon Sep 17 00:00:00 2001 From: tytan652 Date: Sat, 22 Oct 2022 11:51:30 +0200 Subject: [PATCH] obs-frontend-api,UI,docs: Add API to add custom docks with no toggle Some plugin does that by deleting the QAction returned by obs_frontend_add_dock(). Now that obs_frontend_add_dock() is deprecated, obs_frontend_add_custom_qdock() replace this usage. --- UI/api-interface.cpp | 18 +++++ UI/obs-frontend-api/obs-frontend-api.cpp | 6 ++ UI/obs-frontend-api/obs-frontend-api.h | 3 + UI/obs-frontend-api/obs-frontend-internal.hpp | 2 + UI/window-basic-main.cpp | 66 ++++++++++++++++--- UI/window-basic-main.hpp | 5 ++ docs/sphinx/reference-frontend-api.rst | 17 ++++- 7 files changed, 107 insertions(+), 10 deletions(-) diff --git a/UI/api-interface.cpp b/UI/api-interface.cpp index 31e9a9632..8fb3bea3a 100644 --- a/UI/api-interface.cpp +++ b/UI/api-interface.cpp @@ -427,6 +427,24 @@ struct OBSStudioAPI : obs_frontend_callbacks { main->RemoveDockWidget(QT_UTF8(id)); } + bool obs_frontend_add_custom_qdock(const char *id, void *dock) override + { + if (main->IsDockObjectNameUsed(QT_UTF8(id))) { + blog(LOG_WARNING, + "Dock id '%s' already used! " + "Duplicate library?", + id); + return false; + } + + QDockWidget *d = reinterpret_cast(dock); + d->setObjectName(QT_UTF8(id)); + + main->AddCustomDockWidget(d); + + return true; + } + void obs_frontend_add_event_callback(obs_frontend_event_cb callback, void *private_data) override { diff --git a/UI/obs-frontend-api/obs-frontend-api.cpp b/UI/obs-frontend-api/obs-frontend-api.cpp index 15e1ac685..34747fc07 100644 --- a/UI/obs-frontend-api/obs-frontend-api.cpp +++ b/UI/obs-frontend-api/obs-frontend-api.cpp @@ -344,6 +344,12 @@ void obs_frontend_remove_dock(const char *id) c->obs_frontend_remove_dock(id); } +bool obs_frontend_add_custom_qdock(const char *id, void *dock) +{ + return !!callbacks_valid() ? c->obs_frontend_add_custom_qdock(id, dock) + : false; +} + void obs_frontend_add_event_callback(obs_frontend_event_cb callback, void *private_data) { diff --git a/UI/obs-frontend-api/obs-frontend-api.h b/UI/obs-frontend-api/obs-frontend-api.h index 4102ea3f1..a0913e683 100644 --- a/UI/obs-frontend-api/obs-frontend-api.h +++ b/UI/obs-frontend-api/obs-frontend-api.h @@ -147,6 +147,9 @@ EXPORT bool obs_frontend_add_dock_by_id(const char *id, const char *title, EXPORT void obs_frontend_remove_dock(const char *id); +/* takes QDockWidget for dock */ +EXPORT bool obs_frontend_add_custom_qdock(const char *id, void *dock); + typedef void (*obs_frontend_event_cb)(enum obs_frontend_event event, void *private_data); diff --git a/UI/obs-frontend-api/obs-frontend-internal.hpp b/UI/obs-frontend-api/obs-frontend-internal.hpp index 58ba51ae9..90a0e06ea 100644 --- a/UI/obs-frontend-api/obs-frontend-internal.hpp +++ b/UI/obs-frontend-api/obs-frontend-internal.hpp @@ -70,6 +70,8 @@ struct obs_frontend_callbacks { const char *title, void *widget) = 0; virtual void obs_frontend_remove_dock(const char *id) = 0; + virtual bool obs_frontend_add_custom_qdock(const char *id, + void *dock) = 0; virtual void obs_frontend_add_event_callback(obs_frontend_event_cb callback, diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index cae4ddc66..4b57ec240 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -9311,10 +9311,12 @@ void OBSBasic::on_resetDocks_triggered(bool force) #ifdef BROWSER_AVAILABLE if ((oldExtraDocks.size() || extraDocks.size() || - extraBrowserDocks.size()) && + extraCustomDocks.size() || extraBrowserDocks.size()) && !force) { #else - if ((oldExtraDocks.size() || extraDocks.size()) && !force) { + if ((oldExtraDocks.size() || extraDocks.size() || + extraCustomDocks.size()) && + !force) { #endif QMessageBox::StandardButton button = QMessageBox::question( this, QTStr("ResetUIWarning.Title"), @@ -9347,6 +9349,7 @@ void OBSBasic::on_resetDocks_triggered(bool force) } RESET_DOCKLIST(extraDocks) + RESET_DOCKLIST(extraCustomDocks) #ifdef BROWSER_AVAILABLE RESET_DOCKLIST(extraBrowserDocks) #endif @@ -9406,6 +9409,9 @@ void OBSBasic::on_lockDocks_toggled(bool lock) for (int i = extraDocks.size() - 1; i >= 0; i--) extraDocks[i]->setFeatures(features); + for (int i = extraCustomDocks.size() - 1; i >= 0; i--) + extraCustomDocks[i]->setFeatures(features); + #ifdef BROWSER_AVAILABLE for (int i = extraBrowserDocks.size() - 1; i >= 0; i--) extraBrowserDocks[i]->setFeatures(features); @@ -10321,13 +10327,17 @@ void OBSBasic::AddDockWidget(QDockWidget *dock, Qt::DockWidgetArea area, void OBSBasic::RemoveDockWidget(const QString &name) { - if (!extraDockNames.contains(name)) - return; - - int idx = extraDockNames.indexOf(name); - extraDockNames.removeAt(idx); - extraDocks[idx].clear(); - extraDocks.removeAt(idx); + if (extraDockNames.contains(name)) { + int idx = extraDockNames.indexOf(name); + extraDockNames.removeAt(idx); + extraDocks[idx].clear(); + extraDocks.removeAt(idx); + } else if (extraCustomDockNames.contains(name)) { + int idx = extraCustomDockNames.indexOf(name); + extraCustomDockNames.removeAt(idx); + removeDockWidget(extraCustomDocks[idx]); + extraCustomDocks.removeAt(idx); + } } bool OBSBasic::IsDockObjectNameUsed(const QString &name) @@ -10341,10 +10351,48 @@ bool OBSBasic::IsDockObjectNameUsed(const QString &name) << "statsDock"; list << oldExtraDockNames; list << extraDockNames; + list << extraCustomDockNames; return list.contains(name); } +void OBSBasic::AddCustomDockWidget(QDockWidget *dock) +{ + // Prevent the object name from being changed + connect(dock, &QObject::objectNameChanged, this, + &OBSBasic::RepairCustomExtraDockName); + + bool lock = ui->lockDocks->isChecked(); + QDockWidget::DockWidgetFeatures features = + lock ? QDockWidget::NoDockWidgetFeatures + : (QDockWidget::DockWidgetClosable | + QDockWidget::DockWidgetMovable | + QDockWidget::DockWidgetFloatable); + + dock->setFeatures(features); + addDockWidget(Qt::RightDockWidgetArea, dock); + + extraCustomDockNames.push_back(dock->objectName()); + extraCustomDocks.push_back(dock); +} + +void OBSBasic::RepairCustomExtraDockName() +{ + QDockWidget *dock = reinterpret_cast(sender()); + int idx = extraCustomDocks.indexOf(dock); + QSignalBlocker block(dock); + + if (idx == -1) { + blog(LOG_WARNING, "A custom dock got its object name changed"); + return; + } + + blog(LOG_WARNING, "The custom dock '%s' got its object name restored", + QT_TO_UTF8(extraCustomDockNames[idx])); + + dock->setObjectName(extraCustomDockNames[idx]); +} + OBSBasic *OBSBasic::Get() { return reinterpret_cast(App()->GetMainWindow()); diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index c5908797b..5079b057a 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -557,6 +557,9 @@ private: QStringList extraDockNames; QList> extraDocks; + QStringList extraCustomDockNames; + QList> extraCustomDocks; + #ifdef BROWSER_AVAILABLE QPointer extraBrowserMenuDocksSeparator; @@ -972,6 +975,7 @@ public: bool extraBrowser = false); void RemoveDockWidget(const QString &name); bool IsDockObjectNameUsed(const QString &name); + void AddCustomDockWidget(QDockWidget *dock); static OBSBasic *Get(); @@ -1205,6 +1209,7 @@ private slots: void ResizeOutputSizeOfSource(); void RepairOldExtraDockName(); + void RepairCustomExtraDockName(); public slots: void on_actionResetTransform_triggered(); diff --git a/docs/sphinx/reference-frontend-api.rst b/docs/sphinx/reference-frontend-api.rst index b4ed0f4d4..a68db69ce 100644 --- a/docs/sphinx/reference-frontend-api.rst +++ b/docs/sphinx/reference-frontend-api.rst @@ -448,7 +448,8 @@ Functions :return: A pointer to the added QAction .. deprecated:: 29.1 - Prefer :c:func:`obs_frontend_add_dock_by_id()` instead. + Prefer :c:func:`obs_frontend_add_dock_by_id()` or + :c:func:`obs_frontend_add_custom_qdock()` instead. --------------------------------------- @@ -476,6 +477,20 @@ Functions --------------------------------------- +.. function:: bool obs_frontend_add_custom_qdock(const char *id, void *dock) + + Adds a custom dock to the UI with no toggle. + + Note: Use :c:func:`obs_frontend_remove_dock` to remove the dock + reference and id from the UI. + + :param id: Unique identifier of the dock + :param dock: QDockWidget to add + :return: *true* if the dock was added, *false* if the id was already + used + +--------------------------------------- + .. function:: void obs_frontend_add_event_callback(obs_frontend_event_cb callback, void *private_data) Adds a callback that will be called when a frontend event occurs.