Skip to content

Commit

Permalink
Gui: Adjust sizing of Workbench TabBar when changing orientation
Browse files Browse the repository at this point in the history
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: FreeCAD#13286
  • Loading branch information
kadet1090 committed May 4, 2024
1 parent d51eaed commit b32b232
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 58 deletions.
165 changes: 110 additions & 55 deletions src/Gui/WorkbenchSelector.cpp
Expand Up @@ -32,13 +32,12 @@
# include <QLayout>
#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"


Expand Down Expand Up @@ -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);

Expand All @@ -132,61 +132,103 @@ 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);
tabBar->setUsesScrollButtons(true);
tabBar->setDrawBase(true);
tabBar->setIconSize(QSize(16, 16));

refreshList(aGroup->getEnabledWbActions());
updateWorkbenchList();

Check warning on line 149 in src/Gui/WorkbenchSelector.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

<-- trailing whitespace
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 (additionalWorkbenchAction) {
tabBar->removeTab(tabBar->count() - 1);
}
if (auto toolBar = qobject_cast<QToolBar*>(parent)) {
connect(toolBar, &QToolBar::topLevelChanged, this, &WorkbenchTabWidget::updateLayout);
connect(toolBar, &QToolBar::orientationChanged, this, &WorkbenchTabWidget::updateLayout);
}
}

additionalWorkbenchAction = action;
void WorkbenchTabWidget::updateLayout()

Check warning on line 160 in src/Gui/WorkbenchSelector.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

void WorkbenchTabWidget::updateLayout() <-- trailing whitespace
{
auto toolBar = qobject_cast<QToolBar*>(parentWidget());

addWorkbenchTab(action);
tabBar->setCurrentIndex(tabBar->count() - 1);
// if it's not placed in toolbar it must be placed in menubar so alike top toolbar area
if (!toolBar) {
setToolBarArea(Qt::TopToolBarArea);
return;
}

return;
}
setSizePolicy(toolBar->sizePolicy());
tabBar->setSizePolicy(toolBar->sizePolicy());

tabBar->setCurrentIndex(actionToTabIndex[action]);
});
if (toolBar->isFloating()) {
setToolBarArea(toolBar->orientation() == Qt::Horizontal ? Qt::TopToolBarArea : Qt::LeftToolBarArea);
return;
}

connect(tabBar, qOverload<int>(&QTabBar::currentChanged), aGroup, [this](int index) {
if (tabIndexToAction.find(index) != tabIndexToAction.end()) {
tabIndexToAction[index]->trigger();
setToolBarArea(getMainWindow()->toolBarArea(toolBar));
}

void WorkbenchTabWidget::handleWorkbenchSelection(QAction* selectedWorkbenchAction)

Check warning on line 181 in src/Gui/WorkbenchSelector.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

void WorkbenchTabWidget::handleWorkbenchSelection(QAction* selectedWorkbenchAction) <-- trailing whitespace
{
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<QToolBar*>(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<QAction*> 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

Check warning on line 228 in src/Gui/WorkbenchSelector.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

// This in turn will cause workbench to change, so we need to prevent <-- trailing whitespace
// processing of such events until the QTabBar is fully prepared.
Base::StateLocker lock(isInitializing);

actionToTabIndex.clear();
tabIndexToAction.clear();

Expand All @@ -195,7 +237,7 @@ void WorkbenchTabWidget::refreshList(QList<QAction*> actionList)
tabBar->removeTab(i);
}

for (QAction* action : actionList) {
for (QAction* action : wbActionGroup->getEnabledWbActions()) {
addWorkbenchTab(action);
}

Expand All @@ -204,6 +246,7 @@ void WorkbenchTabWidget::refreshList(QList<QAction*> actionList)
}

buildPrefMenu();
adjustSize();
}

void WorkbenchTabWidget::addWorkbenchTab(QAction* action)
Expand All @@ -214,7 +257,7 @@ void WorkbenchTabWidget::addWorkbenchTab(QAction* action)

auto tabIndex = tabBar->count();

actionToTabIndex[action] = tabBar->count();
actionToTabIndex[action] = tabIndex;
tabIndexToAction[tabIndex] = action;

QIcon icon = action->icon();
Expand All @@ -231,30 +274,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:

Check warning on line 286 in src/Gui/WorkbenchSelector.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

case Qt::ToolBarArea::LeftToolBarArea: <-- trailing whitespace
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<QToolBar*>(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()
Expand Down Expand Up @@ -282,4 +330,11 @@ void WorkbenchTabWidget::buildPrefMenu()
});
}

void WorkbenchTabWidget::adjustSize()
{
QWidget::adjustSize();

parentWidget()->adjustSize();
}

#include "moc_WorkbenchSelector.cpp"

Check failure on line 340 in src/Gui/WorkbenchSelector.cpp

View workflow job for this annotation

GitHub Actions / Lint / Lint

'moc_WorkbenchSelector.cpp' file not found [clang-diagnostic-error]
18 changes: 15 additions & 3 deletions src/Gui/WorkbenchSelector.h
Expand Up @@ -28,6 +28,7 @@
#include <QTabBar>
#include <QMenu>
#include <QToolButton>
#include <QLayout>
#include <FCGlobal.h>
#include <map>

Expand Down Expand Up @@ -55,20 +56,31 @@ class GuiExport WorkbenchTabWidget : public QWidget
{
Q_OBJECT

void addWorkbenchTab(QAction* workbenchActivateAction);

public:
explicit WorkbenchTabWidget(WorkbenchGroup* aGroup, QWidget* parent = nullptr);

Check warning on line 63 in src/Gui/WorkbenchSelector.h

View workflow job for this annotation

GitHub Actions / Lint / Lint

<-- trailing whitespace
void updateLayoutAndTabOrientation(bool);
void setToolBarArea(Qt::ToolBarArea area);
void buildPrefMenu();


void adjustSize();

public Q_SLOTS:
void refreshList(QList<QAction*>);
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;

Expand Down

0 comments on commit b32b232

Please sign in to comment.