diff --git a/UI/auth-restream.cpp b/UI/auth-restream.cpp index 689ea14e84297e..ed4d39c88264c6 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 6216e741016f29..334906c42f7a5e 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 c01eb6e4ea0f5e..034c3d82bd8251 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 add9ce57a94e86..152b2a95730fd7 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 f2ee5e42b81e30..7783fa62d4884a 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 f1937dbeb0b8e8..ffe35c25c39c09 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/forms/OBSBasic.ui b/UI/forms/OBSBasic.ui index ed0d09cf252508..d3b35fccd64513 100644 --- a/UI/forms/OBSBasic.ui +++ b/UI/forms/OBSBasic.ui @@ -713,12 +713,6 @@ - - - - - - @@ -2187,61 +2181,6 @@ Basic.MainMenu.Docks.LockDocks - - - true - - - true - - - Basic.Main.Scenes - - - - - true - - - true - - - Basic.Main.Sources - - - - - true - - - true - - - Mixer - - - - - true - - - true - - - Basic.SceneTransitions - - - - - true - - - true - - - Basic.Main.Controls - - Basic.MainMenu.Help.HelpPortal @@ -2262,17 +2201,6 @@ Basic.MainMenu.Help.Discord - - - true - - - true - - - Basic.Stats - - Basic.MainMenu.Help.About diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 204875e6dacc43..544ff5b03c94d5 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -251,6 +251,32 @@ void assignDockToggle(QDockWidget *dock, QAction *action) dock->connect(action, &QAction::toggled, handleMenuToggle); } +void setupDockAction(QDockWidget *dock) +{ + QAction *action = dock->toggleViewAction(); + + auto neverDisable = [action]() { + QSignalBlocker block(action); + action->setEnabled(true); + }; + + auto newToggleView = [dock](bool check) { + QSignalBlocker block(dock); + dock->setVisible(check); + }; + + // Replace the slot connected by default + action->disconnect(SIGNAL(triggered(bool))); + dock->connect(action, &QAction::triggered, newToggleView); + + // Make the action unable to be disabled +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + action->connect(action, &QAction::changed, neverDisable); +#else + action->connect(action, &QAction::enabledChanged, neverDisable); +#endif +} + extern void RegisterTwitchAuth(); extern void RegisterRestreamAuth(); #if YOUTUBE_ENABLED @@ -423,12 +449,20 @@ OBSBasic::OBSBasic(QWidget *parent) addNudge(Qt::SHIFT | Qt::Key_Left, MoveDir::Left, 10); addNudge(Qt::SHIFT | Qt::Key_Right, MoveDir::Right, 10); - assignDockToggle(ui->scenesDock, ui->toggleScenes); - assignDockToggle(ui->sourcesDock, ui->toggleSources); - assignDockToggle(ui->mixerDock, ui->toggleMixer); - assignDockToggle(ui->transitionsDock, ui->toggleTransitions); - assignDockToggle(ui->controlsDock, ui->toggleControls); - assignDockToggle(statsDock, ui->toggleStats); + /* Setup dock toggle action + * And hide all docks before restoring parent geometry */ +#define SETUP_DOCK(dock) \ + setupDockAction(dock); \ + ui->menuDocks->addAction(dock->toggleViewAction()); \ + dock->setVisible(false); + + SETUP_DOCK(ui->scenesDock); + SETUP_DOCK(ui->sourcesDock); + SETUP_DOCK(ui->mixerDock); + SETUP_DOCK(ui->transitionsDock); + SETUP_DOCK(ui->controlsDock); + SETUP_DOCK(statsDock); +#undef SETUP_DOCK // Register shortcuts for Undo/Redo ui->actionMainUndo->setShortcut(Qt::CTRL | Qt::Key_Z); @@ -440,14 +474,6 @@ OBSBasic::OBSBasic(QWidget *parent) ui->actionMainUndo->setShortcutContext(Qt::ApplicationShortcut); ui->actionMainRedo->setShortcutContext(Qt::ApplicationShortcut); - //hide all docking panes - ui->toggleScenes->setChecked(false); - ui->toggleSources->setChecked(false); - ui->toggleMixer->setChecked(false); - ui->toggleTransitions->setChecked(false); - ui->toggleControls->setChecked(false); - ui->toggleStats->setChecked(false); - QPoint curPos; //restore parent window geometry @@ -2015,10 +2041,12 @@ void OBSBasic::OBSInit() QAction *action = new QAction(QTStr("Basic.MainMenu.Docks." "CustomBrowserDocks"), this); - ui->menuDocks->insertAction(ui->toggleScenes, action); + ui->menuDocks->insertAction(ui->scenesDock->toggleViewAction(), + action); connect(action, &QAction::triggered, this, &OBSBasic::ManageExtraBrowserDocks); - ui->menuDocks->insertSeparator(ui->toggleScenes); + ui->menuDocks->insertSeparator( + ui->scenesDock->toggleViewAction()); LoadExtraBrowserDocks(); } @@ -9048,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")); @@ -9064,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(); @@ -9126,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); } } } @@ -9919,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 = @@ -9935,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 31e01bb3e3be80..ddbf803ef257c6 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -228,7 +228,7 @@ class OBSBasic : public OBSMainWindow { std::vector signalHandlers; - QList> extraDocks; + QList> oldExtraDocks; bool loaded = false; long disableSaving = 1; @@ -551,9 +551,13 @@ class OBSBasic : public OBSMainWindow { void UpdatePreviewProgramIndicators(); + QStringList extraDockNames; + QList> extraDocks; + #ifdef BROWSER_AVAILABLE + QPointer extraBrowserMenuDocksSeparator; + QList> extraBrowserDocks; - QList> extraBrowserDockActions; QStringList extraBrowserDockTargets; void ClearExtraBrowserDocks(); @@ -957,6 +961,9 @@ private slots: 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 21e16a398e787d..a53f66106eda8e 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); }