diff --git a/src/Gui/Action.cpp b/src/Gui/Action.cpp index d6423d359a..eee53308af 100644 --- a/src/Gui/Action.cpp +++ b/src/Gui/Action.cpp @@ -36,7 +36,6 @@ # include # include # include -# include #endif #include @@ -55,7 +54,6 @@ #include "Macro.h" #include "MainWindow.h" #include "PythonEditor.h" -#include "UserSettings.h" #include "WhatsThis.h" #include "Widgets.h" #include "Workbench.h" @@ -631,7 +629,7 @@ WorkbenchGroup::WorkbenchGroup ( Command* pcCmd, QObject * parent ) void WorkbenchGroup::addTo(QWidget *widget) { - if (widget->inherits("QToolBar") || widget->inherits("QMenuBar")) { + if (widget->inherits("QToolBar")) { ParameterGrp::handle hGrp; hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); QWidget* wbSel; @@ -642,13 +640,7 @@ void WorkbenchGroup::addTo(QWidget *widget) wbSel = new WorkbenchTabWidget(this, widget); } - if (widget->inherits("QToolBar")) { - qobject_cast(widget)->addWidget(wbSel); - } - else { - bool left = WorkbenchSwitcher::isLeftCorner(WorkbenchSwitcher::getValue()); - qobject_cast(widget)->setCornerWidget(wbSel, left ? Qt::TopLeftCorner : Qt::TopRightCorner); - } + static_cast(widget)->addWidget(wbSel); } else if (widget->inherits("QMenu")) { auto menu = qobject_cast(widget); diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index f3da6bc391..cb75c5cc66 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -1217,7 +1217,6 @@ SET(FreeCADGui_CPP_SRCS ManualAlignment.cpp StartupProcess.cpp TransactionObject.cpp - UserSettings.cpp ) SET(FreeCADGui_SRCS Application.h @@ -1255,7 +1254,6 @@ SET(FreeCADGui_SRCS ManualAlignment.h StartupProcess.h TransactionObject.h - UserSettings.h ${FreeCADGui_SDK_MOC_HDRS} ) diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp index ea0693a895..930a1e78c9 100644 --- a/src/Gui/MainWindow.cpp +++ b/src/Gui/MainWindow.cpp @@ -37,6 +37,7 @@ # include # include # include +# include # include # include # include @@ -789,7 +790,19 @@ bool MainWindow::updateDAGView(bool show) QMenu* MainWindow::createPopupMenu () { - QMenu* menu = QMainWindow::createPopupMenu(); + QMenu *menu = new QMenu(this); + populateDockWindowMenu(menu); + menu->addSeparator(); + populateToolBarMenu(menu); + QMenu *undockMenu = new QMenu(menu); + ToolBarManager::getInstance()->populateUndockMenu(undockMenu); + if (undockMenu->actions().isEmpty()) { + delete undockMenu; + } + else { + menu->addMenu(undockMenu); + } + menu->addSeparator(); Workbench* wb = WorkbenchManager::instance()->active(); if (wb) { MenuItem item; @@ -1406,26 +1419,41 @@ void MainWindow::onToolBarMenuAboutToShow() { auto menu = static_cast(sender()); menu->clear(); - QList dock = this->findChildren(); - for (const auto & it : dock) { - if (it->parentWidget() == this) { - QAction* action = it->toggleViewAction(); - action->setToolTip(tr("Toggles this toolbar")); - action->setStatusTip(tr("Toggles this toolbar")); - action->setWhatsThis(tr("Toggles this toolbar")); - menu->addAction(action); - } - } + populateToolBarMenu(menu); menu->addSeparator(); Application::Instance->commandManager().getCommandByName("Std_ToggleToolBarLock")->addTo(menu); } +void MainWindow::populateToolBarMenu(QMenu *menu) +{ + QList toolbars = this->findChildren(); + for (const auto & toolbar : toolbars) { + if (auto parent = toolbar->parentWidget()) { + if (parent == this + || parent == statusBar() + || parent->parentWidget() == statusBar() + || parent->parentWidget() == menuBar()) { + QAction* action = toolbar->toggleViewAction(); + action->setToolTip(tr("Toggles this toolbar")); + action->setStatusTip(tr("Toggles this toolbar")); + action->setWhatsThis(tr("Toggles this toolbar")); + menu->addAction(action); + } + } + } +} + void MainWindow::onDockWindowMenuAboutToShow() { auto menu = static_cast(sender()); menu->clear(); + populateDockWindowMenu(menu); +} + +void MainWindow::populateDockWindowMenu(QMenu *menu) +{ QList dock = this->findChildren(); for (auto & it : dock) { QAction* action = it->toggleViewAction(); diff --git a/src/Gui/MainWindow.h b/src/Gui/MainWindow.h index 299df4d1d7..01098b69b5 100644 --- a/src/Gui/MainWindow.h +++ b/src/Gui/MainWindow.h @@ -308,6 +308,9 @@ private: bool updateComboView(bool show); bool updateDAGView(bool show); + void populateToolBarMenu(QMenu *); + void populateDockWindowMenu(QMenu *); + static void renderDevBuildWarning(QPainter &painter, const QPoint startPosition, const QSize maxSize); private Q_SLOTS: diff --git a/src/Gui/MenuManager.cpp b/src/Gui/MenuManager.cpp index 30c03457de..8606d62002 100644 --- a/src/Gui/MenuManager.cpp +++ b/src/Gui/MenuManager.cpp @@ -31,7 +31,6 @@ #include "Application.h" #include "Command.h" #include "MainWindow.h" -#include "UserSettings.h" using namespace Gui; @@ -288,8 +287,6 @@ void MenuManager::setup(MenuItem* menuItems) const } } - setupMenuBarCornerWidgets(); - // hide all menus which we don't need for the moment for (QList::Iterator it = actions.begin(); it != actions.end(); ++it) { (*it)->setVisible(false); @@ -366,41 +363,6 @@ void MenuManager::setup(MenuItem* item, QMenu* menu) const } } -void MenuManager::setupMenuBarCornerWidgets() const -{ - /*Note: currently only workbench selector uses corner widget.*/ - QMenuBar* menuBar = getMainWindow()->menuBar(); - std::string pos = WorkbenchSwitcher::getValue(); - - bool showLeftWidget = false; - bool showRightWidget = false; - - //Right corner widget - if (WorkbenchSwitcher::isRightCorner(pos)) { - //add workbench selector to menubar right corner widget. - if (!menuBar->cornerWidget(Qt::TopRightCorner)) { - Application::Instance->commandManager().addTo("Std_Workbench", menuBar); - } - showRightWidget = true; - } - //Left corner widget - else if (WorkbenchSwitcher::isLeftCorner(pos)) { - //add workbench selector to menubar left corner widget. - if (!menuBar->cornerWidget(Qt::TopLeftCorner)) { - Application::Instance->commandManager().addTo("Std_Workbench", menuBar); - } - showLeftWidget = true; - } - - // Set visibility of corner widget - if (QWidget* right = menuBar->cornerWidget(Qt::TopRightCorner)) { - right->setVisible(showRightWidget); - } - if (QWidget* left = menuBar->cornerWidget(Qt::TopLeftCorner)) { - left->setVisible(showLeftWidget); - } -} - void MenuManager::retranslate() const { QMenuBar* menuBar = getMainWindow()->menuBar(); diff --git a/src/Gui/MenuManager.h b/src/Gui/MenuManager.h index 736fd08c9f..bf1df584c8 100644 --- a/src/Gui/MenuManager.h +++ b/src/Gui/MenuManager.h @@ -79,7 +79,6 @@ class GuiExport MenuManager public: /** Sets up the menus of a given workbench. */ void setup(MenuItem*) const; - void setupMenuBarCornerWidgets() const; /// sets up a context menu out of item void setupContextMenu(MenuItem* item, QMenu &menu) const; void retranslate() const; diff --git a/src/Gui/PreferencePages/DlgSettingsWorkbenches.ui b/src/Gui/PreferencePages/DlgSettingsWorkbenches.ui index 6bed2929e4..ccce811a87 100644 --- a/src/Gui/PreferencePages/DlgSettingsWorkbenches.ui +++ b/src/Gui/PreferencePages/DlgSettingsWorkbenches.ui @@ -14,6 +14,75 @@ Available Workbenches + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Workbench selector items style: + + + + + + + Customize how the items are displayed. + + + + + + + + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Workbench selector type: + + + + + + + Choose the workbench selector widget type (restart required). + + + + + @@ -37,8 +106,24 @@ Currently, your system has the following workbenches:</p></body>< - - + + + + If checked, application will remember which workbench is active for each tab of the viewport + + + Remember active workbench by tab + + + false + + + SaveWBbyTab + + + View + + @@ -74,142 +159,20 @@ after FreeCAD launches - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Workbench selector type: - - - - - - - Choose the workbench selector widget type (restart required). - - - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Workbench selector position: - - - - - - - Customize where the workbench selector appears (restart required). - -'Toolbar': In the toolbars, as a movable toolbar. -'Left Corner': In the menu bar, on the left corner. -'Right Corner': In the menu bar, on the right corner. - - - - - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Workbench selector items style: - - - - - - - Customize how the items are displayed. - - - - - - - - - If checked, application will remember which workbench is active for each tab of the viewport - - - Remember active workbench by tab - - - false - - - SaveWBbyTab - - - View - - - - - ListWidgetDragBugFix - QListWidget -
ListWidgetDragBugFix.h
-
Gui::PrefCheckBox QCheckBox
Gui/PrefWidgets.h
+ + ListWidgetDragBugFix + QListWidget +
ListWidgetDragBugFix.h
+
diff --git a/src/Gui/PreferencePages/DlgSettingsWorkbenchesImp.cpp b/src/Gui/PreferencePages/DlgSettingsWorkbenchesImp.cpp index 2a873b9c12..bf40384ba5 100644 --- a/src/Gui/PreferencePages/DlgSettingsWorkbenchesImp.cpp +++ b/src/Gui/PreferencePages/DlgSettingsWorkbenchesImp.cpp @@ -33,7 +33,6 @@ #endif #include -#include #include #include @@ -365,9 +364,6 @@ void DlgSettingsWorkbenchesImp::resetSettingsToDefaults() hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow"); hGrp->RemoveASCII("WSPosition"); - if (ui->WorkbenchSelectorPosition->currentIndex() != WorkbenchSwitcher::getIndex()) { - requireRestart(); - } //finally reset all the parameters associated to Gui::Pref* widgets PreferencePage::resetSettingsToDefaults(); @@ -499,19 +495,11 @@ void DlgSettingsWorkbenchesImp::changeEvent(QEvent *e) void DlgSettingsWorkbenchesImp::saveWorkbenchSelector() { - //save workbench selector position - int prevIndex = WorkbenchSwitcher::getIndex(); - auto index = ui->WorkbenchSelectorPosition->currentIndex(); - if (prevIndex != index) { - WorkbenchSwitcher::setIndex(index); - requireRestart(); - } - //save workbench selector type ParameterGrp::handle hGrp; hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); - prevIndex = hGrp->GetInt("WorkbenchSelectorType", 0); - index = ui->WorkbenchSelectorType->currentIndex(); + int prevIndex = hGrp->GetInt("WorkbenchSelectorType", 0); + int index = ui->WorkbenchSelectorType->currentIndex(); if (prevIndex != index) { hGrp->SetInt("WorkbenchSelectorType", index); requireRestart(); @@ -528,13 +516,6 @@ void DlgSettingsWorkbenchesImp::saveWorkbenchSelector() void DlgSettingsWorkbenchesImp::loadWorkbenchSelector() { - //workbench selector position combobox setup - ui->WorkbenchSelectorPosition->clear(); - ui->WorkbenchSelectorPosition->addItem(tr("Toolbar")); - ui->WorkbenchSelectorPosition->addItem(tr("Left corner")); - ui->WorkbenchSelectorPosition->addItem(tr("Right corner")); - ui->WorkbenchSelectorPosition->setCurrentIndex(WorkbenchSwitcher::getIndex()); - //workbench selector type setup ParameterGrp::handle hGrp; hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); diff --git a/src/Gui/ToolBarManager.cpp b/src/Gui/ToolBarManager.cpp index a6e9d561e1..54bb8edb69 100644 --- a/src/Gui/ToolBarManager.cpp +++ b/src/Gui/ToolBarManager.cpp @@ -21,18 +21,29 @@ ***************************************************************************/ #include "PreCompiled.h" +#include "Selection.h" +#include #ifndef _PreComp_ # include # include +# include +# include +# include +# include +# include # include # include -# include #endif +#include + +#include + #include "ToolBarManager.h" #include "Application.h" #include "Command.h" #include "MainWindow.h" +#include "OverlayWidgets.h" using namespace Gui; @@ -154,6 +165,135 @@ QList ToolBarItem::getItems() const // ----------------------------------------------------------- +namespace Gui { + +class ToolBarArea : public QWidget +{ + using inherited = QWidget; +public: + ToolBarArea(QWidget *parent, + ParameterGrp::handle hParam, + boost::signals2::scoped_connection &conn, + QTimer *timer = nullptr) + : QWidget(parent) + , _sizingTimer(timer) + , _hParam(hParam) + , _conn(conn) + { + _layout = new QHBoxLayout(this); + _layout->setMargin(0); + } + + void addWidget(QWidget *w) + { + if (_layout->indexOf(w) < 0) { + _layout->addWidget(w); + adjustParent(); + QString name = w->objectName(); + if (!name.isEmpty()) { + Base::ConnectionBlocker block(_conn); + _hParam->SetInt(w->objectName().toUtf8().constData(), _layout->count()-1); + } + } + } + + void insertWidget(int idx, QWidget *w) + { + int index = _layout->indexOf(w); + if (index == idx) + return; + if (index > 0) + _layout->removeWidget(w); + _layout->insertWidget(idx, w); + adjustParent(); + saveState(); + } + + void adjustParent() + { + if (_sizingTimer) { + _sizingTimer->start(10); + } + } + + void removeWidget(QWidget *w) + { + _layout->removeWidget(w); + QString name = w->objectName(); + if (!name.isEmpty()) { + Base::ConnectionBlocker block(_conn); + _hParam->RemoveInt(name.toUtf8().constData()); + } + adjustParent(); + } + + QWidget *widgetAt(int index) const + { + auto item = _layout->itemAt(index); + return item ? item->widget() : nullptr; + } + + int count() const + { + return _layout->count(); + } + + int indexOf(QWidget *w) const + { + return _layout->indexOf(w); + } + + template + void foreachToolBar(FuncT &&func) + { + for (int i = 0, c = _layout->count(); i < c; ++i) { + auto toolbar = qobject_cast(widgetAt(i)); + if (!toolbar || toolbar->objectName().isEmpty() + || toolbar->objectName().startsWith(QStringLiteral("*"))) + continue; + func(toolbar, i, this); + } + } + + void saveState() + { + Base::ConnectionBlocker block(_conn); + for (auto &v : _hParam->GetIntMap()) { + _hParam->RemoveInt(v.first.c_str()); + } + foreachToolBar([this](QToolBar *toolbar, int idx, ToolBarArea*) { + _hParam->SetInt(toolbar->objectName().toUtf8().constData(), idx); + }); + }; + + void restoreState(const std::map &toolbars) + { + for (const auto &[index, toolbar] : toolbars) { + bool visible = toolbar->isVisible(); + getMainWindow()->removeToolBar(toolbar); + toolbar->setOrientation(Qt::Horizontal); + insertWidget(index, toolbar); + toolbar->setVisible(visible); + } + + for (const auto &[name, visible] : _hParam->GetBoolMap()) { + auto widget = findChild(QString::fromUtf8(name.c_str())); + if (widget) + widget->setVisible(visible); + } + }; + +private: + QHBoxLayout *_layout; + QPointer _sizingTimer; + ParameterGrp::handle _hParam; + boost::signals2::scoped_connection &_conn; +}; + +} // namespace Gui + +// ----------------------------------------------------------- + ToolBarManager* ToolBarManager::_instance=nullptr; ToolBarManager* ToolBarManager::getInstance() @@ -169,7 +309,100 @@ void ToolBarManager::destruct() _instance = nullptr; } -ToolBarManager::ToolBarManager() = default; +ToolBarManager::ToolBarManager() +{ + hGeneral = App::GetApplication().GetUserParameter().GetGroup( + "BaseApp/Preferences/General"); + + hStatusBar = App::GetApplication().GetUserParameter().GetGroup( + "BaseApp/MainWindow/StatusBar"); + + hMenuBarRight = App::GetApplication().GetUserParameter().GetGroup( + "BaseApp/MainWindow/MenuBarRight"); + hMenuBarLeft = App::GetApplication().GetUserParameter().GetGroup( + "BaseApp/MainWindow/MenuBarLeft"); + + hPref = App::GetApplication().GetUserParameter().GetGroup( + "BaseApp/MainWindow/Toolbars"); + + if (auto sb = getMainWindow()->statusBar()) { + sb->installEventFilter(this); + statusBarArea = new ToolBarArea(sb, hStatusBar, connParam); + statusBarArea->setObjectName(QStringLiteral("StatusBarArea")); + sb->insertPermanentWidget(2, statusBarArea); + statusBarArea->show(); + } + + if (auto mb = getMainWindow()->menuBar()) { + mb->installEventFilter(this); + menuBarLeftArea = new ToolBarArea(mb, hMenuBarLeft, connParam, &menuBarTimer); + menuBarLeftArea->setObjectName(QStringLiteral("MenuBarLeftArea")); + mb->setCornerWidget(menuBarLeftArea, Qt::TopLeftCorner); + menuBarLeftArea->show(); + menuBarRightArea = new ToolBarArea(mb, hMenuBarRight, connParam, &menuBarTimer); + menuBarRightArea->setObjectName(QStringLiteral("MenuBarRightArea")); + mb->setCornerWidget(menuBarRightArea, Qt::TopRightCorner); + menuBarRightArea->show(); + } + + sizeTimer.setSingleShot(true); + connect(&sizeTimer, &QTimer::timeout, [this]{ + setupToolBarIconSize(); + }); + + resizeTimer.setSingleShot(true); + connect(&resizeTimer, &QTimer::timeout, [this]{ + for (const auto &[toolbar, guard] : resizingToolbars) { + if (guard) { + setToolBarIconSize(toolbar); + } + } + resizingToolbars.clear(); + }); + + auto refreshParams = [this](const char *name) { + bool sizeChanged = false; + if (!name || boost::equals(name, "ToolbarIconSize")) { + _toolBarIconSize = hGeneral->GetInt("ToolbarIconSize", 24); + sizeChanged = true; + } + if (!name || boost::equals(name, "StatusBarIconSize")) { + _statusBarIconSize = hGeneral->GetInt("StatusBarIconSize", 0); + sizeChanged = true; + } + if (!name || boost::equals(name, "MenuBarIconSize")) { + _menuBarIconSize = hGeneral->GetInt("MenuBarIconSize", 0); + sizeChanged = true; + } + if (sizeChanged) { + sizeTimer.start(100); + } + }; + + refreshParams(nullptr); + connParam = App::GetApplication().GetUserParameter().signalParamChanged.connect( + [this, refreshParams](ParameterGrp *hParam, ParameterGrp::ParamType, const char *name, const char *) { + if (hParam == hGeneral && name) { + refreshParams(name); + } + if (hParam == hPref + || hParam == hStatusBar + || hParam == hMenuBarRight + || hParam == hMenuBarLeft) + timer.start(100); + }); + timer.setSingleShot(true); + connect(&timer, &QTimer::timeout, [this]{ + onTimer(); + }); + + menuBarTimer.setSingleShot(true); + QObject::connect(&menuBarTimer, &QTimer::timeout, [] { + if (auto menuBar = getMainWindow()->menuBar()) { + menuBar->adjustSize(); + } + }); +} ToolBarManager::~ToolBarManager() = default; @@ -199,6 +432,49 @@ QPointer createActionWidget() } } +int ToolBarManager::toolBarIconSize(QWidget *widget) const +{ + int s = _toolBarIconSize; + if (widget) { + if (widget->parentWidget() == statusBarArea) { + if (_statusBarIconSize > 0) + s = _statusBarIconSize; + else + s *= 0.6; + } + else if (widget->parentWidget() == menuBarLeftArea + || widget->parentWidget() == menuBarRightArea) { + if (_menuBarIconSize > 0) + s = _menuBarIconSize; + else + s *= 0.6; + } + } + return std::max(s, 5); +} + +void ToolBarManager::setupToolBarIconSize() +{ + int s = toolBarIconSize(); + getMainWindow()->setIconSize(QSize(s, s)); + // Most of the the toolbar will have explicit icon size, so the above call + // to QMainWindow::setIconSize() will have no effect. We need to explicitly + // change the icon size. + for (auto toolbar : getMainWindow()->findChildren()) { + setToolBarIconSize(toolbar); + } +} + +void ToolBarManager::setToolBarIconSize(QToolBar *toolbar) +{ + int s = toolBarIconSize(toolbar); + toolbar->setIconSize(QSize(s, s)); + if (toolbar->parentWidget() == menuBarLeftArea) + menuBarLeftArea->adjustParent(); + else if (toolbar->parentWidget() == menuBarRightArea) + menuBarRightArea->adjustParent(); +} + void ToolBarManager::setup(ToolBarItem* toolBarItems) { if (!toolBarItems) @@ -212,8 +488,6 @@ void ToolBarManager::setup(ToolBarItem* toolBarItems) int max_width = getMainWindow()->width(); int top_width = 0; - ParameterGrp::handle hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp") - ->GetGroup("MainWindow")->GetGroup("Toolbars"); bool nameAsToolTip = App::GetApplication().GetUserParameter().GetGroup("BaseApp") ->GetGroup("Preferences")->GetGroup("MainWindow")->GetBool("ToolBarNameAsToolTip",true); QList items = toolBarItems->getItems(); @@ -291,7 +565,6 @@ void ToolBarManager::setup(ToolBarItem* toolBarItems) } } } - // hide all unneeded toolbars for (QList::Iterator it = toolbars.begin(); it != toolbars.end(); ++it) { // make sure that the main window has the focus when hiding the toolbar with @@ -313,10 +586,8 @@ void ToolBarManager::setup(ToolBarItem* toolBarItems) (*it)->toggleViewAction()->setVisible(false); } - hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp") - ->GetGroup("Preferences")->GetGroup("General"); - bool lockToolBars = hPref->GetBool("LockToolBars", false); - setMovable(!lockToolBars); + setMovable(!areToolBarsLocked()); + restoreState(); } void ToolBarManager::setup(ToolBarItem* item, QToolBar* toolbar) const @@ -357,6 +628,11 @@ void ToolBarManager::setup(ToolBarItem* item, QToolBar* toolbar) const } } +void ToolBarManager::onTimer() +{ + restoreState(); +} + void ToolBarManager::saveState() const { auto ignoreSave = [](QAction* action) { @@ -377,9 +653,6 @@ void ToolBarManager::saveState() const return value == ToolBarItem::DefaultVisibility::Unavailable; }; - ParameterGrp::handle hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp") - ->GetGroup("MainWindow")->GetGroup("Toolbars"); - QList toolbars = toolBars(); for (QStringList::ConstIterator it = this->toolbarNames.begin(); it != this->toolbarNames.end(); ++it) { QToolBar* toolbar = findToolBar(toolbars, *it); @@ -396,19 +669,326 @@ void ToolBarManager::saveState() const void ToolBarManager::restoreState() const { - ParameterGrp::handle hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp") - ->GetGroup("MainWindow")->GetGroup("Toolbars"); - + std::map sbToolBars; + std::map mbRightToolBars; + std::map mbLeftToolBars; QList toolbars = toolBars(); for (QStringList::ConstIterator it = this->toolbarNames.begin(); it != this->toolbarNames.end(); ++it) { QToolBar* toolbar = findToolBar(toolbars, *it); if (toolbar) { QByteArray toolbarName = toolbar->objectName().toUtf8(); - toolbar->setVisible(hPref->GetBool(toolbarName.constData(), toolbar->isVisible())); + if (getToolbarPolicy(toolbar) != ToolBarItem::DefaultVisibility::Unavailable) { + toolbar->setVisible(hPref->GetBool(toolbarName.constData(), toolbar->isVisible())); + } + + int idx = hStatusBar->GetInt(toolbarName, -1); + if (idx >= 0) { + sbToolBars[idx] = toolbar; + continue; + } + idx = hMenuBarLeft->GetInt(toolbarName, -1); + if (idx >= 0) { + mbLeftToolBars[idx] = toolbar; + continue; + } + idx = hMenuBarRight->GetInt(toolbarName, -1); + if (idx >= 0) { + mbRightToolBars[idx] = toolbar; + continue; + } + if (toolbar->parentWidget() != getMainWindow()) { + getMainWindow()->addToolBar(toolbar); + } } } setMovable(!areToolBarsLocked()); + + statusBarArea->restoreState(sbToolBars); + menuBarRightArea->restoreState(mbRightToolBars); + menuBarLeftArea->restoreState(mbLeftToolBars); +} + +bool ToolBarManager::addToolBarToArea(QObject *source, QMouseEvent *ev) +{ + auto statusBar = getMainWindow()->statusBar(); + if (!statusBar || !statusBar->isVisible()) + statusBar = nullptr; + + auto menuBar = getMainWindow()->menuBar(); + if (!menuBar || !menuBar->isVisible()) { + if (!statusBar) + return false; + menuBar = nullptr; + } + + auto tb = qobject_cast(source); + if (!tb || !tb->isFloating()) + return false; + + static QPointer tbPlaceholder; + static QPointer lastArea; + static int tbIndex = -1; + if (ev->type() == QEvent::MouseMove) { + if (tb->orientation() != Qt::Horizontal + || ev->buttons() != Qt::LeftButton) { + if (tbIndex >= 0) { + if (lastArea) { + lastArea->removeWidget(tbPlaceholder); + lastArea = nullptr; + } + tbPlaceholder->hide(); + tbIndex = -1; + } + return false; + } + } + + if (ev->type() == QEvent::MouseButtonRelease && ev->button() != Qt::LeftButton) + return false; + + QPoint pos = QCursor::pos(); + ToolBarArea *area = nullptr; + if (statusBar) { + QRect rect(statusBar->mapToGlobal(QPoint(0,0)), statusBar->size()); + if (rect.contains(pos)) + area = statusBarArea; + } + if (!area) { + if (!menuBar) { + return false; + } + QRect rect(menuBar->mapToGlobal(QPoint(0,0)), menuBar->size()); + if (rect.contains(pos)) { + if (pos.x() - rect.left() < menuBar->width()/2) { + area = menuBarLeftArea; + } + else { + area = menuBarRightArea; + } + } + else { + if (tbPlaceholder) { + if (lastArea) { + lastArea->removeWidget(tbPlaceholder); + lastArea = nullptr; + } + tbPlaceholder->hide(); + tbIndex = -1; + } + return false; + } + } + + int idx = 0; + for (int c = area->count(); idx < c ;++idx) { + auto w = area->widgetAt(idx); + if (!w || w->isHidden()) + continue; + int p = w->mapToGlobal(w->rect().center()).x(); + if (pos.x() < p) + break; + } + if (tbIndex >= 0 && tbIndex == idx-1) + idx = tbIndex; + if (ev->type() == QEvent::MouseMove) { + if (!tbPlaceholder) { + tbPlaceholder = new OverlayDragFrame(getMainWindow()); + tbPlaceholder->hide(); + tbIndex = -1; + } + if (tbIndex != idx) { + tbIndex = idx; + tbPlaceholder->setSizePolicy(tb->sizePolicy()); + tbPlaceholder->setMinimumWidth(tb->minimumWidth()); + tbPlaceholder->resize(tb->size()); + area->insertWidget(idx, tbPlaceholder); + lastArea = area; + tbPlaceholder->adjustSize(); + tbPlaceholder->show(); + } + } else { + tbIndex = idx; + QTimer::singleShot(10, tb, [tb,this]() { + if (!lastArea) + return; + else { + tbPlaceholder->hide(); + QSignalBlocker block(tb); + lastArea->removeWidget(tbPlaceholder); + getMainWindow()->removeToolBar(tb); + tb->setOrientation(Qt::Horizontal); + lastArea->insertWidget(tbIndex, tb); + tb->setVisible(true); + lastArea = nullptr; + } + tb->topLevelChanged(false); + tbIndex = -1; + }); + } + return false; +} + +void ToolBarManager::populateUndockMenu(QMenu *menu, ToolBarArea *area) +{ + menu->setTitle(tr("Undock toolbars")); + auto tooltip = QObject::tr("Undock from status bar"); + auto addMenuUndockItem = [&](QToolBar *toolbar, int, ToolBarArea *area) { + auto *action = toolbar->toggleViewAction(); + auto undockAction = new QAction(menu); + undockAction->setText(action->text()); + undockAction->setToolTip(tooltip); + menu->addAction(undockAction); + QObject::connect(undockAction, &QAction::triggered, [area, toolbar, this]() { + if (toolbar->parentWidget() == getMainWindow()) { + return; + } + auto pos = toolbar->mapToGlobal(QPoint(0, 0)); + QSignalBlocker blocker(toolbar); + area->removeWidget(toolbar); + getMainWindow()->addToolBar(toolbar); + toolbar->setWindowFlags(Qt::Tool + | Qt::FramelessWindowHint + | Qt::X11BypassWindowManagerHint); + toolbar->move(pos.x(), pos.y()-toolbar->height()-10); + toolbar->adjustSize(); + toolbar->setVisible(true); + toolbar->topLevelChanged(true); + }); + }; + if (area) + area->foreachToolBar(addMenuUndockItem); + else { + statusBarArea->foreachToolBar(addMenuUndockItem); + menuBarLeftArea->foreachToolBar(addMenuUndockItem); + menuBarRightArea->foreachToolBar(addMenuUndockItem); + } +} + +bool ToolBarManager::showContextMenu(QObject *source) +{ + QMenu menu; + QMenu menuUndock; + QHBoxLayout *layout = nullptr; + ToolBarArea *area; + if (getMainWindow()->statusBar() == source) { + area = statusBarArea; + for (auto l : source->findChildren()) { + if(l->indexOf(area) >= 0) { + layout = l; + break; + } + } + } + else if (getMainWindow()->menuBar() == source) { + QPoint pos = QCursor::pos(); + QRect rect(menuBarLeftArea->mapToGlobal(QPoint(0,0)), menuBarLeftArea->size()); + if (rect.contains(pos)) { + area = menuBarLeftArea; + } + else { + rect = QRect(menuBarRightArea->mapToGlobal(QPoint(0,0)), menuBarRightArea->size()); + if (rect.contains(pos)) { + area = menuBarRightArea; + } + else { + return false; + } + } + } + else { + return false; + } + + auto addMenuVisibleItem = [&](QToolBar *toolbar, int, ToolBarArea *) { + auto action = toolbar->toggleViewAction(); + if ((action->isVisible() || toolbar->isVisible()) && action->text().size()) { + action->setVisible(true); + menu.addAction(action); + } + }; + + if (layout) { + for (int i = 0, c = layout->count(); i < c; ++i) { + auto widget = layout->itemAt(i)->widget(); + if (!widget || widget == area + || widget->objectName().isEmpty() + || widget->objectName().startsWith(QStringLiteral("*"))) + { + continue; + } + QString name = widget->windowTitle(); + if (name.isEmpty()) { + name = widget->objectName(); + name.replace(QLatin1Char('_'), QLatin1Char(' ')); + name = name.simplified(); + } + QAction *action = new QAction(&menu); + action->setText(name); + action->setCheckable(true); + action->setChecked(widget->isVisible()); + menu.addAction(action); + + auto onToggle = [widget, this](bool visible) { + onToggleStatusBarWidget(widget, visible); + }; + QObject::connect(action, &QAction::triggered, onToggle); + } + } + + area->foreachToolBar(addMenuVisibleItem); + populateUndockMenu(&menuUndock, area); + + if (menuUndock.actions().size()) { + menu.addSeparator(); + menu.addMenu(&menuUndock); + } + menu.exec(QCursor::pos()); + return true; +} + +void ToolBarManager::onToggleStatusBarWidget(QWidget *widget, bool visible) +{ + Base::ConnectionBlocker block(connParam); + widget->setVisible(visible); + hStatusBar->SetBool(widget->objectName().toUtf8().constData(), widget->isVisible()); +} + +bool ToolBarManager::eventFilter(QObject *source, QEvent *ev) +{ + bool res = false; + switch(ev->type()) { + case QEvent::Show: + case QEvent::Hide: + if (auto toolbar = qobject_cast(source)) { + auto parent = toolbar->parentWidget(); + if (parent == menuBarLeftArea || parent == menuBarRightArea) { + menuBarTimer.start(10); + } + } + break; + case QEvent::MouseButtonRelease: { + auto mev = static_cast(ev); + if (mev->button() == Qt::RightButton) { + if (showContextMenu(source)) { + return true; + } + } + } + // fall through + case QEvent::MouseMove: + res = addToolBarToArea(source, static_cast(ev)); + break; + case QEvent::ParentChange: + if (auto toolbar = qobject_cast(source)) { + resizingToolbars[toolbar] = toolbar; + resizeTimer.start(100); + } + break; + default: + break; + } + return res; } void ToolBarManager::retranslate() const @@ -424,24 +1004,12 @@ void ToolBarManager::retranslate() const bool Gui::ToolBarManager::areToolBarsLocked() const { - auto hPref = App::GetApplication() - .GetUserParameter() - .GetGroup("BaseApp") - ->GetGroup("Preferences") - ->GetGroup("General"); - - return hPref->GetBool("LockToolBars", false); + return hGeneral->GetBool("LockToolBars", false); } void Gui::ToolBarManager::setToolBarsLocked(bool locked) const { - auto hPref = App::GetApplication() - .GetUserParameter() - .GetGroup("BaseApp") - ->GetGroup("Preferences") - ->GetGroup("General"); - - hPref->SetBool("LockToolBars", locked); + hGeneral->SetBool("LockToolBars", locked); setMovable(!locked); } @@ -475,12 +1043,19 @@ QAction* ToolBarManager::findAction(const QList& acts, const QString& QList ToolBarManager::toolBars() const { - QWidget* mw = getMainWindow(); + auto mw = getMainWindow(); QList tb; QList bars = getMainWindow()->findChildren(); for (QList::Iterator it = bars.begin(); it != bars.end(); ++it) { - if ((*it)->parentWidget() == mw) + auto parent = (*it)->parentWidget(); + if (parent == mw + || parent == mw->statusBar() + || parent == statusBarArea + || parent == menuBarLeftArea + || parent == menuBarRightArea) { tb.push_back(*it); + (*it)->installEventFilter(const_cast(this)); + } } return tb; @@ -507,13 +1082,11 @@ void ToolBarManager::setState(const QList& names, State state) void ToolBarManager::setState(const QString& name, State state) { - ParameterGrp::handle hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")->GetGroup("MainWindow")->GetGroup("Toolbars"); - - auto visibility = [hPref, name](bool defaultvalue) { + auto visibility = [this, name](bool defaultvalue) { return hPref->GetBool(name.toStdString().c_str(), defaultvalue); }; - auto saveVisibility = [hPref, name](bool value) { + auto saveVisibility = [this, name](bool value) { hPref->SetBool(name.toStdString().c_str(), value); }; @@ -574,3 +1147,5 @@ void ToolBarManager::setState(const QString& name, State state) } } } + +#include "moc_ToolBarManager.cpp" diff --git a/src/Gui/ToolBarManager.h b/src/Gui/ToolBarManager.h index 86059f08f7..9cf705c7bd 100644 --- a/src/Gui/ToolBarManager.h +++ b/src/Gui/ToolBarManager.h @@ -25,14 +25,23 @@ #define GUI_TOOLBARMANAGER_H #include +#include + #include +#include + #include +#include class QAction; +class QMenu; +class QMouseEvent; class QToolBar; namespace Gui { +class ToolBarArea; + class GuiExport ToolBarItem { public: @@ -83,8 +92,9 @@ private: * @see MenuManager * @author Werner Mayer */ -class GuiExport ToolBarManager +class GuiExport ToolBarManager : public QObject { + Q_OBJECT public: enum class State { @@ -109,6 +119,11 @@ public: void setState(const QList& names, State state); void setState(const QString& name, State state); + int toolBarIconSize(QWidget *widget=nullptr) const; + void setupToolBarIconSize(); + + void populateUndockMenu(QMenu *menu, ToolBarArea *area = nullptr); + protected: void setup(ToolBarItem*, QToolBar*) const; @@ -116,6 +131,14 @@ protected: ToolBarItem::DefaultVisibility getToolbarPolicy(const QToolBar *) const; + bool addToolBarToArea(QObject *source, QMouseEvent *ev); + bool showContextMenu(QObject *source); + void onToggleStatusBarWidget(QWidget *widget, bool visible); + void setToolBarIconSize(QToolBar *toolbar); + void onTimer(); + + bool eventFilter(QObject *source, QEvent *ev) override; + /** Returns a list of all currently existing toolbars. */ QList toolBars() const; QToolBar* findToolBar(const QList&, const QString&) const; @@ -126,6 +149,25 @@ protected: private: QStringList toolbarNames; static ToolBarManager* _instance; + + QTimer timer; + QTimer menuBarTimer; + QTimer sizeTimer; + QTimer resizeTimer; + boost::signals2::scoped_connection connParam; + ToolBarArea *statusBarArea = nullptr; + ToolBarArea *menuBarLeftArea = nullptr; + ToolBarArea *menuBarRightArea = nullptr; + ParameterGrp::handle hGeneral; + ParameterGrp::handle hPref; + ParameterGrp::handle hStatusBar; + ParameterGrp::handle hMenuBarLeft; + ParameterGrp::handle hMenuBarRight; + std::map> resizingToolbars; + int _toolBarIconSize = 0; + int _statusBarIconSize = 0; + int _menuBarIconSize = 0; + mutable bool restored = false; }; } // namespace Gui diff --git a/src/Gui/UserSettings.cpp b/src/Gui/UserSettings.cpp deleted file mode 100644 index beb417d952..0000000000 --- a/src/Gui/UserSettings.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2022 Werner Mayer * - * * - * This file is part of the FreeCAD CAx development system. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Library General Public * - * License as published by the Free Software Foundation; either * - * version 2 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Library General Public License for more details. * - * * - * You should have received a copy of the GNU Library General Public * - * License along with this library; see the file COPYING.LIB. If not, * - * write to the Free Software Foundation, Inc., 59 Temple Place, * - * Suite 330, Boston, MA 02111-1307, USA * - * * - ***************************************************************************/ - -#include "PreCompiled.h" -#ifndef _PreComp_ -#endif - - -#include "UserSettings.h" -#include - - -using namespace Gui; - -namespace { - -ParameterGrp::handle getWSParameter() -{ - return App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/MainWindow"); -} - -} - -std::string WorkbenchSwitcher::getValue() -{ - return getWSParameter()->GetASCII("WSPosition", "WSToolbar"); -} - -bool WorkbenchSwitcher::isLeftCorner(const std::string& value) -{ - return (value == "WSLeftCorner"); -} - -bool WorkbenchSwitcher::isRightCorner(const std::string& value) -{ - return (value == "WSRightCorner"); -} - -bool WorkbenchSwitcher::isToolbar(const std::string& value) -{ - return (value == "WSToolbar"); -} - -QVector WorkbenchSwitcher::values() -{ - QVector wsPositions; - wsPositions << "WSToolbar" << "WSLeftCorner" << "WSRightCorner"; - return wsPositions; -} - -int WorkbenchSwitcher::getIndex() -{ - auto hGrp = getWSParameter(); - std::string pos = hGrp->GetASCII("WSPosition", "WSToolbar"); - auto wsPositions = values(); - int index = std::max(0, static_cast(wsPositions.indexOf(pos))); - return index; -} - -void WorkbenchSwitcher::setIndex(int index) -{ - auto wsPositions = values(); - auto hGrp = getWSParameter(); - if (index >= 0 && index < wsPositions.size()) { - hGrp->SetASCII("WSPosition", wsPositions[index].c_str()); - } -} diff --git a/src/Gui/UserSettings.h b/src/Gui/UserSettings.h deleted file mode 100644 index c116f17e27..0000000000 --- a/src/Gui/UserSettings.h +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************** - * Copyright (c) 2022 Werner Mayer * - * * - * This file is part of the FreeCAD CAx development system. * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Library General Public * - * License as published by the Free Software Foundation; either * - * version 2 of the License, or (at your option) any later version. * - * * - * This library is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU Library General Public License for more details. * - * * - * You should have received a copy of the GNU Library General Public * - * License along with this library; see the file COPYING.LIB. If not, * - * write to the Free Software Foundation, Inc., 59 Temple Place, * - * Suite 330, Boston, MA 02111-1307, USA * - * * - ***************************************************************************/ - -#ifndef GUI_USERSETTINGS_H -#define GUI_USERSETTINGS_H - -#include -#include -#include - -namespace Gui { - -class GuiExport WorkbenchSwitcher -{ -public: - static bool isLeftCorner(const std::string&); - static bool isRightCorner(const std::string&); - static bool isToolbar(const std::string&); - static std::string getValue(); - static int getIndex(); - static void setIndex(int); - -private: - static QVector values(); -}; - -} // namespace Gui - -#endif // GUI_USERSETTINGS_H diff --git a/src/Gui/Workbench.cpp b/src/Gui/Workbench.cpp index e284b42bb7..504ce4a780 100644 --- a/src/Gui/Workbench.cpp +++ b/src/Gui/Workbench.cpp @@ -41,7 +41,6 @@ #include "Selection.h" #include "ToolBarManager.h" #include "ToolBoxManager.h" -#include "UserSettings.h" #include "Window.h" #include @@ -797,11 +796,9 @@ ToolBarItem* StdWorkbench::setupToolBars() const *clipboard << "Std_Cut" << "Std_Copy" << "Std_Paste"; // Workbench switcher - if (WorkbenchSwitcher::isToolbar(WorkbenchSwitcher::getValue())) { - auto wb = new ToolBarItem(root); - wb->setCommand("Workbench"); - *wb << "Std_Workbench"; - } + auto wb = new ToolBarItem(root); + wb->setCommand("Workbench"); + *wb << "Std_Workbench"; // Macro auto macro = new ToolBarItem( root, ToolBarItem::DefaultVisibility::Hidden); diff --git a/src/Gui/WorkbenchSelector.cpp b/src/Gui/WorkbenchSelector.cpp index 68e92a934e..6ef25ce62e 100644 --- a/src/Gui/WorkbenchSelector.cpp +++ b/src/Gui/WorkbenchSelector.cpp @@ -27,7 +27,9 @@ # include # include # include +# include # include +# include # include #endif @@ -208,15 +210,30 @@ void WorkbenchTabWidget::refreshList(QList actionList) void WorkbenchTabWidget::updateLayoutAndTabOrientation(bool floating) { - if (!parentWidget()->inherits("QToolBar") || floating) { + auto parent = parentWidget(); + if (!parent || !parent->inherits("QToolBar")) { return; } ParameterGrp::handle hGrp = App::GetApplication() .GetParameterGroupByPath("User parameter:BaseApp/Preferences/Workbenches"); - QToolBar* tb = qobject_cast(parentWidget()); - Qt::ToolBarArea area = getMainWindow()->toolBarArea(tb); + Qt::ToolBarArea area; + parent = parent->parentWidget(); + + if (floating) { + area = Qt::TopToolBarArea; + } + else if (parent && parent->parentWidget() == getMainWindow()->statusBar()) { + area = Qt::BottomToolBarArea; + } + else if (parent && parent->parentWidget() == getMainWindow()->menuBar()) { + area = Qt::TopToolBarArea; + } + else { + QToolBar* tb = qobject_cast(parentWidget()); + area = getMainWindow()->toolBarArea(tb); + } if (area == Qt::LeftToolBarArea || area == Qt::RightToolBarArea) { setShape(area == Qt::LeftToolBarArea ? QTabBar::RoundedWest : QTabBar::RoundedEast); diff --git a/src/Mod/Tux/PersistentToolbarsGui.py b/src/Mod/Tux/PersistentToolbarsGui.py index 781766d3ba..64a0693ca0 100644 --- a/src/Mod/Tux/PersistentToolbarsGui.py +++ b/src/Mod/Tux/PersistentToolbarsGui.py @@ -66,7 +66,7 @@ def onRestore(active): isConnected(i) - if i.objectName() and not i.isFloating(): + if i.objectName() and i.parentWidget() == mw and not i.isFloating(): toolbars[i.objectName()] = i else: pass