Gui: Use RTL layout when Wb Tab Bar is placed in right corner

Right corner is placed to the right edge of screen, so its natural
growth occours on the left side. Basically it is Right to Left order and
so in that case the "end" is actually on left and so TabBar should grow
in that direction.

Unfortunately it is not possible to simply use RTL Qt feature to handle
that case as it would result in reverse order of workbenches (people will still
read it in LTR order) and icons on the right which is not wanted. That's
custom support is introduced.
This commit is contained in:
Kacper Donat
2024-05-05 13:42:37 +02:00
parent 37d6ba2898
commit 82f6b68307
3 changed files with 148 additions and 48 deletions

View File

@@ -632,15 +632,16 @@ void WorkbenchGroup::addTo(QWidget *widget)
if (widget->inherits("QToolBar")) {
ParameterGrp::handle hGrp;
hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches");
QWidget* wbSel;
QWidget* workbenchSelectorWidget;
if (hGrp->GetInt("WorkbenchSelectorType", 0) == 0) {
wbSel = new WorkbenchComboBox(this, widget);
workbenchSelectorWidget = new WorkbenchComboBox(this, widget);
}
else {
wbSel = new WorkbenchTabWidget(this, widget);
workbenchSelectorWidget = new WorkbenchTabWidget(this, widget);
}
static_cast<QToolBar*>(widget)->addWidget(wbSel);
static_cast<QToolBar*>(widget)->addWidget(workbenchSelectorWidget);
}
else if (widget->inherits("QMenu")) {
auto menu = qobject_cast<QMenu*>(widget);

View File

@@ -80,15 +80,17 @@ void WorkbenchComboBox::refreshList(QList<QAction*> actionList)
ParameterGrp::handle hGrp;
hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches");
int itemStyleIndex = hGrp->GetInt("WorkbenchSelectorItem", 0);
auto itemStyle = static_cast<WorkbenchItemStyle>(hGrp->GetInt("WorkbenchSelectorItem", 0));
for (QAction* action : actionList) {
QIcon icon = action->icon();
if (icon.isNull() || itemStyleIndex == 2) {
if (icon.isNull() || itemStyle == WorkbenchItemStyle::TextOnly) {
addItem(action->text());
}
else if (itemStyleIndex == 1) {
addItem(icon, QString::fromLatin1(""));
else if (itemStyle == WorkbenchItemStyle::IconOnly) {
addItem(icon, {}); // empty string to ensure that only icon is displayed
}
else {
addItem(icon, action->text());
@@ -149,7 +151,7 @@ WorkbenchTabWidget::WorkbenchTabWidget(WorkbenchGroup* aGroup, QWidget* parent)
tabBar->setIconSize(QSize(16, 16));
updateWorkbenchList();
connect(aGroup, &WorkbenchGroup::workbenchListRefreshed, this, &WorkbenchTabWidget::updateWorkbenchList);
connect(aGroup->groupAction(), &QActionGroup::triggered, this, &WorkbenchTabWidget::handleWorkbenchSelection);
connect(tabBar, &QTabBar::currentChanged, this, &WorkbenchTabWidget::handleTabChange);
@@ -160,7 +162,54 @@ WorkbenchTabWidget::WorkbenchTabWidget(WorkbenchGroup* aGroup, QWidget* parent)
}
}
void WorkbenchTabWidget::updateLayout()
inline Qt::LayoutDirection WorkbenchTabWidget::direction() const
{
return _direction;
}
void WorkbenchTabWidget::setDirection(Qt::LayoutDirection direction)
{
_direction = direction;
Q_EMIT directionChanged(direction);
}
inline int WorkbenchTabWidget::temporaryWorkbenchTabIndex() const
{
if (direction() == Qt::RightToLeft) {
return 0;
}
int nextTabIndex = tabBar->count();
return temporaryWorkbenchAction ? nextTabIndex - 1 : nextTabIndex;
}
QAction* WorkbenchTabWidget::workbenchActivateActionByTabIndex(int tabIndex) const
{
if (temporaryWorkbenchAction && tabIndex == temporaryWorkbenchTabIndex()) {
return temporaryWorkbenchAction;
}
auto it = tabIndexToAction.find(tabIndex);
if (it != tabIndexToAction.end()) {
return it->second;
}
return nullptr;
}
int WorkbenchTabWidget::tabIndexForWorkbenchActivateAction(QAction* workbenchActivateAction) const
{
if (workbenchActivateAction == temporaryWorkbenchAction) {
return temporaryWorkbenchTabIndex();
}
return actionToTabIndex.at(workbenchActivateAction);
}
void WorkbenchTabWidget::updateLayout()
{
if (!parentWidget()) {
setToolBarArea(Gui::ToolBarArea::TopToolBarArea);
@@ -180,30 +229,47 @@ void WorkbenchTabWidget::updateLayout()
auto toolBarArea = Gui::ToolBarManager::getInstance()->toolBarArea(parentWidget());
setToolBarArea(toolBarArea);
tabBar->setSelectionBehaviorOnRemove(
direction() == Qt::LeftToRight
? QTabBar::SelectLeftTab
: QTabBar::SelectRightTab
);
}
void WorkbenchTabWidget::handleWorkbenchSelection(QAction* selectedWorkbenchAction)
void WorkbenchTabWidget::handleWorkbenchSelection(QAction* selectedWorkbenchAction)
{
if (wbActionGroup->getDisabledWbActions().contains(selectedWorkbenchAction)) {
if (additionalWorkbenchAction == selectedWorkbenchAction) {
if (temporaryWorkbenchAction == selectedWorkbenchAction) {
return;
}
if (additionalWorkbenchAction) {
tabBar->removeTab(tabBar->count() - 1);
}
additionalWorkbenchAction = selectedWorkbenchAction;
addWorkbenchTab(selectedWorkbenchAction);
tabBar->setCurrentIndex(tabBar->count() - 1);
return;
setTemporaryWorkbenchTab(selectedWorkbenchAction);
}
updateLayout();
tabBar->setCurrentIndex(actionToTabIndex[selectedWorkbenchAction]);
tabBar->setCurrentIndex(tabIndexForWorkbenchActivateAction(selectedWorkbenchAction));
}
void WorkbenchTabWidget::setTemporaryWorkbenchTab(QAction* workbenchActivateAction)
{
auto temporaryTabIndex = temporaryWorkbenchTabIndex();
if (temporaryWorkbenchAction) {
temporaryWorkbenchAction = nullptr;
tabBar->removeTab(temporaryTabIndex);
}
temporaryWorkbenchAction = workbenchActivateAction;
if (!workbenchActivateAction) {
return;
}
addWorkbenchTab(workbenchActivateAction, temporaryTabIndex);
adjustSize();
}
void WorkbenchTabWidget::handleTabChange(int selectedTabIndex)
@@ -214,13 +280,12 @@ void WorkbenchTabWidget::handleTabChange(int selectedTabIndex)
return;
}
if (tabIndexToAction.find(selectedTabIndex) != tabIndexToAction.end()) {
tabIndexToAction[selectedTabIndex]->trigger();
if (auto workbenchActivateAction = workbenchActivateActionByTabIndex(selectedTabIndex)) {
workbenchActivateAction->trigger();
}
if (selectedTabIndex != tabBar->count() - 1 && additionalWorkbenchAction) {
tabBar->removeTab(tabBar->count() - 1);
additionalWorkbenchAction = nullptr;
if (selectedTabIndex != temporaryWorkbenchTabIndex()) {
setTemporaryWorkbenchTab(nullptr);
}
adjustSize();
@@ -229,11 +294,12 @@ void WorkbenchTabWidget::handleTabChange(int selectedTabIndex)
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
// 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();
tabIndexToAction.clear();
// tabs->clear() (QTabBar has no clear)
for (int i = tabBar->count() - 1; i >= 0; --i) {
@@ -244,34 +310,39 @@ void WorkbenchTabWidget::updateWorkbenchList()
addWorkbenchTab(action);
}
if (additionalWorkbenchAction != nullptr) {
addWorkbenchTab(additionalWorkbenchAction);
if (temporaryWorkbenchAction != nullptr) {
setTemporaryWorkbenchTab(temporaryWorkbenchAction);
}
buildPrefMenu();
adjustSize();
}
void WorkbenchTabWidget::addWorkbenchTab(QAction* action)
int WorkbenchTabWidget::addWorkbenchTab(QAction* action, int tabIndex)
{
ParameterGrp::handle hGrp;
hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches");
int itemStyleIndex = hGrp->GetInt("WorkbenchSelectorItem", 0);
auto itemStyle = static_cast<WorkbenchItemStyle>(hGrp->GetInt("WorkbenchSelectorItem", 0));
auto tabIndex = tabBar->count();
// if tabIndex is negative we assume that tab must be placed at the end of tabBar (default behavior)
if (tabIndex < 0) {
tabIndex = tabBar->count();
}
actionToTabIndex[action] = tabIndex;
tabIndexToAction[tabIndex] = action;
// for the maps we consider order in which tabs have been added
// that's why here we use tabBar->count() instead of tabIndex
actionToTabIndex[action] = tabBar->count();
tabIndexToAction[tabBar->count()] = action;
QIcon icon = action->icon();
if (icon.isNull() || itemStyleIndex == 2) {
tabBar->addTab(action->text());
if (icon.isNull() || itemStyle == WorkbenchItemStyle::TextOnly) {
tabBar->insertTab(tabIndex, action->text());
}
else if (itemStyleIndex == 1) {
tabBar->addTab(icon, QString::fromLatin1(""));
else if (itemStyle == IconOnly) {
tabBar->insertTab(tabIndex, icon, {}); // empty string to ensure only icon is displayed
}
else {
tabBar->addTab(icon, action->text());
tabBar->insertTab(tabIndex, icon, action->text());
}
tabBar->setTabToolTip(tabIndex, action->toolTip());
@@ -279,6 +350,8 @@ void WorkbenchTabWidget::addWorkbenchTab(QAction* action)
if (action->isChecked()) {
tabBar->setCurrentIndex(tabIndex);
}
return tabIndex;
}
void WorkbenchTabWidget::setToolBarArea(Gui::ToolBarArea area)
@@ -286,9 +359,10 @@ void WorkbenchTabWidget::setToolBarArea(Gui::ToolBarArea area)
ParameterGrp::handle hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches");
switch (area) {
case Gui::ToolBarArea::LeftToolBarArea:
case Gui::ToolBarArea::LeftToolBarArea:
case Gui::ToolBarArea::RightToolBarArea: {
layout->setDirection(QBoxLayout::TopToBottom);
setDirection(Qt::LeftToRight);
layout->setDirection(direction() == Qt::LeftToRight ? QBoxLayout::TopToBottom : QBoxLayout::BottomToTop);
tabBar->setShape(area == Gui::ToolBarArea::LeftToolBarArea ? QTabBar::RoundedWest : QTabBar::RoundedEast);
hGrp->SetASCII("TabBarOrientation", area == Gui::ToolBarArea::LeftToolBarArea ? "West" : "East");
break;
@@ -299,13 +373,17 @@ void WorkbenchTabWidget::setToolBarArea(Gui::ToolBarArea area)
case Gui::ToolBarArea::LeftMenuToolBarArea:
case Gui::ToolBarArea::RightMenuToolBarArea:
case Gui::ToolBarArea::StatusBarToolBarArea: {
layout->setDirection(QBoxLayout::LeftToRight);
bool isTop =
bool isTop =
area == Gui::ToolBarArea::TopToolBarArea ||
area == Gui::ToolBarArea::LeftMenuToolBarArea ||
area == Gui::ToolBarArea::RightMenuToolBarArea;
bool isRightAligned =
area == Gui::ToolBarArea::RightMenuToolBarArea ||
area == Gui::ToolBarArea::StatusBarToolBarArea;
setDirection(isRightAligned ? Qt::RightToLeft : Qt::LeftToRight);
layout->setDirection(direction() == Qt::LeftToRight ? QBoxLayout::LeftToRight : QBoxLayout::RightToLeft);
tabBar->setShape(isTop ? QTabBar::RoundedNorth : QTabBar::RoundedSouth);
hGrp->SetASCII("TabBarOrientation", isTop ? "North" : "South");
break;

View File

@@ -37,6 +37,12 @@ namespace Gui
{
class WorkbenchGroup;
enum WorkbenchItemStyle {
IconAndText = 0,
IconOnly = 1,
TextOnly = 2
};
class GuiExport WorkbenchComboBox : public QComboBox
{
Q_OBJECT
@@ -56,8 +62,15 @@ private:
class GuiExport WorkbenchTabWidget : public QWidget
{
Q_OBJECT
Q_PROPERTY(Qt::LayoutDirection direction READ direction WRITE setDirection NOTIFY directionChanged)
void addWorkbenchTab(QAction* workbenchActivateAction);
int addWorkbenchTab(QAction* workbenchActivateAction, int index = -1);
void setTemporaryWorkbenchTab(QAction* workbenchActivateAction);
int temporaryWorkbenchTabIndex() const;
QAction* workbenchActivateActionByTabIndex(int tabIndex) const;
int tabIndexForWorkbenchActivateAction(QAction* workbenchActivateAction) const;
public:
explicit WorkbenchTabWidget(WorkbenchGroup* aGroup, QWidget* parent = nullptr);
@@ -65,6 +78,8 @@ public:
void setToolBarArea(Gui::ToolBarArea area);
void buildPrefMenu();
Qt::LayoutDirection direction() const;
void setDirection(Qt::LayoutDirection direction);
void adjustSize();
@@ -75,6 +90,9 @@ public Q_SLOTS:
void updateLayout();
void updateWorkbenchList();
Q_SIGNALS:
void directionChanged(const Qt::LayoutDirection&);
private:
bool isInitializing = false;
@@ -82,8 +100,11 @@ private:
QToolButton* moreButton;
QTabBar* tabBar;
QBoxLayout* layout;
Qt::LayoutDirection _direction = Qt::LeftToRight;
// this action is used for workbenches that are typically disabled
QAction* additionalWorkbenchAction = nullptr;
QAction* temporaryWorkbenchAction = nullptr;
std::map<QAction*, int> actionToTabIndex;
std::map<int, QAction*> tabIndexToAction;