From e6873d32786305c9d508acdceddb1407e0423e7e Mon Sep 17 00:00:00 2001 From: tytan652 Date: Fri, 21 Oct 2022 16:53:06 +0200 Subject: [PATCH] UI: Refactor integration and browser docks Use the QAction provided by QDockWidget with new Qt connection rather than creating a new one for each dock. Separate extra browser docks from extra docks, the latter is meant for plugin/integration docks. --- UI/auth-restream.cpp | 43 ++++++++---- UI/auth-restream.hpp | 9 +-- UI/auth-twitch.cpp | 76 +++++++++++--------- UI/auth-twitch.hpp | 9 +-- UI/auth-youtube.cpp | 24 +++++-- UI/auth-youtube.hpp | 4 +- UI/window-basic-main.cpp | 131 +++++++++++++++++++++++++++++------ UI/window-basic-main.hpp | 11 ++- UI/window-extra-browsers.cpp | 23 ++---- 9 files changed, 222 insertions(+), 108 deletions(-) diff --git a/UI/auth-restream.cpp b/UI/auth-restream.cpp index 689ea14e8..ed4d39c88 100644 --- a/UI/auth-restream.cpp +++ b/UI/auth-restream.cpp @@ -24,12 +24,28 @@ using namespace json11; #define RESTREAM_STREAMKEY_URL "https://api.restream.io/v2/user/streamKey" #define RESTREAM_SCOPE_VERSION 1 +#define RESTREAM_CHAT_DOCK_NAME "restreamChat" +#define RESTREAM_INFO_DOCK_NAME "restreamInfo" +#define RESTREAM_CHANNELS_DOCK_NAME "restreamChannel" + static Auth::Def restreamDef = {"Restream", Auth::Type::OAuth_StreamKey}; /* ------------------------------------------------------------------------- */ RestreamAuth::RestreamAuth(const Def &d) : OAuthStreamKey(d) {} +RestreamAuth::~RestreamAuth() +{ + if (!uiLoaded) + return; + + OBSBasic *main = OBSBasic::Get(); + + main->RemoveDockWidget(RESTREAM_CHAT_DOCK_NAME); + main->RemoveDockWidget(RESTREAM_INFO_DOCK_NAME); + main->RemoveDockWidget(RESTREAM_CHANNELS_DOCK_NAME); +} + bool RestreamAuth::GetChannelInfo() try { std::string client_id = RESTREAM_CLIENTID; @@ -134,52 +150,49 @@ void RestreamAuth::LoadUI() QSize size = main->frameSize(); QPoint pos = main->pos(); - chat.reset(new BrowserDock()); - chat->setObjectName("restreamChat"); + BrowserDock *chat = new BrowserDock(); + chat->setObjectName(RESTREAM_CHAT_DOCK_NAME); chat->resize(420, 600); chat->setMinimumSize(200, 300); chat->setWindowTitle(QTStr("Auth.Chat")); chat->setAllowedAreas(Qt::AllDockWidgetAreas); - browser = cef->create_widget(chat.data(), url, panel_cookies); + browser = cef->create_widget(chat, url, panel_cookies); chat->SetWidget(browser); - main->addDockWidget(Qt::RightDockWidgetArea, chat.data()); - chatMenu.reset(main->AddDockWidget(chat.data())); + main->AddDockWidget(chat, Qt::RightDockWidgetArea); /* ----------------------------------- */ url = "https://restream.io/titles/embed"; - info.reset(new BrowserDock()); - info->setObjectName("restreamInfo"); + BrowserDock *info = new BrowserDock(); + info->setObjectName(RESTREAM_INFO_DOCK_NAME); info->resize(410, 600); info->setMinimumSize(200, 150); info->setWindowTitle(QTStr("Auth.StreamInfo")); info->setAllowedAreas(Qt::AllDockWidgetAreas); - browser = cef->create_widget(info.data(), url, panel_cookies); + browser = cef->create_widget(info, url, panel_cookies); info->SetWidget(browser); - main->addDockWidget(Qt::LeftDockWidgetArea, info.data()); - infoMenu.reset(main->AddDockWidget(info.data())); + main->AddDockWidget(info, Qt::LeftDockWidgetArea); /* ----------------------------------- */ url = "https://restream.io/channel/embed"; - channels.reset(new BrowserDock()); - channels->setObjectName("restreamChannel"); + BrowserDock *channels = new BrowserDock(); + channels->setObjectName(RESTREAM_CHANNELS_DOCK_NAME); channels->resize(410, 600); channels->setMinimumSize(410, 300); channels->setWindowTitle(QTStr("RestreamAuth.Channels")); channels->setAllowedAreas(Qt::AllDockWidgetAreas); - browser = cef->create_widget(channels.data(), url, panel_cookies); + browser = cef->create_widget(channels, url, panel_cookies); channels->SetWidget(browser); - main->addDockWidget(Qt::LeftDockWidgetArea, channels.data()); - channelMenu.reset(main->AddDockWidget(channels.data())); + main->AddDockWidget(channels, Qt::LeftDockWidgetArea); /* ----------------------------------- */ diff --git a/UI/auth-restream.hpp b/UI/auth-restream.hpp index 6216e7410..334906c42 100644 --- a/UI/auth-restream.hpp +++ b/UI/auth-restream.hpp @@ -7,14 +7,6 @@ class BrowserDock; class RestreamAuth : public OAuthStreamKey { Q_OBJECT - QSharedPointer chat; - QSharedPointer info; - QSharedPointer channels; - - QSharedPointer chatMenu; - QSharedPointer infoMenu; - QSharedPointer channelMenu; - bool uiLoaded = false; virtual bool RetryLogin() override; @@ -28,6 +20,7 @@ class RestreamAuth : public OAuthStreamKey { public: RestreamAuth(const Def &d); + ~RestreamAuth(); static std::shared_ptr Login(QWidget *parent, const std::string &service_name); diff --git a/UI/auth-twitch.cpp b/UI/auth-twitch.cpp index c01eb6e4e..034c3d82b 100644 --- a/UI/auth-twitch.cpp +++ b/UI/auth-twitch.cpp @@ -27,6 +27,11 @@ using namespace json11; #define TWITCH_SCOPE_VERSION 1 +#define TWITCH_CHAT_DOCK_NAME "twitchChat" +#define TWITCH_INFO_DOCK_NAME "twitchInfo" +#define TWITCH_STATS_DOCK_NAME "twitchStats" +#define TWITCH_FEED_DOCK_NAME "twitchFeed" + static Auth::Def twitchDef = {"Twitch", Auth::Type::OAuth_StreamKey}; /* ------------------------------------------------------------------------- */ @@ -49,6 +54,19 @@ TwitchAuth::TwitchAuth(const Def &d) : OAuthStreamKey(d) &TwitchAuth::TryLoadSecondaryUIPanes); } +TwitchAuth::~TwitchAuth() +{ + if (!uiLoaded) + return; + + OBSBasic *main = OBSBasic::Get(); + + main->RemoveDockWidget(TWITCH_CHAT_DOCK_NAME); + main->RemoveDockWidget(TWITCH_INFO_DOCK_NAME); + main->RemoveDockWidget(TWITCH_STATS_DOCK_NAME); + main->RemoveDockWidget(TWITCH_FEED_DOCK_NAME); +} + bool TwitchAuth::MakeApiRequest(const char *path, Json &json_out) { std::string client_id = TWITCH_CLIENTID; @@ -233,16 +251,16 @@ void TwitchAuth::LoadUI() QSize size = main->frameSize(); QPoint pos = main->pos(); - chat.reset(new BrowserDock()); - chat->setObjectName("twitchChat"); + BrowserDock *chat = new BrowserDock(); + chat->setObjectName(TWITCH_CHAT_DOCK_NAME); chat->resize(300, 600); chat->setMinimumSize(200, 300); chat->setWindowTitle(QTStr("Auth.Chat")); chat->setAllowedAreas(Qt::AllDockWidgetAreas); - browser = cef->create_widget(chat.data(), url, panel_cookies); + browser = cef->create_widget(chat, url, panel_cookies); chat->SetWidget(browser); - cef->add_force_popup_url(moderation_tools_url, chat.data()); + cef->add_force_popup_url(moderation_tools_url, chat); if (App()->IsThemeDark()) { script = "localStorage.setItem('twilight.theme', 1);"; @@ -261,8 +279,7 @@ void TwitchAuth::LoadUI() browser->setStartupScript(script); - main->addDockWidget(Qt::RightDockWidgetArea, chat.data()); - chatMenu.reset(main->AddDockWidget(chat.data())); + main->AddDockWidget(chat, Qt::RightDockWidgetArea); /* ----------------------------------- */ @@ -323,19 +340,18 @@ void TwitchAuth::LoadSecondaryUIPanes() url += name; url += "/stream-manager/edit-stream-info"; - info.reset(new BrowserDock()); - info->setObjectName("twitchInfo"); + BrowserDock *info = new BrowserDock(); + info->setObjectName(TWITCH_INFO_DOCK_NAME); info->resize(300, 650); info->setMinimumSize(200, 300); info->setWindowTitle(QTStr("Auth.StreamInfo")); info->setAllowedAreas(Qt::AllDockWidgetAreas); - browser = cef->create_widget(info.data(), url, panel_cookies); + browser = cef->create_widget(info, url, panel_cookies); info->SetWidget(browser); browser->setStartupScript(script); - main->addDockWidget(Qt::RightDockWidgetArea, info.data()); - infoMenu.reset(main->AddDockWidget(info.data())); + main->AddDockWidget(info, Qt::RightDockWidgetArea); /* ----------------------------------- */ @@ -343,19 +359,18 @@ void TwitchAuth::LoadSecondaryUIPanes() url += name; url += "/dashboard/live/stats"; - stat.reset(new BrowserDock()); - stat->setObjectName("twitchStats"); - stat->resize(200, 250); - stat->setMinimumSize(200, 150); - stat->setWindowTitle(QTStr("TwitchAuth.Stats")); - stat->setAllowedAreas(Qt::AllDockWidgetAreas); + BrowserDock *stats = new BrowserDock(); + stats->setObjectName(TWITCH_STATS_DOCK_NAME); + stats->resize(200, 250); + stats->setMinimumSize(200, 150); + stats->setWindowTitle(QTStr("TwitchAuth.Stats")); + stats->setAllowedAreas(Qt::AllDockWidgetAreas); - browser = cef->create_widget(stat.data(), url, panel_cookies); - stat->SetWidget(browser); + browser = cef->create_widget(stats, url, panel_cookies); + stats->SetWidget(browser); browser->setStartupScript(script); - main->addDockWidget(Qt::RightDockWidgetArea, stat.data()); - statMenu.reset(main->AddDockWidget(stat.data())); + main->AddDockWidget(stats, Qt::RightDockWidgetArea); /* ----------------------------------- */ @@ -364,36 +379,35 @@ void TwitchAuth::LoadSecondaryUIPanes() url += "/stream-manager/activity-feed"; url += "?uuid=" + uuid; - feed.reset(new BrowserDock()); - feed->setObjectName("twitchFeed"); + BrowserDock *feed = new BrowserDock(); + feed->setObjectName(TWITCH_FEED_DOCK_NAME); feed->resize(300, 650); feed->setMinimumSize(200, 300); feed->setWindowTitle(QTStr("TwitchAuth.Feed")); feed->setAllowedAreas(Qt::AllDockWidgetAreas); - browser = cef->create_widget(feed.data(), url, panel_cookies); + browser = cef->create_widget(feed, url, panel_cookies); feed->SetWidget(browser); browser->setStartupScript(script); - main->addDockWidget(Qt::RightDockWidgetArea, feed.data()); - feedMenu.reset(main->AddDockWidget(feed.data())); + main->AddDockWidget(feed, Qt::RightDockWidgetArea); /* ----------------------------------- */ info->setFloating(true); - stat->setFloating(true); + stats->setFloating(true); feed->setFloating(true); - QSize statSize = stat->frameSize(); + QSize statSize = stats->frameSize(); info->move(pos.x() + 50, pos.y() + 50); - stat->move(pos.x() + size.width() / 2 - statSize.width() / 2, - pos.y() + size.height() / 2 - statSize.height() / 2); + stats->move(pos.x() + size.width() / 2 - statSize.width() / 2, + pos.y() + size.height() / 2 - statSize.height() / 2); feed->move(pos.x() + 100, pos.y() + 100); if (firstLoad) { info->setVisible(true); - stat->setVisible(false); + stats->setVisible(false); feed->setVisible(false); } else { uint32_t lastVersion = config_get_int(App()->GlobalConfig(), diff --git a/UI/auth-twitch.hpp b/UI/auth-twitch.hpp index add9ce57a..152b2a957 100644 --- a/UI/auth-twitch.hpp +++ b/UI/auth-twitch.hpp @@ -15,14 +15,6 @@ class TwitchAuth : public OAuthStreamKey { friend class TwitchLogin; - QSharedPointer chat; - QSharedPointer info; - QSharedPointer stat; - QSharedPointer feed; - QSharedPointer chatMenu; - QSharedPointer infoMenu; - QSharedPointer statMenu; - QSharedPointer feedMenu; bool uiLoaded = false; std::string name; @@ -40,6 +32,7 @@ class TwitchAuth : public OAuthStreamKey { public: TwitchAuth(const Def &d); + ~TwitchAuth(); static std::shared_ptr Login(QWidget *parent, const std::string &service_name); diff --git a/UI/auth-youtube.cpp b/UI/auth-youtube.cpp index f2ee5e42b..7783fa62d 100644 --- a/UI/auth-youtube.cpp +++ b/UI/auth-youtube.cpp @@ -42,6 +42,8 @@ using namespace json11; #define YOUTUBE_CHAT_POPOUT_URL \ "https://www.youtube.com/live_chat?is_popout=1&dark_theme=1&v=%1" +#define YOUTUBE_CHAT_DOCK_NAME "ytChat" + static const char allowedChars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; static const int allowedCount = static_cast(sizeof(allowedChars) - 1); @@ -71,6 +73,19 @@ YoutubeAuth::YoutubeAuth(const Def &d) { } +YoutubeAuth::~YoutubeAuth() +{ + if (!uiLoaded) + return; + +#ifdef BROWSER_AVAILABLE + OBSBasic *main = OBSBasic::Get(); + + main->RemoveDockWidget(YOUTUBE_CHAT_DOCK_NAME); + chat = nullptr; +#endif +} + bool YoutubeAuth::RetryLogin() { return true; @@ -139,20 +154,19 @@ void YoutubeAuth::LoadUI() QSize size = main->frameSize(); QPoint pos = main->pos(); - chat.reset(new YoutubeChatDock()); - chat->setObjectName("ytChat"); + chat = new YoutubeChatDock(); + chat->setObjectName(YOUTUBE_CHAT_DOCK_NAME); chat->resize(300, 600); chat->setMinimumSize(200, 300); chat->setWindowTitle(QTStr("Auth.Chat")); chat->setAllowedAreas(Qt::AllDockWidgetAreas); - browser = cef->create_widget(chat.data(), YOUTUBE_CHAT_PLACEHOLDER_URL, + browser = cef->create_widget(chat, YOUTUBE_CHAT_PLACEHOLDER_URL, panel_cookies); browser->setStartupScript(ytchat_script); chat->SetWidget(browser); - main->addDockWidget(Qt::RightDockWidgetArea, chat.data()); - chatMenu.reset(main->AddDockWidget(chat.data())); + main->AddDockWidget(chat, Qt::RightDockWidgetArea); chat->setFloating(true); chat->move(pos.x() + size.width() - chat->width() - 50, pos.y() + 50); diff --git a/UI/auth-youtube.hpp b/UI/auth-youtube.hpp index f1937dbeb..ffe35c25c 100644 --- a/UI/auth-youtube.hpp +++ b/UI/auth-youtube.hpp @@ -43,8 +43,7 @@ class YoutubeAuth : public OAuthStreamKey { std::string section; #ifdef BROWSER_AVAILABLE - QSharedPointer chat; - QSharedPointer chatMenu; + YoutubeChatDock *chat; #endif virtual bool RetryLogin() override; @@ -56,6 +55,7 @@ class YoutubeAuth : public OAuthStreamKey { public: YoutubeAuth(const Def &d); + ~YoutubeAuth(); void SetChatId(const QString &chat_id, const std::string &api_chat_id); void ResetChat(); diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 9304b6a3f..280309652 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -9076,13 +9076,19 @@ int OBSBasic::GetProfilePath(char *path, size_t size, const char *file) const void OBSBasic::on_resetDocks_triggered(bool force) { /* prune deleted extra docks */ - for (int i = extraDocks.size() - 1; i >= 0; i--) { - if (!extraDocks[i]) { - extraDocks.removeAt(i); + for (int i = oldExtraDocks.size() - 1; i >= 0; i--) { + if (!oldExtraDocks[i]) { + oldExtraDocks.removeAt(i); } } - if (extraDocks.size() && !force) { +#ifdef BROWSER_AVAILABLE + if ((oldExtraDocks.size() || extraDocks.size() || + extraBrowserDocks.size()) && + !force) { +#else + if ((oldExtraDocks.size() || extraDocks.size()) && !force) { +#endif QMessageBox::StandardButton button = QMessageBox::question( this, QTStr("ResetUIWarning.Title"), QTStr("ResetUIWarning.Text")); @@ -9092,17 +9098,33 @@ void OBSBasic::on_resetDocks_triggered(bool force) } /* undock/hide/center extra docks */ - for (int i = extraDocks.size() - 1; i >= 0; i--) { - if (extraDocks[i]) { - extraDocks[i]->setVisible(true); - extraDocks[i]->setFloating(true); - extraDocks[i]->move(frameGeometry().topLeft() + - rect().center() - - extraDocks[i]->rect().center()); - extraDocks[i]->setVisible(false); + for (int i = oldExtraDocks.size() - 1; i >= 0; i--) { + if (oldExtraDocks[i]) { + oldExtraDocks[i]->setVisible(true); + oldExtraDocks[i]->setFloating(true); + oldExtraDocks[i]->move( + frameGeometry().topLeft() + rect().center() - + oldExtraDocks[i]->rect().center()); + oldExtraDocks[i]->setVisible(false); } } +#define RESET_DOCKLIST(dockList) \ + for (int i = dockList.size() - 1; i >= 0; i--) { \ + dockList[i]->setVisible(true); \ + dockList[i]->setFloating(true); \ + dockList[i]->move(frameGeometry().topLeft() + \ + rect().center() - \ + dockList[i]->rect().center()); \ + dockList[i]->setVisible(false); \ + } + + RESET_DOCKLIST(extraDocks) +#ifdef BROWSER_AVAILABLE + RESET_DOCKLIST(extraBrowserDocks) +#endif +#undef RESET_DOCKLIST + restoreState(startingDockLayout); int cx = width(); @@ -9154,11 +9176,19 @@ void OBSBasic::on_lockDocks_toggled(bool lock) ui->controlsDock->setFeatures(mainFeatures); statsDock->setFeatures(features); - for (int i = extraDocks.size() - 1; i >= 0; i--) { - if (!extraDocks[i]) { - extraDocks.removeAt(i); + for (int i = extraDocks.size() - 1; i >= 0; i--) + extraDocks[i]->setFeatures(features); + +#ifdef BROWSER_AVAILABLE + for (int i = extraBrowserDocks.size() - 1; i >= 0; i--) + extraBrowserDocks[i]->setFeatures(features); +#endif + + for (int i = oldExtraDocks.size() - 1; i >= 0; i--) { + if (!oldExtraDocks[i]) { + oldExtraDocks.removeAt(i); } else { - extraDocks[i]->setFeatures(features); + oldExtraDocks[i]->setFeatures(features); } } } @@ -9947,11 +9977,20 @@ void OBSBasic::ResizeOutputSizeOfSource() QAction *OBSBasic::AddDockWidget(QDockWidget *dock) { +#ifdef BROWSER_AVAILABLE + QAction *action = new QAction(dock->windowTitle(), ui->menuDocks); + + if (!extraBrowserMenuDocksSeparator.isNull()) + ui->menuDocks->insertAction(extraBrowserMenuDocksSeparator, + action); + else + ui->menuDocks->addAction(action); +#else QAction *action = ui->menuDocks->addAction(dock->windowTitle()); - action->setProperty("uuid", dock->property("uuid").toString()); +#endif action->setCheckable(true); assignDockToggle(dock, action); - extraDocks.push_back(dock); + oldExtraDocks.push_back(dock); bool lock = ui->lockDocks->isChecked(); QDockWidget::DockWidgetFeatures features = @@ -9963,15 +10002,65 @@ QAction *OBSBasic::AddDockWidget(QDockWidget *dock) dock->setFeatures(features); /* prune deleted docks */ - for (int i = extraDocks.size() - 1; i >= 0; i--) { - if (!extraDocks[i]) { - extraDocks.removeAt(i); + for (int i = oldExtraDocks.size() - 1; i >= 0; i--) { + if (!oldExtraDocks[i]) { + oldExtraDocks.removeAt(i); } } return action; } +void OBSBasic::AddDockWidget(QDockWidget *dock, Qt::DockWidgetArea area, + bool extraBrowser) +{ + if (dock->objectName().isEmpty()) + return; + + bool lock = ui->lockDocks->isChecked(); + QDockWidget::DockWidgetFeatures features = + lock ? QDockWidget::NoDockWidgetFeatures + : (QDockWidget::DockWidgetClosable | + QDockWidget::DockWidgetMovable | + QDockWidget::DockWidgetFloatable); + + setupDockAction(dock); + dock->setFeatures(features); + addDockWidget(area, dock); + +#ifdef BROWSER_AVAILABLE + if (extraBrowser && extraBrowserMenuDocksSeparator.isNull()) + extraBrowserMenuDocksSeparator = ui->menuDocks->addSeparator(); + + if (!extraBrowser && !extraBrowserMenuDocksSeparator.isNull()) + ui->menuDocks->insertAction(extraBrowserMenuDocksSeparator, + dock->toggleViewAction()); + else + ui->menuDocks->addAction(dock->toggleViewAction()); + + if (extraBrowser) + return; +#else + UNUSED_PARAMETER(extraBrowser); + + ui->menuDocks->addAction(dock->toggleViewAction()); +#endif + + extraDockNames.push_back(dock->objectName()); + extraDocks.push_back(QSharedPointer(dock)); +} + +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); +} + OBSBasic *OBSBasic::Get() { return reinterpret_cast(App()->GetMainWindow()); diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index 31e01bb3e..ddbf803ef 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -228,7 +228,7 @@ private: std::vector signalHandlers; - QList> extraDocks; + QList> oldExtraDocks; bool loaded = false; long disableSaving = 1; @@ -551,9 +551,13 @@ private: void UpdatePreviewProgramIndicators(); + QStringList extraDockNames; + QList> extraDocks; + #ifdef BROWSER_AVAILABLE + QPointer extraBrowserMenuDocksSeparator; + QList> extraBrowserDocks; - QList> extraBrowserDockActions; QStringList extraBrowserDockTargets; void ClearExtraBrowserDocks(); @@ -957,6 +961,9 @@ public: void CreateEditTransformWindow(obs_sceneitem_t *item); QAction *AddDockWidget(QDockWidget *dock); + void AddDockWidget(QDockWidget *dock, Qt::DockWidgetArea area, + bool extraBrowser = false); + void RemoveDockWidget(const QString &name); static OBSBasic *Get(); diff --git a/UI/window-extra-browsers.cpp b/UI/window-extra-browsers.cpp index 21e16a398..a53f66106 100644 --- a/UI/window-extra-browsers.cpp +++ b/UI/window-extra-browsers.cpp @@ -179,7 +179,6 @@ void ExtraBrowsersModel::UpdateItem(Item &item) main->extraBrowserDocks[idx].data()); dock->setWindowTitle(item.title); dock->setObjectName(item.title + OBJ_NAME_SUFFIX); - main->extraBrowserDockActions[idx]->setText(item.title); if (main->extraBrowserDockTargets[idx] != item.url) { dock->cefWidget->setURL(QT_TO_UTF8(item.url)); @@ -234,11 +233,13 @@ void ExtraBrowsersModel::Apply() for (int i = deleted.size() - 1; i >= 0; i--) { int idx = deleted[i]; - main->extraBrowserDockActions.removeAt(idx); main->extraBrowserDockTargets.removeAt(idx); main->extraBrowserDocks.removeAt(idx); } + if (main->extraBrowserDocks.empty()) + main->extraBrowserMenuDocksSeparator.clear(); + deleted.clear(); Reset(); @@ -459,7 +460,6 @@ void OBSExtraBrowsers::on_apply_clicked() void OBSBasic::ClearExtraBrowserDocks() { extraBrowserDockTargets.clear(); - extraBrowserDockActions.clear(); extraBrowserDocks.clear(); } @@ -475,7 +475,7 @@ void OBSBasic::LoadExtraBrowserDocks() Json::array array = json.array_items(); if (!array.empty()) - ui->menuDocks->addSeparator(); + extraBrowserMenuDocksSeparator = ui->menuDocks->addSeparator(); for (Json &item : array) { std::string title = item["title"].string_value(); @@ -562,7 +562,9 @@ void OBSBasic::AddExtraBrowserDock(const QString &title, const QString &url, } } - addDockWidget(Qt::RightDockWidgetArea, dock); + AddDockWidget(dock, Qt::RightDockWidgetArea, true); + extraBrowserDocks.push_back(QSharedPointer(dock)); + extraBrowserDockTargets.push_back(url); if (firstCreate) { dock->setFloating(true); @@ -577,15 +579,4 @@ void OBSBasic::AddExtraBrowserDock(const QString &title, const QString &url, dock->move(curPos); dock->setVisible(true); } - - QAction *action = AddDockWidget(dock); - if (firstCreate) { - action->blockSignals(true); - action->setChecked(true); - action->blockSignals(false); - } - - extraBrowserDocks.push_back(QSharedPointer(dock)); - extraBrowserDockActions.push_back(QSharedPointer(action)); - extraBrowserDockTargets.push_back(url); }