From 5eab28cbda2588a10b71dc7970cb8ad90c549255 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sat, 4 May 2024 00:45:05 +0200 Subject: [PATCH] Gui: Adjust sizing of Workbench TabBar when changing orientation This should fix issues when toolbar containing Workbench TabBar suddenly (or not) changes orientation. It also fixes size policies so toolbar resizes properly and does not cause window to grow. Fixes: #13286 --- src/Gui/WorkbenchSelector.cpp | 169 +++++++++++++++++++++++----------- src/Gui/WorkbenchSelector.h | 18 +++- 2 files changed, 129 insertions(+), 58 deletions(-) diff --git a/src/Gui/WorkbenchSelector.cpp b/src/Gui/WorkbenchSelector.cpp index bf164c31c3e64..d5152f0ca0e62 100644 --- a/src/Gui/WorkbenchSelector.cpp +++ b/src/Gui/WorkbenchSelector.cpp @@ -32,13 +32,12 @@ # include #endif +#include "Base/Tools.h" #include "Action.h" #include "BitmapFactory.h" #include "Command.h" -#include "PreferencePages/DlgSettingsWorkbenchesImp.h" #include "DlgPreferencesImp.h" #include "MainWindow.h" -#include "WorkbenchManager.h" #include "WorkbenchSelector.h" @@ -111,11 +110,12 @@ WorkbenchTabWidget::WorkbenchTabWidget(WorkbenchGroup* aGroup, QWidget* parent) tabBar = new QTabBar(this); moreButton = new QToolButton(this); - auto layout = new QHBoxLayout(this); + layout = new QBoxLayout(QBoxLayout::LeftToRight, this); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(tabBar); layout->addWidget(moreButton); + layout->setAlignment(moreButton, Qt::AlignCenter); setLayout(layout); @@ -132,10 +132,12 @@ WorkbenchTabWidget::WorkbenchTabWidget(WorkbenchGroup* aGroup, QWidget* parent) hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); std::string orientation = hGrp->GetASCII("TabBarOrientation", "North"); - tabBar->setShape(orientation == "North" ? QTabBar::RoundedNorth : - orientation == "South" ? QTabBar::RoundedSouth : - orientation == "East" ? QTabBar::RoundedEast : - QTabBar::RoundedWest); + setToolBarArea( + orientation == "North" ? Qt::TopToolBarArea : + orientation == "South" ? Qt::BottomToolBarArea : + orientation == "East" ? Qt::LeftToolBarArea : + Qt::RightToolBarArea + ); } tabBar->setDocumentMode(true); @@ -143,48 +145,90 @@ WorkbenchTabWidget::WorkbenchTabWidget(WorkbenchGroup* aGroup, QWidget* parent) tabBar->setDrawBase(true); tabBar->setIconSize(QSize(16, 16)); - refreshList(aGroup->getEnabledWbActions()); + updateWorkbenchList(); - connect(aGroup, &WorkbenchGroup::workbenchListRefreshed, this, &WorkbenchTabWidget::refreshList); - connect(aGroup->groupAction(), &QActionGroup::triggered, this, [this](QAction* action) { - if (wbActionGroup->getDisabledWbActions().contains(action)) { - if (additionalWorkbenchAction == action) { - return; - } + connect(aGroup, &WorkbenchGroup::workbenchListRefreshed, this, &WorkbenchTabWidget::updateWorkbenchList); + connect(aGroup->groupAction(), &QActionGroup::triggered, this, &WorkbenchTabWidget::handleWorkbenchSelection); + connect(tabBar, &QTabBar::currentChanged, this, &WorkbenchTabWidget::handleTabChange); + + if (auto toolBar = qobject_cast(parent)) { + connect(toolBar, &QToolBar::topLevelChanged, this, &WorkbenchTabWidget::updateLayout); + connect(toolBar, &QToolBar::orientationChanged, this, &WorkbenchTabWidget::updateLayout); + } +} - if (additionalWorkbenchAction) { - tabBar->removeTab(tabBar->count() - 1); - } +void WorkbenchTabWidget::updateLayout() +{ + auto toolBar = qobject_cast(parentWidget()); - additionalWorkbenchAction = action; + // if it's not placed in toolbar it must be placed in menubar so alike top toolbar area + if (!toolBar) { + setToolBarArea(Qt::TopToolBarArea); + return; + } - addWorkbenchTab(action); - tabBar->setCurrentIndex(tabBar->count() - 1); + setSizePolicy(toolBar->sizePolicy()); + tabBar->setSizePolicy(toolBar->sizePolicy()); - return; - } + if (toolBar->isFloating()) { + setToolBarArea(toolBar->orientation() == Qt::Horizontal ? Qt::TopToolBarArea : Qt::LeftToolBarArea); + return; + } - tabBar->setCurrentIndex(actionToTabIndex[action]); - }); + setToolBarArea(getMainWindow()->toolBarArea(toolBar)); +} - connect(tabBar, qOverload(&QTabBar::currentChanged), aGroup, [this](int index) { - tabIndexToAction[index]->trigger(); +void WorkbenchTabWidget::handleWorkbenchSelection(QAction* selectedWorkbenchAction) +{ + if (wbActionGroup->getDisabledWbActions().contains(selectedWorkbenchAction)) { + if (additionalWorkbenchAction == selectedWorkbenchAction) { + return; + } - if (index != tabBar->count() - 1 && additionalWorkbenchAction) { + if (additionalWorkbenchAction) { tabBar->removeTab(tabBar->count() - 1); - additionalWorkbenchAction = nullptr; } - }); - if (parent->inherits("QToolBar")) { - // Connect toolbar orientation changed - QToolBar* tb = qobject_cast(parent); - connect(tb, &QToolBar::topLevelChanged, this, &WorkbenchTabWidget::updateLayoutAndTabOrientation); + additionalWorkbenchAction = selectedWorkbenchAction; + + addWorkbenchTab(selectedWorkbenchAction); + tabBar->setCurrentIndex(tabBar->count() - 1); + + return; + } + + updateLayout(); + + tabBar->setCurrentIndex(actionToTabIndex[selectedWorkbenchAction]); +} + +void WorkbenchTabWidget::handleTabChange(int selectedTabIndex) +{ + // Prevents from rapid workbench changes on initialization as this can cause + // some serious race conditions. + if (isInitializing) { + return; + } + + if (tabIndexToAction.find(selectedTabIndex) != tabIndexToAction.end()) { + tabIndexToAction[selectedTabIndex]->trigger(); + } + + if (selectedTabIndex != tabBar->count() - 1 && additionalWorkbenchAction) { + tabBar->removeTab(tabBar->count() - 1); + additionalWorkbenchAction = nullptr; } + + adjustSize(); } -void WorkbenchTabWidget::refreshList(QList actionList) +void WorkbenchTabWidget::updateWorkbenchList() { + // As clearing and adding tabs can cause changing current tab in QTabBar. + // This in turn will cause workbench to change, so we need to prevent + // processing of such events until the QTabBar is fully prepared. + Base::StateLocker lock(isInitializing); + actionToTabIndex.clear(); // tabs->clear() (QTabBar has no clear) @@ -192,7 +236,7 @@ void WorkbenchTabWidget::refreshList(QList actionList) tabBar->removeTab(i); } - for (QAction* action : actionList) { + for (QAction* action : wbActionGroup->getEnabledWbActions()) { addWorkbenchTab(action); } @@ -201,6 +245,7 @@ void WorkbenchTabWidget::refreshList(QList actionList) } buildPrefMenu(); + adjustSize(); } void WorkbenchTabWidget::addWorkbenchTab(QAction* action) @@ -209,8 +254,10 @@ void WorkbenchTabWidget::addWorkbenchTab(QAction* action) hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); int itemStyleIndex = hGrp->GetInt("WorkbenchSelectorItem", 0); - actionToTabIndex[action] = tabBar->count(); - tabIndexToAction[tabBar->count()] = action; + auto tabIndex = tabBar->count(); + + actionToTabIndex[action] = tabIndex; + tabIndexToAction[tabIndex] = action; QIcon icon = action->icon(); if (icon.isNull() || itemStyleIndex == 2) { @@ -226,30 +273,35 @@ void WorkbenchTabWidget::addWorkbenchTab(QAction* action) tabBar->setTabToolTip(tabIndex, action->toolTip()); if (action->isChecked()) { - tabBar->setCurrentIndex(tabBar->count() - 1); + tabBar->setCurrentIndex(tabIndex); } } -void WorkbenchTabWidget::updateLayoutAndTabOrientation(bool floating) +void WorkbenchTabWidget::setToolBarArea(Qt::ToolBarArea area) { - if (!parentWidget()->inherits("QToolBar") || floating) { - return; + ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); + + switch (area) { + case Qt::ToolBarArea::LeftToolBarArea: + case Qt::ToolBarArea::RightToolBarArea: + layout->setDirection(QBoxLayout::TopToBottom); + tabBar->setShape(area == Qt::LeftToolBarArea ? QTabBar::RoundedWest : QTabBar::RoundedEast); + hGrp->SetASCII("TabBarOrientation", area == Qt::LeftToolBarArea ? "West" : "East"); + break; + + case Qt::ToolBarArea::TopToolBarArea: + case Qt::ToolBarArea::BottomToolBarArea: + layout->setDirection(QBoxLayout::LeftToRight); + tabBar->setShape(area == Qt::TopToolBarArea ? QTabBar::RoundedNorth : QTabBar::RoundedSouth); + hGrp->SetASCII("TabBarOrientation", area == Qt::TopToolBarArea ? "North" : "South"); + break; + + default: + // no-op + break; } - ParameterGrp::handle hGrp = App::GetApplication() - .GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); - - QToolBar* tb = qobject_cast(parentWidget()); - Qt::ToolBarArea area = getMainWindow()->toolBarArea(tb); - - if (area == Qt::LeftToolBarArea || area == Qt::RightToolBarArea) { - tabBar->setShape(area == Qt::LeftToolBarArea ? QTabBar::RoundedWest : QTabBar::RoundedEast); - hGrp->SetASCII("TabBarOrientation", area == Qt::LeftToolBarArea ? "West" : "East"); - } - else { - tabBar->setShape(area == Qt::TopToolBarArea ? QTabBar::RoundedNorth : QTabBar::RoundedSouth); - hGrp->SetASCII("TabBarOrientation", area == Qt::TopToolBarArea ? "North" : "South"); - } + adjustSize(); } void WorkbenchTabWidget::buildPrefMenu() @@ -277,4 +329,11 @@ void WorkbenchTabWidget::buildPrefMenu() }); } +void WorkbenchTabWidget::adjustSize() +{ + QWidget::adjustSize(); + + parentWidget()->adjustSize(); +} + #include "moc_WorkbenchSelector.cpp" diff --git a/src/Gui/WorkbenchSelector.h b/src/Gui/WorkbenchSelector.h index f29637d6248a6..f45251308253a 100644 --- a/src/Gui/WorkbenchSelector.h +++ b/src/Gui/WorkbenchSelector.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -55,20 +56,31 @@ class GuiExport WorkbenchTabWidget : public QWidget { Q_OBJECT + void addWorkbenchTab(QAction* workbenchActivateAction); + public: explicit WorkbenchTabWidget(WorkbenchGroup* aGroup, QWidget* parent = nullptr); - void updateLayoutAndTabOrientation(bool); + void setToolBarArea(Qt::ToolBarArea area); void buildPrefMenu(); + + void adjustSize(); + public Q_SLOTS: - void refreshList(QList); - void addWorkbenchTab(QAction* workbenchActivateAction); + void handleWorkbenchSelection(QAction* selectedWorkbenchAction); + void handleTabChange(int selectedTabIndex); + + void updateLayout(); + void updateWorkbenchList(); private: + bool isInitializing = false; + WorkbenchGroup* wbActionGroup; QToolButton* moreButton; QTabBar* tabBar; + QBoxLayout* layout; // this action is used for workbenches that are typically disabled QAction* additionalWorkbenchAction = nullptr;