From 7af2095f2f71d57fd149fefef025bc798f074477 Mon Sep 17 00:00:00 2001 From: Waqar Ahmed Date: Wed, 8 Sep 2021 15:09:41 +0500 Subject: [PATCH] Allow switching tabs via context menu in the tabs area This change allows you to switch tabs via the context menu. The context menu only shows up if you click on the empty area beside the tabs. Can be tested with `--allow-switch-tabs-via-menu` option in the example. Fixes #232 Signed-off-by: Waqar Ahmed --- examples/dockwidgets/main.cpp | 9 ++++++- src/Config.h | 1 + src/MainWindowBase.cpp | 2 +- src/private/widgets/TabWidgetWidget.cpp | 35 +++++++++++++++++++++++++ src/private/widgets/TabWidgetWidget_p.h | 4 +++ 5 files changed, 49 insertions(+), 2 deletions(-) diff --git a/examples/dockwidgets/main.cpp b/examples/dockwidgets/main.cpp index 59ca8f87..125884c1 100644 --- a/examples/dockwidgets/main.cpp +++ b/examples/dockwidgets/main.cpp @@ -120,13 +120,17 @@ int main(int argc, char **argv) parser.addOption(dontCloseBeforeRestore); QCommandLineOption showButtonsInTabBarIfTitleBarHidden("show-buttons-in-tabbar-if-titlebar-hidden", - QCoreApplication::translate("main", "If we're not using title bars we'll still show the close and float button in the tab bar")); + QCoreApplication::translate("main", "If we're not using title bars we'll still show the close and float button in the tab bar")); parser.addOption(showButtonsInTabBarIfTitleBarHidden); QCommandLineOption centralWidget("central-widget", QCoreApplication::translate("main", "The main window will have a non-detachable central widget")); parser.addOption(centralWidget); + QCommandLineOption ctxtMenuOnTabs("allow-switch-tabs-via-menu", + QCoreApplication::translate("main", "Allow switching tabs via context menu in tabs area")); + parser.addOption(ctxtMenuOnTabs); + #if defined(DOCKS_DEVELOPER_MODE) parser.addOption(centralFrame); @@ -237,6 +241,9 @@ int main(int argc, char **argv) if (parser.isSet(tabsHaveCloseButton)) flags |= KDDockWidgets::Config::Flag_TabsHaveCloseButton; + if (parser.isSet(ctxtMenuOnTabs)) + flags |= KDDockWidgets::Config::Flag_AllowSwitchingTabsViaMenu; + if (parser.isSet(doubleClickMaximize)) flags |= KDDockWidgets::Config::Flag_DoubleClickMaximizes; diff --git a/src/Config.h b/src/Config.h index 7ba78b0c..74dfc685 100644 --- a/src/Config.h +++ b/src/Config.h @@ -83,6 +83,7 @@ public: Flag_KeepAboveIfNotUtilityWindow = 0x10000, ///< Only meaningful if Flag_DontUseUtilityFloatingWindows is set. If floating windows are normal windows, you might still want them to keep above and not minimize when you focus the main window. Flag_CloseOnlyCurrentTab = 0x20000, ///< The TitleBar's close button will only close the current tab, instead of all of them Flag_ShowButtonsOnTabBarIfTitleBarHidden = 0x40000, ///< When using Flag_HideTitleBarWhenTabsVisible the close/float buttons disappear with the title bar. With Flag_ShowButtonsOnTabBarIfHidden they'll be shown in the tab bar. + Flag_AllowSwitchingTabsViaMenu = 0x80000, ///< Allow switching tabs via a context menu when right clicking on the tab area Flag_Default = Flag_AeroSnapWithClientDecos ///< The defaults }; Q_DECLARE_FLAGS(Flags, Flag) diff --git a/src/MainWindowBase.cpp b/src/MainWindowBase.cpp index 47c7ba55..7b446416 100644 --- a/src/MainWindowBase.cpp +++ b/src/MainWindowBase.cpp @@ -788,4 +788,4 @@ QWidgetOrQuick *MainWindowBase::persistentCentralWidget() const return dw->widget(); return nullptr; -} \ No newline at end of file +} diff --git a/src/private/widgets/TabWidgetWidget.cpp b/src/private/widgets/TabWidgetWidget.cpp index 938e1150..80970131 100644 --- a/src/private/widgets/TabWidgetWidget.cpp +++ b/src/private/widgets/TabWidgetWidget.cpp @@ -27,6 +27,7 @@ #include #include #include +#include using namespace KDDockWidgets; @@ -38,6 +39,9 @@ TabWidgetWidget::TabWidgetWidget(Frame *parent) setTabBar(static_cast(m_tabBar->asWidget())); setTabsClosable(Config::self().flags() & Config::Flag_TabsHaveCloseButton); + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, &QTabWidget::customContextMenuRequested, this, &TabWidgetWidget::showContextMenu); + // In case tabs closable is set by the factory, a tabClosedRequested() is emitted when the user presses [x] connect(this, &QTabWidget::tabCloseRequested, this, [this](int index) { if (DockWidgetBase *dw = dockwidgetAt(index)) { @@ -201,3 +205,34 @@ void TabWidgetWidget::updateMargins() m_cornerWidgetLayout->setContentsMargins(QMargins(0, 0, 2, 0) * factor); m_cornerWidgetLayout->setSpacing(int(2 * factor)); } + +void TabWidgetWidget::showContextMenu(QPoint pos) +{ + if (!(Config::self().flags() & Config::Flag_AllowSwitchingTabsViaMenu)) + return; + + QTabBar *tabBar = QTabWidget::tabBar(); + // We dont want context menu if there is only one tab + if (tabBar->count() <= 1) + return; + + // Click on a tab => No menu + if (tabBar->tabAt(pos) >= 0) + return; + + // Right click is allowed only on the tabs area + QRect tabAreaRect = tabBar->rect(); + tabAreaRect.setWidth(this->width()); + if (!tabAreaRect.contains(pos)) + return; + + QMenu menu(this); + for (int i = 0; i < tabBar->count(); ++i) { + QAction *action = menu.addAction(tabText(i), this, [this, i] { + setCurrentIndex(i); + }); + if (i == currentIndex()) + action->setDisabled(true); + } + menu.exec(mapToGlobal(pos)); +} diff --git a/src/private/widgets/TabWidgetWidget_p.h b/src/private/widgets/TabWidgetWidget_p.h index 1ebc8314..15a80c59 100644 --- a/src/private/widgets/TabWidgetWidget_p.h +++ b/src/private/widgets/TabWidgetWidget_p.h @@ -65,6 +65,10 @@ protected: DockWidgetBase *dockwidgetAt(int index) const override; int currentIndex() const override; + /// @brief Shows the context menu. Override to implement your own context menu. + /// By default it's used to honour Config::Flag_AllowSwitchingTabsViaMenu + virtual void showContextMenu(QPoint pos); + private: void updateMargins(); void setupTabBarButtons();