diff --git a/src/Gui/Application.cpp b/src/Gui/Application.cpp
index f58c18072e..0e62bc16d1 100644
--- a/src/Gui/Application.cpp
+++ b/src/Gui/Application.cpp
@@ -2082,6 +2082,13 @@ void Application::runApplication()
<< QString::fromUtf8((App::Application::getResourceDir() + "Gui/Stylesheets/").c_str())
<< QLatin1String(":/stylesheets");
QDir::setSearchPaths(QString::fromLatin1("qss"), qssPaths);
+ // setup the search paths for Qt overlay style sheets
+ QStringList qssOverlayPaths;
+ qssOverlayPaths << QString::fromUtf8((App::Application::getUserAppDataDir()
+ + "Gui/Stylesheets/overlay").c_str())
+ << QString::fromUtf8((App::Application::getResourceDir()
+ + "Gui/Stylesheets/overlay").c_str());
+ QDir::setSearchPaths(QStringLiteral("overlay"), qssOverlayPaths);
// set search paths for images
QStringList imagePaths;
diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt
index 811bb10ab9..7d62108de2 100644
--- a/src/Gui/CMakeLists.txt
+++ b/src/Gui/CMakeLists.txt
@@ -1066,10 +1066,12 @@ SOURCE_GROUP("Widget" FILES ${Widget_SRCS})
SET(Params_CPP_SRCS
TreeParams.cpp
+ OverlayParams.cpp
)
SET(Params_HPP_SRCS
TreeParams.h
+ OverlayParams.h
)
SET(Params_SRCS
@@ -1103,6 +1105,8 @@ SOURCE_GROUP("View" FILES ${View_SRCS})
# The workbench sources
SET(Workbench_CPP_SRCS
DockWindowManager.cpp
+ OverlayManager.cpp
+ OverlayWidgets.cpp
MenuManager.cpp
PythonWorkbenchPyImp.cpp
ToolBarManager.cpp
@@ -1116,6 +1120,8 @@ SET(Workbench_CPP_SRCS
SET(Workbench_SRCS
${Workbench_CPP_SRCS}
DockWindowManager.h
+ OverlayManager.h
+ OverlayWidgets.h
MenuManager.h
ToolBarManager.h
ToolBoxManager.h
diff --git a/src/Gui/ComboView.h b/src/Gui/ComboView.h
index 0aac485b05..b63e2cf856 100644
--- a/src/Gui/ComboView.h
+++ b/src/Gui/ComboView.h
@@ -23,6 +23,7 @@
#ifndef GUI_DOCKWND_COMBOVIEW_H
#define GUI_DOCKWND_COMBOVIEW_H
+#include
#include "DockWindow.h"
@@ -70,6 +71,8 @@ public:
*/
ComboView(Gui::Document* pcDocument, QWidget *parent=nullptr);
+ void setShowModel(bool);
+
/**
* A destructor.
* A more elaborate description of the destructor.
diff --git a/src/Gui/CommandView.cpp b/src/Gui/CommandView.cpp
index bf648a4ce8..d691a433b7 100644
--- a/src/Gui/CommandView.cpp
+++ b/src/Gui/CommandView.cpp
@@ -67,6 +67,8 @@
#include "Macro.h"
#include "MainWindow.h"
#include "NavigationStyle.h"
+#include "OverlayParams.h"
+#include "OverlayManager.h"
#include "SceneInspector.h"
#include "Selection.h"
#include "SelectionObject.h"
@@ -3715,6 +3717,279 @@ Action * StdCmdSelBoundingBox::createAction()
return pcAction;
}
+//===========================================================================
+// Std_DockOverlayAll
+//===========================================================================
+
+DEF_STD_CMD(StdCmdDockOverlayAll)
+
+StdCmdDockOverlayAll::StdCmdDockOverlayAll()
+ :Command("Std_DockOverlayAll")
+{
+ sGroup = "View";
+ sMenuText = QT_TR_NOOP("Toggle overlay for all");
+ sToolTipText = QT_TR_NOOP("Toggle overlay mode for all docked windows");
+ sWhatsThis = "Std_DockOverlayAll";
+ sStatusTip = sToolTipText;
+ sAccel = "F4";
+ eType = 0;
+}
+
+void StdCmdDockOverlayAll::activated(int iMsg)
+{
+ Q_UNUSED(iMsg);
+ OverlayManager::instance()->setOverlayMode(OverlayManager::OverlayMode::ToggleAll);
+}
+
+//===========================================================================
+// Std_DockOverlayTransparentAll
+//===========================================================================
+
+DEF_STD_CMD(StdCmdDockOverlayTransparentAll)
+
+StdCmdDockOverlayTransparentAll::StdCmdDockOverlayTransparentAll()
+ :Command("Std_DockOverlayTransparentAll")
+{
+ sGroup = "View";
+ sMenuText = QT_TR_NOOP("Toggle transparent for all");
+ sToolTipText = QT_TR_NOOP("Toggle transparent for all overlay docked window.\n"
+ "This makes the docked widget stay transparent at all times.");
+ sWhatsThis = "Std_DockOverlayTransparentAll";
+ sStatusTip = sToolTipText;
+ sAccel = "SHIFT+F4";
+ eType = 0;
+}
+
+void StdCmdDockOverlayTransparentAll::activated(int iMsg)
+{
+ Q_UNUSED(iMsg);
+ OverlayManager::instance()->setOverlayMode(OverlayManager::OverlayMode::ToggleTransparentAll);
+}
+
+//===========================================================================
+// Std_DockOverlayToggle
+//===========================================================================
+
+DEF_STD_CMD(StdCmdDockOverlayToggle)
+
+StdCmdDockOverlayToggle::StdCmdDockOverlayToggle()
+ :Command("Std_DockOverlayToggle")
+{
+ sGroup = "View";
+ sMenuText = QT_TR_NOOP("Toggle overlay");
+ sToolTipText = QT_TR_NOOP("Toggle overlay mode of the docked window under cursor");
+ sWhatsThis = "Std_DockOverlayToggle";
+ sStatusTip = sToolTipText;
+ sAccel = "F3";
+ eType = 0;
+}
+
+void StdCmdDockOverlayToggle::activated(int iMsg)
+{
+ Q_UNUSED(iMsg);
+ OverlayManager::instance()->setOverlayMode(OverlayManager::OverlayMode::ToggleActive);
+}
+
+//===========================================================================
+// Std_DockOverlayToggleTransparent
+//===========================================================================
+
+DEF_STD_CMD(StdCmdDockOverlayToggleTransparent)
+
+StdCmdDockOverlayToggleTransparent::StdCmdDockOverlayToggleTransparent()
+ :Command("Std_DockOverlayToggleTransparent")
+{
+ sGroup = "Standard-View";
+ sMenuText = QT_TR_NOOP("Toggle transparent");
+ sToolTipText = QT_TR_NOOP("Toggle transparent mode for the docked widget under cursor.\n"
+ "This makes the docked widget stay transparent at all times.");
+ sWhatsThis = "Std_DockOverlayToggleTransparent";
+ sStatusTip = sToolTipText;
+ sAccel = "SHIFT+F3";
+ eType = 0;
+}
+
+void StdCmdDockOverlayToggleTransparent::activated(int iMsg)
+{
+ Q_UNUSED(iMsg);
+ OverlayManager::instance()->setOverlayMode(OverlayManager::OverlayMode::ToggleTransparent);
+}
+
+//===========================================================================
+// Std_DockOverlayToggleLeft
+//===========================================================================
+
+DEF_STD_CMD(StdCmdDockOverlayToggleLeft)
+
+StdCmdDockOverlayToggleLeft::StdCmdDockOverlayToggleLeft()
+ :Command("Std_DockOverlayToggleLeft")
+{
+ sGroup = "Standard-View";
+ sMenuText = QT_TR_NOOP("Toggle left");
+ sToolTipText = QT_TR_NOOP("Show/hide left overlay panel");
+ sWhatsThis = "Std_DockOverlayToggleLeft";
+ sStatusTip = sToolTipText;
+ sAccel = "SHIFT+Left";
+ sPixmap = "qss:overlay/close.svg";
+ eType = 0;
+}
+
+void StdCmdDockOverlayToggleLeft::activated(int iMsg)
+{
+ Q_UNUSED(iMsg);
+ OverlayManager::instance()->setOverlayMode(OverlayManager::OverlayMode::ToggleLeft);
+}
+
+//===========================================================================
+// Std_DockOverlayToggleRight
+//===========================================================================
+
+DEF_STD_CMD(StdCmdDockOverlayToggleRight)
+
+StdCmdDockOverlayToggleRight::StdCmdDockOverlayToggleRight()
+ :Command("Std_DockOverlayToggleRight")
+{
+ sGroup = "Standard-View";
+ sMenuText = QT_TR_NOOP("Toggle right");
+ sToolTipText = QT_TR_NOOP("Show/hide right overlay panel");
+ sWhatsThis = "Std_DockOverlayToggleRight";
+ sStatusTip = sToolTipText;
+ sAccel = "SHIFT+Right";
+ sPixmap = "qss:overlay/close.svg";
+ eType = 0;
+}
+
+void StdCmdDockOverlayToggleRight::activated(int iMsg)
+{
+ Q_UNUSED(iMsg);
+ OverlayManager::instance()->setOverlayMode(OverlayManager::OverlayMode::ToggleRight);
+}
+
+//===========================================================================
+// Std_DockOverlayToggleTop
+//===========================================================================
+
+DEF_STD_CMD(StdCmdDockOverlayToggleTop)
+
+StdCmdDockOverlayToggleTop::StdCmdDockOverlayToggleTop()
+ :Command("Std_DockOverlayToggleTop")
+{
+ sGroup = "Standard-View";
+ sMenuText = QT_TR_NOOP("Toggle top");
+ sToolTipText = QT_TR_NOOP("Show/hide top overlay panel");
+ sWhatsThis = "Std_DockOverlayToggleTop";
+ sStatusTip = sToolTipText;
+ sAccel = "SHIFT+Up";
+ sPixmap = "qss:overlay/close.svg";
+ eType = 0;
+}
+
+void StdCmdDockOverlayToggleTop::activated(int iMsg)
+{
+ Q_UNUSED(iMsg);
+ OverlayManager::instance()->setOverlayMode(OverlayManager::OverlayMode::ToggleTop);
+}
+
+//===========================================================================
+// Std_DockOverlayToggleBottom
+//===========================================================================
+
+DEF_STD_CMD(StdCmdDockOverlayToggleBottom)
+
+StdCmdDockOverlayToggleBottom::StdCmdDockOverlayToggleBottom()
+ :Command("Std_DockOverlayToggleBottom")
+{
+ sGroup = "Standard-View";
+ sMenuText = QT_TR_NOOP("Toggle bottom");
+ sToolTipText = QT_TR_NOOP("Show/hide bottom overlay panel");
+ sWhatsThis = "Std_DockOverlayToggleBottom";
+ sStatusTip = sToolTipText;
+ sAccel = "SHIFT+Down";
+ sPixmap = "qss:overlay/close.svg";
+ eType = 0;
+}
+
+void StdCmdDockOverlayToggleBottom::activated(int iMsg)
+{
+ Q_UNUSED(iMsg);
+ OverlayManager::instance()->setOverlayMode(OverlayManager::OverlayMode::ToggleBottom);
+}
+
+//===========================================================================
+// Std_DockOverlayMouseTransparent
+//===========================================================================
+
+DEF_STD_CMD_AC(StdCmdDockOverlayMouseTransparent)
+
+StdCmdDockOverlayMouseTransparent::StdCmdDockOverlayMouseTransparent()
+ :Command("Std_DockOverlayMouseTransparent")
+{
+ sGroup = "View";
+ sMenuText = QT_TR_NOOP("Bypass mouse events in dock overlay");
+ sToolTipText = QT_TR_NOOP("Bypass all mouse events in dock overlay");
+ sWhatsThis = "Std_DockOverlayMouseTransparent";
+ sStatusTip = sToolTipText;
+ sAccel = "T, T";
+ eType = NoTransaction;
+}
+
+void StdCmdDockOverlayMouseTransparent::activated(int iMsg)
+{
+ (void)iMsg;
+ bool checked = !OverlayManager::instance()->isMouseTransparent();
+ OverlayManager::instance()->setMouseTransparent(checked);
+ if(_pcAction)
+ _pcAction->setChecked(checked,true);
+}
+
+Action * StdCmdDockOverlayMouseTransparent::createAction(void) {
+ Action *pcAction = Command::createAction();
+ pcAction->setCheckable(true);
+ pcAction->setIcon(QIcon());
+ _pcAction = pcAction;
+ isActive();
+ return pcAction;
+}
+
+bool StdCmdDockOverlayMouseTransparent::isActive() {
+ bool checked = OverlayManager::instance()->isMouseTransparent();
+ if(_pcAction && _pcAction->isChecked()!=checked)
+ _pcAction->setChecked(checked,true);
+ return true;
+}
+
+// ============================================================================
+
+class StdCmdDockOverlay : public GroupCommand
+{
+public:
+ StdCmdDockOverlay()
+ :GroupCommand("Std_DockOverlay")
+ {
+ sGroup = "View";
+ sMenuText = QT_TR_NOOP("Dock window overlay");
+ sToolTipText = QT_TR_NOOP("Setting docked window overlay mode");
+ sWhatsThis = "Std_DockOverlay";
+ sStatusTip = sToolTipText;
+ eType = 0;
+ bCanLog = false;
+
+ addCommand(new StdCmdDockOverlayAll());
+ addCommand(new StdCmdDockOverlayTransparentAll());
+ addCommand();
+ addCommand(new StdCmdDockOverlayToggle());
+ addCommand(new StdCmdDockOverlayToggleTransparent());
+ addCommand();
+ addCommand(new StdCmdDockOverlayMouseTransparent());
+ addCommand();
+ addCommand(new StdCmdDockOverlayToggleLeft());
+ addCommand(new StdCmdDockOverlayToggleRight());
+ addCommand(new StdCmdDockOverlayToggleTop());
+ addCommand(new StdCmdDockOverlayToggleBottom());
+ };
+ virtual const char* className() const {return "StdCmdDockOverlay";}
+};
+
//===========================================================================
// Std_StoreWorkingView
//===========================================================================
@@ -3859,6 +4134,7 @@ void CreateViewStdCommands()
rcCmdMgr.addCommand(new CmdViewMeasureToggleAll());
rcCmdMgr.addCommand(new StdCmdSelBoundingBox());
rcCmdMgr.addCommand(new StdCmdTreeViewActions());
+ rcCmdMgr.addCommand(new StdCmdDockOverlay());
auto hGrp = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
if(hGrp->GetASCII("GestureRollFwdCommand").empty())
diff --git a/src/Gui/DockWindowManager.cpp b/src/Gui/DockWindowManager.cpp
index cf1b6a1f5c..bf94522cb1 100644
--- a/src/Gui/DockWindowManager.cpp
+++ b/src/Gui/DockWindowManager.cpp
@@ -25,15 +25,23 @@
#ifndef _PreComp_
# include
# include
+# include
# include
# include
+# include
# include
+# include
#endif
+#include
+
#include
+#include
+#include
#include "DockWindowManager.h"
#include "MainWindow.h"
+#include "OverlayManager.h"
using namespace Gui;
@@ -45,7 +53,7 @@ DockWindowItems::~DockWindowItems() = default;
void DockWindowItems::addDockWidget(const char* name, Qt::DockWidgetArea pos, bool visibility, bool tabbed)
{
DockWindowItem item;
- item.name = QString::fromLatin1(name);
+ item.name = QString::fromUtf8(name);
item.pos = pos;
item.visibility = visibility;
item.tabbed = tabbed;
@@ -55,7 +63,7 @@ void DockWindowItems::addDockWidget(const char* name, Qt::DockWidgetArea pos, bo
void DockWindowItems::setDockingArea(const char* name, Qt::DockWidgetArea pos)
{
for (QList::iterator it = _items.begin(); it != _items.end(); ++it) {
- if (it->name == QLatin1String(name)) {
+ if (it->name == QString::fromUtf8(name)) {
it->pos = pos;
break;
}
@@ -65,7 +73,7 @@ void DockWindowItems::setDockingArea(const char* name, Qt::DockWidgetArea pos)
void DockWindowItems::setVisibility(const char* name, bool v)
{
for (QList::iterator it = _items.begin(); it != _items.end(); ++it) {
- if (it->name == QLatin1String(name)) {
+ if (it->name == QString::fromUtf8(name)) {
it->visibility = v;
break;
}
@@ -87,11 +95,66 @@ const QList& DockWindowItems::dockWidgets() const
// -----------------------------------------------------------
namespace Gui {
+
+class DockWidgetEventFilter: public QObject {
+public:
+ bool eventFilter(QObject *o, QEvent *e) {
+ if (!o->isWidgetType() || e->type() != QEvent::MouseMove)
+ return false;
+ auto widget = qobject_cast(o);
+ if (!widget || !widget->isFloating()) {
+ if (overridden) {
+ overridden = false;
+ QApplication::restoreOverrideCursor();
+ }
+ return false;
+ }
+ if (static_cast(e)->buttons() != Qt::NoButton)
+ return false;
+ auto pos = QCursor::pos();
+ QPoint topLeft = widget->mapToGlobal(QPoint(cursorMargin, cursorMargin));
+ int h = widget->frameGeometry().height();
+ int w = widget->frameGeometry().width();
+ QPoint bottomRight = widget->mapToGlobal(QPoint(w-cursorMargin, h-cursorMargin));
+ bool left = QRect(topLeft - QPoint(cursorMargin,cursorMargin), QSize(cursorMargin, h)).contains(pos);
+ bool right = QRect(bottomRight.x(), topLeft.y(), cursorMargin, h).contains(pos);
+ bool bottom = QRect(topLeft.x()-cursorMargin, bottomRight.y(), w, cursorMargin).contains(pos);
+ auto cursor = Qt::ArrowCursor;
+ if (left && bottom)
+ cursor = Qt::SizeBDiagCursor;
+ else if (right && bottom)
+ cursor = Qt::SizeFDiagCursor;
+ else if (bottom)
+ cursor = Qt::SizeVerCursor;
+ else if (left || right)
+ cursor = Qt::SizeHorCursor;
+ else if (overridden) {
+ overridden = false;
+ QApplication::restoreOverrideCursor();
+ return false;
+ }
+ if (overridden)
+ QApplication::changeOverrideCursor(cursor);
+ else {
+ overridden = true;
+ QApplication::setOverrideCursor(cursor);
+ }
+ return false;
+ }
+
+ bool overridden = false;
+ int cursorMargin = 5;
+};
+
struct DockWindowManagerP
{
QList _dockedWindows;
QMap > _dockWindows;
DockWindowItems _dockWindowItems;
+ ParameterGrp::handle _hPref;
+ boost::signals2::scoped_connection _connParam;
+ QTimer _timer;
+ DockWidgetEventFilter _dockWidgetEventFilter;
};
} // namespace Gui
@@ -113,6 +176,39 @@ void DockWindowManager::destruct()
DockWindowManager::DockWindowManager()
{
d = new DockWindowManagerP;
+ qApp->installEventFilter(&d->_dockWidgetEventFilter);
+ d->_hPref = App::GetApplication().GetUserParameter().GetGroup(
+ "BaseApp/MainWindow/DockWindows");
+ d->_dockWidgetEventFilter.cursorMargin = d->_hPref->GetInt("CursorMargin", 5);
+ d->_connParam = d->_hPref->Manager()->signalParamChanged.connect(
+ [this](ParameterGrp *Param, ParameterGrp::ParamType Type, const char *name, const char *) {
+ if(Param == d->_hPref) {
+ switch(Type) {
+ case ParameterGrp::ParamType::FCBool:
+ // For batch process UI setting changes, e.g. loading new preferences
+ d->_timer.start(100);
+ break;
+ case ParameterGrp::ParamType::FCInt:
+ if (name && boost::equals(name, "CursorMargin"))
+ d->_dockWidgetEventFilter.cursorMargin = d->_hPref->GetInt("CursorMargin", 5);
+ break;
+ default:
+ break;
+ }
+ }
+ });
+
+ d->_timer.setSingleShot(true);
+
+ connect(&d->_timer, &QTimer::timeout, [this](){
+ for(auto w : this->getDockWindows()) {
+ if (auto dw = qobject_cast(w)) {
+ QSignalBlocker blocker(dw);
+ QByteArray dockName = dw->toggleViewAction()->data().toByteArray();
+ dw->setVisible(d->_hPref->GetBool(dockName, dw->isVisible()));
+ }
+ }
+ });
}
DockWindowManager::~DockWindowManager()
@@ -126,9 +222,17 @@ DockWindowManager::~DockWindowManager()
*/
QDockWidget* DockWindowManager::addDockWindow(const char* name, QWidget* widget, Qt::DockWidgetArea pos)
{
+ if(!widget)
+ return nullptr;
+ QDockWidget *dw = qobject_cast(widget->parentWidget());
+ if(dw)
+ return dw;
+
// creates the dock widget as container to embed this widget
MainWindow* mw = getMainWindow();
- auto dw = new QDockWidget(mw);
+ dw = new QDockWidget(mw);
+ OverlayManager::instance()->setupTitleBar(dw);
+
// Note: By default all dock widgets are hidden but the user can show them manually in the view menu.
// First, hide immediately the dock widget to avoid flickering, after setting up the dock widgets
// MainWindow::loadLayoutSettings() is called to restore the layout.
@@ -152,13 +256,28 @@ QDockWidget* DockWindowManager::addDockWindow(const char* name, QWidget* widget,
dw->setWidget(widget);
// set object name and window title needed for i18n stuff
- dw->setObjectName(QLatin1String(name));
- dw->setWindowTitle(QDockWidget::tr(name));
+ dw->setObjectName(QString::fromUtf8(name));
+ QString title = widget->windowTitle();
+ if (title.isEmpty())
+ title = QDockWidget::tr(name);
+ dw->setWindowTitle(title);
dw->setFeatures(QDockWidget::DockWidgetClosable
| QDockWidget::DockWidgetMovable
| QDockWidget::DockWidgetFloatable);
d->_dockedWindows.push_back(dw);
+
+ OverlayManager::instance()->initDockWidget(dw);
+
+ connect(dw->toggleViewAction(), &QAction::triggered, [this, dw](){
+ Base::ConnectionBlocker block(d->_connParam);
+ QByteArray dockName = dw->toggleViewAction()->data().toByteArray();
+ d->_hPref->SetBool(dockName.constData(), dw->isVisible());
+ });
+
+ auto cb = []() {getMainWindow()->saveWindowSettings(true);};
+ connect(dw, &QDockWidget::topLevelChanged, cb);
+ connect(dw, &QDockWidget::dockLocationChanged, cb);
return dw;
}
@@ -169,7 +288,7 @@ QDockWidget* DockWindowManager::addDockWindow(const char* name, QWidget* widget,
QWidget* DockWindowManager::getDockWindow(const char* name) const
{
for (QList::Iterator it = d->_dockedWindows.begin(); it != d->_dockedWindows.end(); ++it) {
- if ((*it)->objectName() == QLatin1String(name))
+ if ((*it)->objectName() == QString::fromUtf8(name))
return (*it)->widget();
}
@@ -208,9 +327,10 @@ QWidget* DockWindowManager::removeDockWindow(const char* name)
{
QWidget* widget=nullptr;
for (QList::Iterator it = d->_dockedWindows.begin(); it != d->_dockedWindows.end(); ++it) {
- if ((*it)->objectName() == QLatin1String(name)) {
+ if ((*it)->objectName() == QString::fromUtf8(name)) {
QDockWidget* dw = *it;
d->_dockedWindows.erase(it);
+ OverlayManager::instance()->unsetupDockWidget(dw);
getMainWindow()->removeDockWidget(dw);
// avoid to destruct the embedded widget
widget = dw->widget();
@@ -234,10 +354,13 @@ QWidget* DockWindowManager::removeDockWindow(const char* name)
*/
void DockWindowManager::removeDockWindow(QWidget* widget)
{
+ if (!widget)
+ return;
for (QList::Iterator it = d->_dockedWindows.begin(); it != d->_dockedWindows.end(); ++it) {
if ((*it)->widget() == widget) {
QDockWidget* dw = *it;
d->_dockedWindows.erase(it);
+ OverlayManager::instance()->unsetupDockWidget(dw);
getMainWindow()->removeDockWidget(dw);
// avoid to destruct the embedded widget
widget->setParent(nullptr);
@@ -283,7 +406,11 @@ void DockWindowManager::activate(QWidget* widget)
void DockWindowManager::retranslate()
{
for (QList::Iterator it = d->_dockedWindows.begin(); it != d->_dockedWindows.end(); ++it) {
- (*it)->setWindowTitle(QDockWidget::tr((*it)->objectName().toLatin1()));
+ QString title = (*it)->windowTitle();
+ if (title.isEmpty())
+ (*it)->setWindowTitle(QDockWidget::tr((*it)->objectName().toUtf8()));
+ else
+ (*it)->setWindowTitle(title);
}
}
@@ -308,10 +435,10 @@ void DockWindowManager::retranslate()
*/
bool DockWindowManager::registerDockWindow(const char* name, QWidget* widget)
{
- QMap >::Iterator it = d->_dockWindows.find(QLatin1String(name));
+ QMap >::Iterator it = d->_dockWindows.find(QString::fromUtf8(name));
if (it != d->_dockWindows.end() || !widget)
return false;
- d->_dockWindows[QLatin1String(name)] = widget;
+ d->_dockWindows[QString::fromUtf8(name)] = widget;
widget->hide(); // hide the widget if not used
return true;
}
@@ -319,14 +446,22 @@ bool DockWindowManager::registerDockWindow(const char* name, QWidget* widget)
QWidget* DockWindowManager::unregisterDockWindow(const char* name)
{
QWidget* widget = nullptr;
- QMap >::Iterator it = d->_dockWindows.find(QLatin1String(name));
+ QMap >::Iterator it = d->_dockWindows.find(QString::fromUtf8(name));
if (it != d->_dockWindows.end()) {
- widget = d->_dockWindows.take(QLatin1String(name));
+ widget = d->_dockWindows.take(QString::fromUtf8(name));
}
return widget;
}
+QWidget* DockWindowManager::findRegisteredDockWindow(const char* name)
+{
+ QMap >::Iterator it = d->_dockWindows.find(QString::fromUtf8(name));
+ if (it != d->_dockWindows.end())
+ return it.value();
+ return nullptr;
+}
+
/** Sets up the dock windows of the activated workbench. */
void DockWindowManager::setup(DockWindowItems* items)
{
@@ -334,14 +469,12 @@ void DockWindowManager::setup(DockWindowItems* items)
saveState();
d->_dockWindowItems = *items;
- ParameterGrp::handle hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
- ->GetGroup("MainWindow")->GetGroup("DockWindows");
QList docked = d->_dockedWindows;
const QList& dws = items->dockWidgets();
for (const auto& it : dws) {
QDockWidget* dw = findDockWidget(docked, it.name);
QByteArray dockName = it.name.toLatin1();
- bool visible = hPref->GetBool(dockName.constData(), it.visibility);
+ bool visible = d->_hPref->GetBool(dockName.constData(), it.visibility);
if (!dw) {
QMap >::Iterator jt = d->_dockWindows.find(it.name);
@@ -358,6 +491,9 @@ void DockWindowManager::setup(DockWindowItems* items)
int index = docked.indexOf(dw);
docked.removeAt(index);
}
+
+ if(dw && visible)
+ OverlayManager::instance()->setupDockWidget(dw);
}
tabifyDockWidgets(items);
@@ -417,15 +553,12 @@ void DockWindowManager::tabifyDockWidgets(DockWindowItems* items)
void DockWindowManager::saveState()
{
- ParameterGrp::handle hPref = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
- ->GetGroup("MainWindow")->GetGroup("DockWindows");
-
const QList& dockItems = d->_dockWindowItems.dockWidgets();
for (QList::ConstIterator it = dockItems.begin(); it != dockItems.end(); ++it) {
QDockWidget* dw = findDockWidget(d->_dockedWindows, it->name);
if (dw) {
QByteArray dockName = dw->toggleViewAction()->data().toByteArray();
- hPref->SetBool(dockName.constData(), dw->isVisible());
+ d->_hPref->SetBool(dockName.constData(), dw->isVisible());
}
}
}
@@ -438,7 +571,7 @@ void DockWindowManager::loadState()
for (QList::ConstIterator it = dockItems.begin(); it != dockItems.end(); ++it) {
QDockWidget* dw = findDockWidget(d->_dockedWindows, it->name);
if (dw) {
- QByteArray dockName = it->name.toLatin1();
+ QByteArray dockName = it->name.toUtf8();
bool visible = hPref->GetBool(dockName.constData(), it->visibility);
dw->setVisible(visible);
}
diff --git a/src/Gui/DockWindowManager.h b/src/Gui/DockWindowManager.h
index 76cc3c2c22..38de218e46 100644
--- a/src/Gui/DockWindowManager.h
+++ b/src/Gui/DockWindowManager.h
@@ -26,7 +26,6 @@
#include
#include
-
class QDockWidget;
class QWidget;
@@ -70,6 +69,7 @@ public:
bool registerDockWindow(const char* name, QWidget* widget);
QWidget* unregisterDockWindow(const char* name);
+ QWidget* findRegisteredDockWindow(const char* name);
void setup(DockWindowItems*);
/// Adds a QDockWidget to the main window and sets \a widget as its widget
diff --git a/src/Gui/Icons/cursor-through.svg b/src/Gui/Icons/cursor-through.svg
new file mode 100644
index 0000000000..e2df7b96d2
--- /dev/null
+++ b/src/Gui/Icons/cursor-through.svg
@@ -0,0 +1,88 @@
+
+
+
+
diff --git a/src/Gui/Icons/resource.qrc b/src/Gui/Icons/resource.qrc
index 792194c0ce..d7f3d83772 100644
--- a/src/Gui/Icons/resource.qrc
+++ b/src/Gui/Icons/resource.qrc
@@ -255,6 +255,7 @@
folder.svg
document-python.svg
document-package.svg
+ cursor-through.svg
Std_Alignment.svg
Std_DuplicateSelection.svg
Std_UserEditModeDefault.svg
diff --git a/src/Gui/MainWindow.cpp b/src/Gui/MainWindow.cpp
index a99dadab81..65ee8af19e 100644
--- a/src/Gui/MainWindow.cpp
+++ b/src/Gui/MainWindow.cpp
@@ -31,6 +31,7 @@
# include
# include
# include
+# include
# include
# include
# include
@@ -58,6 +59,8 @@
# include
#endif
+#include
+
#include
#include
#include
@@ -68,6 +71,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -83,6 +87,7 @@
#include "FileDialog.h"
#include "MenuManager.h"
#include "NotificationArea.h"
+#include "OverlayManager.h"
#include "ProgressBar.h"
#include "PropertyView.h"
#include "PythonConsole.h"
@@ -243,6 +248,8 @@ struct MainWindowP
QTimer* actionTimer;
QTimer* statusTimer;
QTimer* activityTimer;
+ QTimer saveStateTimer;
+ QTimer restoreStateTimer;
QMdiArea* mdiArea;
QPointer activeView;
QSignalMapper* windowMapper;
@@ -254,6 +261,13 @@ struct MainWindowP
int currentStatusType = 100;
int actionUpdateDelay = 0;
QMap > urlHandler;
+ std::string hiddenDockWindows;
+ int screen = -1;
+ boost::signals2::scoped_connection connParam;
+ ParameterGrp::handle hGrp;
+ bool _restoring = false;
+ QTime _showNormal;
+ void restoreWindowState(const QByteArray &);
};
class MDITabbar : public QTabBar
@@ -352,6 +366,32 @@ MainWindow::MainWindow(QWidget * parent, Qt::WindowFlags f)
// global access
instance = this;
+ d->connParam = App::GetApplication().GetUserParameter().signalParamChanged.connect(
+ [this](ParameterGrp *Param, ParameterGrp::ParamType, const char *Name, const char *) {
+ if (Param != d->hGrp || !Name)
+ return;
+ if (boost::equals(Name, "StatusBar")) {
+ if(auto sb = getMainWindow()->statusBar())
+ sb->setVisible(d->hGrp->GetBool("StatusBar", sb->isVisible()));
+ }
+ else if (boost::equals(Name, "MainWindowState")) {
+ OverlayManager::instance()->reload(OverlayManager::ReloadMode::ReloadPause);
+ d->restoreStateTimer.start(100);
+ }
+ });
+
+ d->hGrp = App::GetApplication().GetParameterGroupByPath(
+ "User parameter:BaseApp/Preferences/MainWindow");
+ d->saveStateTimer.setSingleShot(true);
+ connect(&d->saveStateTimer, &QTimer::timeout, [this](){this->saveWindowSettings();});
+
+ d->restoreStateTimer.setSingleShot(true);
+ connect(&d->restoreStateTimer, &QTimer::timeout, [this](){
+ d->restoreWindowState(QByteArray::fromBase64(d->hGrp->GetASCII("MainWindowState").c_str()));
+ ToolBarManager::getInstance()->restoreState();
+ OverlayManager::instance()->reload(OverlayManager::ReloadMode::ReloadResume);
+ });
+
// support for grouped dragging of dockwidgets
// https://woboq.com/blog/qdockwidget-changes-in-56.html
setDockOptions(dockOptions() | QMainWindow::GroupedDragging);
@@ -461,31 +501,46 @@ MainWindow* MainWindow::getInstance()
return instance;
}
-void MainWindow::setupDockWindows()
+// Helper function to update dock widget according to the user parameter
+// settings, e.g. register/unregister, enable/disable, show/hide.
+template
+static inline void _updateDockWidget(const char *name,
+ bool enabled,
+ bool show,
+ Qt::DockWidgetArea pos,
+ T callback)
{
- std::string hiddenDockWindows;
- const std::map& config = App::Application::Config();
- auto ht = config.find("HiddenDockWindow");
- if (ht != config.end())
- hiddenDockWindows = ht->second;
-
- setupTreeView(hiddenDockWindows);
- setupPropertyView(hiddenDockWindows);
- setupTaskView(hiddenDockWindows);
- setupSelectionView(hiddenDockWindows);
- setupComboView(hiddenDockWindows);
-
- // Report view must be created before PythonConsole!
- setupReportView(hiddenDockWindows);
- setupPythonConsole(hiddenDockWindows);
- setupDAGView(hiddenDockWindows);
-
- this->setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::North);
+ auto pDockMgr = DockWindowManager::instance();
+ auto widget = pDockMgr->findRegisteredDockWindow(name);
+ if (!enabled) {
+ if(widget) {
+ pDockMgr->removeDockWindow(widget);
+ pDockMgr->unregisterDockWindow(name);
+ widget->deleteLater();
+ }
+ return;
+ }
+ // Use callback to perform specific update for each type of dock widget
+ widget = callback(widget);
+ if(!widget)
+ return;
+ DockWindowManager::instance()->registerDockWindow(name, widget);
+ if(show) {
+ auto dock = pDockMgr->addDockWindow(
+ widget->objectName().toUtf8().constData(), widget, pos);
+ if(dock) {
+ if(!dock->toggleViewAction()->isChecked())
+ dock->toggleViewAction()->activate(QAction::Trigger);
+ OverlayManager::instance()->refresh(dock);
+ }
+ }
}
-bool MainWindow::setupTreeView(const std::string& hiddenDockWindows)
+void MainWindow::initDockWindows(bool show)
{
- if (hiddenDockWindows.find("Std_TreeView") == std::string::npos) {
+ bool treeView = false;
+
+ if (d->hiddenDockWindows.find("Std_TreeView") == std::string::npos) {
//work through parameter.
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("DockWindows")->GetGroup("TreeView");
@@ -495,111 +550,82 @@ bool MainWindow::setupTreeView(const std::string& hiddenDockWindows)
->GetGroup("MainWindow")->GetGroup("DockWindows")->GetBool("Std_TreeView", false);
}
group->SetBool("Enabled", enabled); //ensure entry exists.
- if (enabled) {
- auto tree = new TreeDockWidget(nullptr, this);
- tree->setObjectName
- (QString::fromLatin1(QT_TRANSLATE_NOOP("QDockWidget","Tree view")));
- tree->setMinimumWidth(210);
-
- DockWindowManager* pDockMgr = DockWindowManager::instance();
- pDockMgr->registerDockWindow("Std_TreeView", tree);
- return true;
- }
+ treeView = enabled;
+ _updateDockWidget("Std_TreeView", enabled, show, Qt::RightDockWidgetArea,
+ [](QWidget *widget) {
+ if(widget)
+ return widget;
+ TreeDockWidget* tree = new TreeDockWidget(0,getMainWindow());
+ tree->setObjectName(QStringLiteral(QT_TRANSLATE_NOOP("QDockWidget","Tree view")));
+ tree->setMinimumWidth(210);
+ widget = tree;
+ return widget;
+ });
}
- return false;
-}
-
-bool MainWindow::setupTaskView(const std::string& hiddenDockWindows)
-{
- // Task view
- if (hiddenDockWindows.find("Std_TaskView") == std::string::npos) {
- auto taskView = new Gui::TaskView::TaskView(this);
- taskView->setObjectName
- (QString::fromLatin1(QT_TRANSLATE_NOOP("QDockWidget","Tasks")));
- taskView->setMinimumWidth(210);
-
- DockWindowManager* pDockMgr = DockWindowManager::instance();
- pDockMgr->registerDockWindow("Std_TaskView", taskView);
- return true;
- }
-
- return false;
-}
-
-bool MainWindow::setupPropertyView(const std::string& hiddenDockWindows)
-{
// Property view
- if (hiddenDockWindows.find("Std_PropertyView") == std::string::npos) {
+ if (d->hiddenDockWindows.find("Std_PropertyView") == std::string::npos) {
//work through parameter.
ParameterGrp::handle group = App::GetApplication().GetUserParameter().
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("DockWindows")->GetGroup("PropertyView");
- bool enabled = group->GetBool("Enabled", true);
- if (enabled != group->GetBool("Enabled", false)) {
+ bool enabled = treeView || group->GetBool("Enabled", false);
+ if (!treeView && enabled != group->GetBool("Enabled", true)) {
enabled = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
->GetGroup("MainWindow")->GetGroup("DockWindows")->GetBool("Std_PropertyView", false);
}
group->SetBool("Enabled", enabled); //ensure entry exists.
- if (enabled) {
- auto pcPropView = new PropertyDockView(nullptr, this);
- pcPropView->setObjectName
- (QString::fromLatin1(QT_TRANSLATE_NOOP("QDockWidget","Property view")));
- pcPropView->setMinimumWidth(210);
-
- DockWindowManager* pDockMgr = DockWindowManager::instance();
- pDockMgr->registerDockWindow("Std_PropertyView", pcPropView);
- return true;
- }
+ _updateDockWidget("Std_PropertyView", enabled, show, Qt::RightDockWidgetArea,
+ [](QWidget *widget) {
+ if(widget)
+ return widget;
+ PropertyDockView* pcPropView = new PropertyDockView(0, getMainWindow());
+ pcPropView->setObjectName(QStringLiteral(QT_TRANSLATE_NOOP("QDockWidget","Property view")));
+ pcPropView->setMinimumWidth(210);
+ widget = pcPropView;
+ return widget;
+ });
}
- return false;
-}
-
-bool MainWindow::setupSelectionView(const std::string& hiddenDockWindows)
-{
- // Selection view
- if (hiddenDockWindows.find("Std_SelectionView") == std::string::npos) {
- auto pcSelectionView = new SelectionView(nullptr, this);
- pcSelectionView->setObjectName
- (QString::fromLatin1(QT_TRANSLATE_NOOP("QDockWidget","Selection view")));
- pcSelectionView->setMinimumWidth(210);
-
- DockWindowManager* pDockMgr = DockWindowManager::instance();
- pDockMgr->registerDockWindow("Std_SelectionView", pcSelectionView);
- return true;
- }
-
- return false;
-}
-
-bool MainWindow::setupComboView(const std::string& hiddenDockWindows)
-{
// Combo view
- if (hiddenDockWindows.find("Std_ComboView") == std::string::npos) {
- ParameterGrp::handle group = App::GetApplication().GetUserParameter().
- GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("DockWindows")->GetGroup("ComboView");
- bool enable = group->GetBool("Enabled", true);
-
- if (enable) {
- auto pcComboView = new ComboView(nullptr, this);
- pcComboView->setObjectName(QString::fromLatin1(QT_TRANSLATE_NOOP("QDockWidget", "Model")));
- pcComboView->setMinimumWidth(150);
-
- DockWindowManager* pDockMgr = DockWindowManager::instance();
- pDockMgr->registerDockWindow("Std_ComboView", pcComboView);
- return true;
+ if (d->hiddenDockWindows.find("Std_ComboView") == std::string::npos) {
+ bool enable = !treeView;
+ if (!enable) {
+ ParameterGrp::handle group = App::GetApplication().GetUserParameter().
+ GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("DockWindows")->GetGroup("ComboView");
+ enable = group->GetBool("Enabled", true);
}
+ _updateDockWidget("Std_ComboView", enable, show, Qt::LeftDockWidgetArea,
+ [](QWidget *widget) {
+ auto pcComboView = qobject_cast(widget);
+ if(widget)
+ return widget;
+ pcComboView = new ComboView(nullptr, getMainWindow());
+ pcComboView->setObjectName(QStringLiteral(QT_TRANSLATE_NOOP("QDockWidget", "Model")));
+ pcComboView->setMinimumWidth(150);
+ widget = pcComboView;
+ return widget;
+ });
}
- return false;
-}
-
-bool MainWindow::setupDAGView(const std::string& hiddenDockWindows)
-{
- //TODO: Add external object support for DAGView
+ //Task List (task watcher).
+ if (d->hiddenDockWindows.find("Std_TaskWatcher") == std::string::npos) {
+ //work through parameter.
+ ParameterGrp::handle group = App::GetApplication().GetUserParameter().
+ GetGroup("BaseApp/Preferences/DockWindows/TaskWatcher");
+ bool enabled = group->GetBool("Enabled", false);
+ group->SetBool("Enabled", enabled); //ensure entry exists.
+ _updateDockWidget("Std_TaskWatcher", enabled, show, Qt::RightDockWidgetArea,
+ [](QWidget *widget) {
+ if(widget)
+ return widget;
+ widget = new TaskView::TaskView(getMainWindow());
+ widget->setObjectName(QStringLiteral(QT_TRANSLATE_NOOP("QDockWidget","Task List")));
+ return widget;
+ });
+ }
//Dag View.
- if (hiddenDockWindows.find("Std_DAGView") == std::string::npos) {
+ if (d->hiddenDockWindows.find("Std_DAGView") == std::string::npos) {
//work through parameter.
// old group name
ParameterGrp::handle deprecateGroup = App::GetApplication().GetUserParameter().
@@ -614,24 +640,68 @@ bool MainWindow::setupDAGView(const std::string& hiddenDockWindows)
GetGroup("BaseApp")->GetGroup("Preferences")->GetGroup("DockWindows")->GetGroup("DAGView");
enabled = group->GetBool("Enabled", enabled);
group->SetBool("Enabled", enabled); //ensure entry exists.
- if (enabled) {
- auto dagDockWindow = new DAG::DockWindow(nullptr, this);
- dagDockWindow->setObjectName
- (QString::fromLatin1(QT_TRANSLATE_NOOP("QDockWidget","DAG View")));
- DockWindowManager* pDockMgr = DockWindowManager::instance();
- pDockMgr->registerDockWindow("Std_DAGView", dagDockWindow);
- return true;
- }
+ _updateDockWidget("Std_DAGView", enabled, show, Qt::RightDockWidgetArea,
+ [](QWidget *widget) {
+ if(widget)
+ return widget;
+ DAG::DockWindow *dagDockWindow = new DAG::DockWindow(nullptr, getMainWindow());
+ dagDockWindow->setObjectName(QStringLiteral(QT_TRANSLATE_NOOP("QDockWidget","DAG View")));
+ widget = dagDockWindow;
+ return widget;
+ });
+ }
+}
+
+void MainWindow::setupDockWindows()
+{
+ // Report view must be created before PythonConsole!
+ setupReportView();
+ setupPythonConsole();
+ setupSelectionView();
+ setupTaskView();
+
+ initDockWindows(false);
+}
+
+bool MainWindow::setupTaskView()
+{
+ // Task view
+ if (d->hiddenDockWindows.find("Std_TaskView") == std::string::npos) {
+ auto taskView = new Gui::TaskView::TaskView(this);
+ taskView->setObjectName
+ (QString::fromLatin1(QT_TRANSLATE_NOOP("QDockWidget","Tasks")));
+ taskView->setMinimumWidth(210);
+
+ DockWindowManager* pDockMgr = DockWindowManager::instance();
+ pDockMgr->registerDockWindow("Std_TaskView", taskView);
+ return true;
}
return false;
}
-bool MainWindow::setupReportView(const std::string& hiddenDockWindows)
+bool MainWindow::setupSelectionView()
+{
+ // Selection view
+ if (d->hiddenDockWindows.find("Std_SelectionView") == std::string::npos) {
+ auto pcSelectionView = new SelectionView(nullptr, this);
+ pcSelectionView->setObjectName
+ (QString::fromLatin1(QT_TRANSLATE_NOOP("QDockWidget","Selection view")));
+ pcSelectionView->setMinimumWidth(210);
+
+ DockWindowManager* pDockMgr = DockWindowManager::instance();
+ pDockMgr->registerDockWindow("Std_SelectionView", pcSelectionView);
+ return true;
+ }
+
+ return false;
+}
+
+bool MainWindow::setupReportView()
{
// Report view
- if (hiddenDockWindows.find("Std_ReportView") == std::string::npos) {
+ if (d->hiddenDockWindows.find("Std_ReportView") == std::string::npos) {
auto pcReport = new ReportOutput(this);
pcReport->setWindowIcon(BitmapFactory().pixmap("MacroEditor"));
pcReport->setObjectName
@@ -648,10 +718,10 @@ bool MainWindow::setupReportView(const std::string& hiddenDockWindows)
return false;
}
-bool MainWindow::setupPythonConsole(const std::string& hiddenDockWindows)
+bool MainWindow::setupPythonConsole()
{
// Python console
- if (hiddenDockWindows.find("Std_PythonView") == std::string::npos) {
+ if (d->hiddenDockWindows.find("Std_PythonView") == std::string::npos) {
auto pcPython = new PythonConsole(this);
pcPython->setWindowIcon(Gui::BitmapFactory().iconFromTheme("applications-python"));
pcPython->setObjectName
@@ -1589,37 +1659,49 @@ void MainWindow::switchToDockedMode()
void MainWindow::loadWindowSettings()
{
- QString vendor = QString::fromLatin1(App::Application::Config()["ExeVendor"].c_str());
- QString application = QString::fromLatin1(App::Application::Config()["ExeName"].c_str());
+ QString vendor = QString::fromUtf8(App::Application::Config()["ExeVendor"].c_str());
+ QString application = QString::fromUtf8(App::Application::Config()["ExeName"].c_str());
int major = (QT_VERSION >> 0x10) & 0xff;
int minor = (QT_VERSION >> 0x08) & 0xff;
- QString qtver = QString::fromLatin1("Qt%1.%2").arg(major).arg(minor);
+ QString qtver = QStringLiteral("Qt%1.%2").arg(major).arg(minor);
QSettings config(vendor, application);
- QRect rect = QApplication::primaryScreen()->availableGeometry();
- int maxHeight = rect.height();
- int maxWidth = rect.width();
+ QRect rect = QApplication::desktop()->availableGeometry(d->screen);
config.beginGroup(qtver);
- QPoint pos = config.value(QString::fromLatin1("Position"), this->pos()).toPoint();
- maxWidth -= pos.x();
- maxHeight -= pos.y();
- this->resize(config.value(QString::fromLatin1("Size"), QSize(maxWidth, maxHeight)).toSize());
+ QPoint pos = config.value(QStringLiteral("Position"), this->pos()).toPoint();
+ QSize size = config.value(QStringLiteral("Size"), rect.size()).toSize();
+ bool max = config.value(QStringLiteral("Maximized"), false).toBool();
+ bool showStatusBar = config.value(QStringLiteral("StatusBar"), true).toBool();
+ QByteArray windowState = config.value(QStringLiteral("MainWindowState")).toByteArray();
+ config.endGroup();
- int x1,x2,y1,y2;
- // make sure that the main window is not totally out of the visible rectangle
- rect.getCoords(&x1, &y1, &x2, &y2);
- pos.setX(qMin(qMax(pos.x(),x1-this->width()+30),x2-30));
- pos.setY(qMin(qMax(pos.y(),y1-10),y2-10));
- this->move(pos);
- {
- // tmp. disable the report window to suppress some bothering warnings
- const Base::ILoggerBlocker blocker("ReportOutput", Base::ConsoleSingleton::MsgType_Wrn);
- this->restoreState(config.value(QString::fromLatin1("MainWindowState")).toByteArray());
+ std::string geometry = d->hGrp->GetASCII("Geometry");
+ std::istringstream iss(geometry);
+ int x,y,w,h;
+ if (iss >> x >> y >> w >> h) {
+ pos = QPoint(x,y);
+ size = QSize(w,h);
}
+ max = d->hGrp->GetBool("Maximized", max);
+ showStatusBar = d->hGrp->GetBool("StatusBar", showStatusBar);
+ std::string wstate = d->hGrp->GetASCII("MainWindowState");
+ if (wstate.size())
+ windowState = QByteArray::fromBase64(wstate.c_str());
+
+ x = std::max(rect.left(), std::min(rect.left()+rect.width()/2, pos.x()));
+ y = std::max(rect.top(), std::min(rect.top()+rect.height()/2, pos.y()));
+ w = std::min(rect.width(), size.width());
+ h = std::min(rect.height(), size.height());
+
+ this->move(x, y);
+ this->resize(w, h);
+
+ Base::StateLocker guard(d->_restoring);
+
+ d->restoreWindowState(windowState);
std::clog << "Main window restored" << std::endl;
- bool max = config.value(QString::fromLatin1("Maximized"), false).toBool();
max ? showMaximized() : show();
// make menus and tooltips usable in fullscreen under Windows, see issue #7563
@@ -1629,31 +1711,84 @@ void MainWindow::loadWindowSettings()
}
#endif
- statusBar()->setVisible(config.value(QString::fromLatin1("StatusBar"), true).toBool());
- config.endGroup();
+ statusBar()->setVisible(showStatusBar);
ToolBarManager::getInstance()->restoreState();
std::clog << "Toolbars restored" << std::endl;
+
+ OverlayManager::instance()->restore();
}
-void MainWindow::saveWindowSettings()
+bool MainWindow::isRestoringWindowState() const
{
- QString vendor = QString::fromLatin1(App::Application::Config()["ExeVendor"].c_str());
- QString application = QString::fromLatin1(App::Application::Config()["ExeName"].c_str());
+ return d->_restoring;
+}
+
+void MainWindowP::restoreWindowState(const QByteArray &windowState)
+{
+ if (windowState.isEmpty())
+ return;
+
+ Base::StateLocker guard(_restoring);
+
+ // tmp. disable the report window to suppress some bothering warnings
+ if (Base::Console().IsMsgTypeEnabled("ReportOutput", Base::ConsoleSingleton::MsgType_Wrn)) {
+ Base::Console().SetEnabledMsgType("ReportOutput", Base::ConsoleSingleton::MsgType_Wrn, false);
+ getMainWindow()->restoreState(windowState);
+ Base::Console().SetEnabledMsgType("ReportOutput", Base::ConsoleSingleton::MsgType_Wrn, true);
+ } else
+ getMainWindow()->restoreState(windowState);
+
+ Base::ConnectionBlocker block(connParam);
+ // as a notification for user code on window state restore
+ hGrp->SetBool("WindowStateRestored", !hGrp->GetBool("WindowStateRestored", false));
+}
+
+void MainWindow::saveWindowSettings(bool canDelay)
+{
+ if (isRestoringWindowState())
+ return;
+
+ if (canDelay) {
+ d->saveStateTimer.start(100);
+ return;
+ }
+
+ QString vendor = QString::fromUtf8(App::Application::Config()["ExeVendor"].c_str());
+ QString application = QString::fromUtf8(App::Application::Config()["ExeName"].c_str());
int major = (QT_VERSION >> 0x10) & 0xff;
int minor = (QT_VERSION >> 0x08) & 0xff;
- QString qtver = QString::fromLatin1("Qt%1.%2").arg(major).arg(minor);
+ QString qtver = QStringLiteral("Qt%1.%2").arg(major).arg(minor);
QSettings config(vendor, application);
+#if 0
config.beginGroup(qtver);
- config.setValue(QString::fromLatin1("Size"), this->size());
- config.setValue(QString::fromLatin1("Position"), this->pos());
- config.setValue(QString::fromLatin1("Maximized"), this->isMaximized());
- config.setValue(QString::fromLatin1("MainWindowState"), this->saveState());
- config.setValue(QString::fromLatin1("StatusBar"), this->statusBar()->isVisible());
+ config.setValue(QStringLiteral("Size"), this->size());
+ config.setValue(QStringLiteral("Position"), this->pos());
+ config.setValue(QStringLiteral("Maximized"), this->isMaximized());
+ config.setValue(QStringLiteral("MainWindowState"), this->saveState());
+ config.setValue(QStringLiteral("StatusBar"), this->statusBar()->isVisible());
config.endGroup();
+#else
+ // We are migrating from saving qt main window layout state in QSettings to
+ // FreeCAD parameters, for more control. The old settings is explicitly
+ // remove from old QSettings conf to allow easier complete reset of
+ // application state by just removing FC user.cfg file.
+ config.remove(qtver);
+#endif
+
+ Base::ConnectionBlocker block(d->connParam);
+ d->hGrp->SetBool("Maximized", this->isMaximized());
+ d->hGrp->SetBool("StatusBar", this->statusBar()->isVisible());
+ d->hGrp->SetASCII("MainWindowState", this->saveState().toBase64().constData());
+
+ std::ostringstream ss;
+ QRect rect(this->pos(), this->size());
+ ss << rect.left() << " " << rect.top() << " " << rect.width() << " " << rect.height();
+ d->hGrp->SetASCII("Geometry", ss.str().c_str());
DockWindowManager::instance()->saveState();
+ OverlayManager::instance()->save();
ToolBarManager::getInstance()->saveState();
}
@@ -1669,6 +1804,7 @@ void MainWindow::startSplasher()
if (hGrp->GetBool("ShowSplasher", true)) {
d->splashscreen = new SplashScreen(this->splashImage());
d->splashscreen->show();
+ d->screen = QApplication::desktop()->screenNumber(d->splashscreen);
}
else
d->splashscreen = nullptr;
@@ -2296,6 +2432,11 @@ void MainWindow::customEvent(QEvent* e)
}
}
+QMdiArea *MainWindow::getMdiArea() const
+{
+ return d->mdiArea;
+}
+
// ----------------------------------------------------------
StatusBarObserver::StatusBarObserver()
diff --git a/src/Gui/MainWindow.h b/src/Gui/MainWindow.h
index 9b8405a4fb..248c49094d 100644
--- a/src/Gui/MainWindow.h
+++ b/src/Gui/MainWindow.h
@@ -105,6 +105,10 @@ public:
* Returns a list of all MDI windows in the worpspace.
*/
QList windows(QMdiArea::WindowOrder order = QMdiArea::CreationOrder) const;
+ /**
+ * Returns the internal QMdiArea instance.
+ */
+ QMdiArea *getMdiArea() const;
/**
* Can be called after the caption of an MDIView has changed to update the tab's caption.
*/
@@ -152,7 +156,7 @@ public:
/// Loads the main window settings.
void loadWindowSettings();
/// Saves the main window settings.
- void saveWindowSettings();
+ void saveWindowSettings(bool canDelay = false);
//@}
/** @name Menu
@@ -203,6 +207,8 @@ public:
enum StatusType {None, Err, Wrn, Pane, Msg, Log, Tmp, Critical};
void showStatus(int type, const QString & message);
+ void initDockWindows(bool show);
+
public Q_SLOTS:
/**
* Updates the standard actions of a text editor such as Cut, Copy, Paste, Undo and Redo.
@@ -254,6 +260,8 @@ public Q_SLOTS:
void showMessage (const QString & message, int timeout = 0);
+ bool isRestoringWindowState() const;
+
protected:
/**
* This method checks if the main window can be closed by checking all open documents and views.
@@ -283,14 +291,10 @@ protected:
private:
void setupDockWindows();
- bool setupTreeView(const std::string&);
- bool setupTaskView(const std::string&);
- bool setupPropertyView(const std::string&);
- bool setupSelectionView(const std::string&);
- bool setupComboView(const std::string&);
- bool setupDAGView(const std::string&);
- bool setupReportView(const std::string&);
- bool setupPythonConsole(const std::string&);
+ bool setupTaskView();
+ bool setupSelectionView();
+ bool setupReportView();
+ bool setupPythonConsole();
static void renderDevBuildWarning(QPainter &painter, const QPoint startPosition, const QSize maxSize);
diff --git a/src/Gui/NaviCube.cpp b/src/Gui/NaviCube.cpp
index 92389f736e..c2eb3acfab 100644
--- a/src/Gui/NaviCube.cpp
+++ b/src/Gui/NaviCube.cpp
@@ -162,7 +162,7 @@ private:
public:
- int m_CubeWidgetSize = 132;
+ static int m_CubeWidgetSize;
QColor m_BaseColor;
QColor m_EmphaseColor;
QColor m_HiliteColor;
@@ -201,6 +201,13 @@ private:
QMenu* m_Menu;
};
+int NaviCubeImplementation::m_CubeWidgetSize = 132;
+
+int NaviCube::getNaviCubeSize()
+{
+ return NaviCubeImplementation::m_CubeWidgetSize;
+}
+
NaviCube::NaviCube(Gui::View3DInventorViewer* viewer) {
m_NaviCubeImplementation = new NaviCubeImplementation(viewer);
}
diff --git a/src/Gui/NaviCube.h b/src/Gui/NaviCube.h
index 0384b63c17..c86a3f36cc 100644
--- a/src/Gui/NaviCube.h
+++ b/src/Gui/NaviCube.h
@@ -68,6 +68,7 @@ public:
// Label order: front, top, right, rear, bottom, left
void setNaviCubeLabels(const std::vector& labels);
static void setNaviCubeCommands(const std::vector& cmd);
+ static int getNaviCubeSize();
private:
NaviCubeImplementation* m_NaviCubeImplementation;
diff --git a/src/Gui/OverlayManager.cpp b/src/Gui/OverlayManager.cpp
new file mode 100644
index 0000000000..2df795ee5d
--- /dev/null
+++ b/src/Gui/OverlayManager.cpp
@@ -0,0 +1,2052 @@
+/****************************************************************************
+ * Copyright (c) 2022 Zheng Lei (realthunder) *
+ * *
+ * 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_
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+#endif
+
+#include
+#include
+
+#include
+#include
+
+#include "OverlayManager.h"
+
+#include
+#include
+#include
+#include
+#include "Application.h"
+#include "BitmapFactory.h"
+#include "Control.h"
+#include "MainWindow.h"
+#include "MDIView.h"
+#include "NaviCube.h"
+#include "OverlayParams.h"
+#include "OverlayWidgets.h"
+#include "TaskView/TaskView.h"
+#include "Tree.h"
+#include "TreeParams.h"
+#include "View3DInventorViewer.h"
+
+FC_LOG_LEVEL_INIT("Dock", true, true);
+
+using namespace Gui;
+
+static std::array _Overlays;
+
+static inline OverlayTabWidget *findTabWidget(QWidget *widget=nullptr, bool filterDialog=false)
+{
+ if(!widget)
+ widget = qApp->focusWidget();
+ for(auto w=widget; w; w=w->parentWidget()) {
+ auto tabWidget = qobject_cast(w);
+ if(tabWidget)
+ return tabWidget;
+ auto proxy = qobject_cast(w);
+ if(proxy)
+ return proxy->getOwner();
+ if(filterDialog && w->windowType() != Qt::Widget)
+ break;
+ }
+ return nullptr;
+}
+
+class OverlayStyleSheet: public ParameterGrp::ObserverType {
+public:
+
+ OverlayStyleSheet() {
+ handle = App::GetApplication().GetParameterGroupByPath(
+ "User parameter:BaseApp/Preferences/MainWindow");
+ update();
+ handle->Attach(this);
+ }
+
+ static OverlayStyleSheet *instance() {
+ static OverlayStyleSheet *inst;
+ if(!inst)
+ inst = new OverlayStyleSheet;
+ return inst;
+ }
+
+ void OnChange(Base::Subject &, const char* sReason) {
+ if(!sReason)
+ return;
+ if(strcmp(sReason, "StyleSheet")==0
+ || strcmp(sReason, "OverlayActiveStyleSheet")==0)
+ {
+ OverlayManager::instance()->refresh(nullptr, true);
+ }
+ }
+
+ void update() {
+ QString mainstyle = QString::fromUtf8(handle->GetASCII("StyleSheet").c_str());
+
+ QString prefix;
+
+ if(!mainstyle.isEmpty()) {
+ int dark = mainstyle.indexOf(QStringLiteral("dark"),0,Qt::CaseInsensitive);
+ prefix = QStringLiteral("overlay:%1").arg(
+ dark<0 ? QStringLiteral("Light") : QStringLiteral("Dark"));
+ }
+
+ QString name;
+ name = QString::fromUtf8(handle->GetASCII("OverlayActiveStyleSheet").c_str());
+ if(name.isEmpty() && !prefix.isEmpty())
+ name = prefix + QStringLiteral(".qss");
+ else if (!QFile::exists(name))
+ name = QStringLiteral("overlay:%1").arg(name);
+ activeStyleSheet.clear();
+ if(QFile::exists(name)) {
+ QFile f(name);
+ if(f.open(QFile::ReadOnly)) {
+ QTextStream str(&f);
+ activeStyleSheet = str.readAll();
+ }
+ }
+ if(activeStyleSheet.isEmpty()) {
+ static QString _default = QStringLiteral(
+ "* {alternate-background-color: rgba(250,250,250,120)}"
+
+ "QComboBox, QComboBox:editable, QComboBox:!editable, QLineEdit,"
+ "QTextEdit, QPlainTextEdit, QAbstractSpinBox, QDateEdit, QDateTimeEdit,"
+ "Gui--PropertyEditor--PropertyEditor QLabel "
+ "{background : palette(base);}"
+
+ "QScrollBar { background: rgba(0,0,0,10);}"
+ "QTabWidget::pane { background-color: transparent; border: transparent }"
+ "Gui--OverlayTabWidget { qproperty-effectColor: rgba(0,0,0,0) }"
+ "Gui--OverlayTabWidget::pane { background-color: rgba(250,250,250,80) }"
+
+ "QTabBar {border : none;}"
+ "QTabBar::tab {color: palette(text);"
+ "background-color: rgba(100,100,100,50);"
+ "padding: 5px}"
+ "QTabBar::tab:selected {background-color: rgba(250,250,250,80);}"
+ "QTabBar::tab:hover {background-color: rgba(250,250,250,200);}"
+
+ "QHeaderView { background:transparent }"
+ "QHeaderView::section {color: palette(text);"
+ "background-color: rgba(250,250,250,50);"
+ "border: 1px solid palette(dark);"
+ "padding: 2px}"
+
+ "QTreeView, QListView, QTableView {"
+ "background: rgb(250,250,250);"
+ "border: transparent;"
+ "selection-background-color: rgba(94, 144, 250, 0.7);}"
+ "QListView::item:selected, QTreeView::item:selected {"
+ "background-color: rgba(94, 144, 250, 0.7);}"
+
+ "Gui--PropertyEditor--PropertyEditor {"
+ "border: 1px solid palette(dark);"
+ "qproperty-groupTextColor: rgb(100, 100, 100);"
+ "qproperty-groupBackground: rgba(180, 180, 180, 0.7);}"
+
+ "QToolTip {background-color: rgba(250,250,250,180);}"
+
+ "Gui--TreeWidget QHeaderView:section {"
+ "height: 0px;"
+ "background-color: transparent;"
+ "padding: 0px;"
+ "border: transparent;}"
+
+ "Gui--CallTipsList::item { background-color: rgba(200,200,200,200);}"
+ "Gui--CallTipsList::item::selected { background-color: palette(highlight);}"
+
+ "QPushButton { background: rgba(250,250,250,80);padding: 2px 4px;}"
+ "QPushButton::hover { background: rgba(250,250,250,200);}"
+ "QPushButton::focus { background: rgba(250,250,250,255);}"
+ "QPushButton::pressed { background-color: #5e90fa;"
+ "border: 1px inset palette(dark) }"
+ "QPushButton::checked { background: rgba(100,100,100,100);"
+ "border: 1px inset palette(dark) }"
+ "QPushButton::checked:hover { background: rgba(150,150,150,200);"
+ "border: 1px inset palette(dark) }"
+ "Gui--OverlayToolButton { background: transparent; padding: 0px; border: none }"
+ "Gui--OverlayTitleBar,"
+ "Gui--OverlaySplitterHandle { background-color: rgba(200, 200, 200, 150); }"
+ "QWidget#ClippingScrollAreaContents, "
+ "QScrollArea#ClippingScrollArea { border: none; background-color: #a0e6e6e6; }"
+ "Gui--PropertyEditor--PropertyEditor > QWidget > QPushButton {text-align:left;padding-left:2px;}"
+ );
+ activeStyleSheet = _default;
+ }
+ }
+
+ ParameterGrp::handle handle;
+ QString activeStyleSheet;
+ bool hideTab = false;
+};
+
+// -----------------------------------------------------------
+
+struct OverlayInfo {
+ const char *name;
+ OverlayTabWidget *tabWidget;
+ Qt::DockWidgetArea dockArea;
+ std::unordered_map &overlayMap;
+ ParameterGrp::handle hGrp;
+ boost::signals2::scoped_connection conn;
+
+ OverlayInfo(QWidget *parent,
+ const char *name,
+ Qt::DockWidgetArea pos,
+ std::unordered_map &map)
+ : name(name), dockArea(pos), overlayMap(map)
+ {
+ tabWidget = new OverlayTabWidget(parent, dockArea);
+ tabWidget->setObjectName(QString::fromUtf8(name));
+ tabWidget->getProxyWidget()->setObjectName(tabWidget->objectName() + QStringLiteral("Proxy"));
+ tabWidget->setMovable(true);
+ hGrp = App::GetApplication().GetUserParameter().GetGroup("BaseApp")
+ ->GetGroup("MainWindow")->GetGroup("DockWindows")->GetGroup(name);
+ conn = App::GetApplication().GetUserParameter().signalParamChanged.connect(
+ [this](ParameterGrp *Param, ParameterGrp::ParamType, const char *Name, const char *) {
+ if (hGrp == Param && Name && !tabWidget->isSaving()) {
+ // This will prevent saving settings which will mess up the
+ // just restored ones
+ tabWidget->restore(nullptr);
+ OverlayManager::instance()->reload();
+ }
+ });
+ }
+
+ bool addWidget(QDockWidget *dock, bool forced=true) {
+ if(!dock)
+ return false;
+ if(tabWidget->dockWidgetIndex(dock) >= 0)
+ return false;
+ overlayMap[dock] = this;
+ bool visible = dock->isVisible();
+
+ auto focus = qApp->focusWidget();
+ if(focus && findTabWidget(focus) != tabWidget)
+ focus = nullptr;
+
+ tabWidget->addWidget(dock, dock->windowTitle());
+
+ if(focus) {
+ tabWidget->setCurrent(dock);
+ focus = qApp->focusWidget();
+ if(focus)
+ focus->clearFocus();
+ }
+
+ if(forced) {
+ auto mw = getMainWindow();
+ for(auto d : mw->findChildren()) {
+ if(mw->dockWidgetArea(d) == dockArea
+ && d->toggleViewAction()->isChecked())
+ {
+ addWidget(d, false);
+ }
+ }
+ if(visible) {
+ dock->show();
+ tabWidget->setCurrent(dock);
+ }
+ } else
+ tabWidget->saveTabs();
+ return true;
+ }
+
+ void removeWidget() {
+ if(!tabWidget->count())
+ return;
+
+ tabWidget->hide();
+
+ QPointer focus = qApp->focusWidget();
+
+ QDockWidget *lastDock = tabWidget->currentDockWidget();
+ if(lastDock)
+ tabWidget->removeWidget(lastDock);
+ while(tabWidget->count()) {
+ QDockWidget *dock = tabWidget->dockWidget(0);
+ if(!dock) {
+ tabWidget->removeTab(0);
+ continue;
+ }
+ tabWidget->removeWidget(dock, lastDock);
+ lastDock = dock;
+ }
+
+ if(focus)
+ focus->setFocus();
+
+ tabWidget->saveTabs();
+ }
+
+ void save()
+ {
+ }
+
+ void restore()
+ {
+ tabWidget->restore(hGrp);
+ for(int i=0,c=tabWidget->count();idockWidget(i);
+ if(dock)
+ overlayMap[dock] = this;
+ }
+ }
+};
+
+enum class ToggleMode {
+ Unset,
+ Set,
+ Toggle,
+ Transparent,
+ Check,
+};
+
+class OverlayManager::Private {
+public:
+
+ QPointer lastIntercept;
+ QTimer _timer;
+ QTimer _reloadTimer;
+
+ bool mouseTransparent = false;
+ bool intercepting = false;
+
+ std::unordered_map _overlayMap;
+ OverlayInfo _left;
+ OverlayInfo _right;
+ OverlayInfo _top;
+ OverlayInfo _bottom;
+ std::array _overlayInfos;
+ QCursor _cursor;
+
+ QPoint _lastPos;
+
+ QAction _actClose;
+ QAction _actFloat;
+ QAction _actOverlay;
+ QList _actions;
+
+ QPointer _trackingWidget;
+ OverlayTabWidget *_trackingOverlay = nullptr;
+
+ bool updateStyle = false;
+ QTime wheelDelay;
+ QPoint wheelPos;
+
+ std::map _dockWidgetNameMap;
+
+ bool raising = false;
+
+ OverlayManager::ReloadMode curReloadMode = OverlayManager::ReloadMode::ReloadPending;
+
+ Private(OverlayManager *host, QWidget *parent)
+ :_left(parent,"OverlayLeft", Qt::LeftDockWidgetArea,_overlayMap)
+ ,_right(parent,"OverlayRight", Qt::RightDockWidgetArea,_overlayMap)
+ ,_top(parent,"OverlayTop", Qt::TopDockWidgetArea,_overlayMap)
+ ,_bottom(parent,"OverlayBottom",Qt::BottomDockWidgetArea,_overlayMap)
+ ,_overlayInfos({&_left,&_right,&_top,&_bottom})
+ ,_actions({&_actOverlay,&_actFloat,&_actClose})
+ {
+ _Overlays = {OverlayTabWidget::_LeftOverlay,
+ OverlayTabWidget::_RightOverlay,
+ OverlayTabWidget::_TopOverlay,
+ OverlayTabWidget::_BottomOverlay};
+
+ connect(&_timer, &QTimer::timeout, [this](){onTimer();});
+ _timer.setSingleShot(true);
+
+ _reloadTimer.setSingleShot(true);
+ connect(&_reloadTimer, &QTimer::timeout, [this]() {
+ for (auto &o : _overlayInfos) {
+ o->tabWidget->restore(nullptr); // prevent saving setting first
+ o->removeWidget();
+ }
+ for (auto &o : _overlayInfos)
+ o->restore();
+ refresh();
+ });
+
+ connect(qApp, &QApplication::focusChanged, host, &OverlayManager::onFocusChanged);
+
+ Application::Instance->signalActivateView.connect([this](const MDIView *) {
+ refresh();
+ });
+ Application::Instance->signalInEdit.connect([this](const ViewProviderDocumentObject &) {
+ refresh();
+ });
+ Application::Instance->signalResetEdit.connect([this](const ViewProviderDocumentObject &) {
+ refresh();
+ });
+
+ _actOverlay.setData(QStringLiteral("OBTN Overlay"));
+ _actFloat.setData(QStringLiteral("OBTN Float"));
+ _actClose.setData(QStringLiteral("OBTN Close"));
+
+ retranslate();
+ refreshIcons();
+
+ for(auto action : _actions) {
+ QObject::connect(action, &QAction::triggered, host, &OverlayManager::onAction);
+ }
+ for(auto o : _overlayInfos) {
+ for(auto action : o->tabWidget->actions()) {
+ QObject::connect(action, &QAction::triggered, host, &OverlayManager::onAction);
+ }
+ o->tabWidget->setTitleBar(createTitleBar(o->tabWidget));
+ }
+
+ QIcon px = BitmapFactory().pixmap("cursor-through");
+ _cursor = QCursor(px.pixmap(32,32), 10, 9);
+ }
+
+ void refreshIcons()
+ {
+ _actFloat.setIcon(BitmapFactory().pixmap("qss:overlay/float.svg"));
+ _actOverlay.setIcon(BitmapFactory().pixmap("qss:overlay/overlay.svg"));
+ _actClose.setIcon(BitmapFactory().pixmap("qss:overlay/close.svg"));
+ for (OverlayTabWidget *tabWidget : _Overlays) {
+ tabWidget->refreshIcons();
+ for (auto handle : tabWidget->findChildren())
+ handle->refreshIcons();
+ }
+ }
+
+ void interceptEvent(QWidget *, QEvent *);
+
+ void setMouseTransparent(bool enabled)
+ {
+ if (mouseTransparent == enabled)
+ return;
+ mouseTransparent = enabled;
+ for (OverlayTabWidget *tabWidget : _Overlays) {
+ tabWidget->setAttribute(
+ Qt::WA_TransparentForMouseEvents, enabled);
+ tabWidget->touch();
+ }
+ refresh();
+ if(!enabled)
+ qApp->restoreOverrideCursor();
+ else
+ qApp->setOverrideCursor(_cursor);
+ }
+
+ bool toggleOverlay(QDockWidget *dock, ToggleMode toggle, int dockPos=Qt::NoDockWidgetArea)
+ {
+ if(!dock)
+ return false;
+
+ auto it = _overlayMap.find(dock);
+ if(it != _overlayMap.end()) {
+ auto o = it->second;
+ switch(toggle) {
+ case ToggleMode::Transparent:
+ o->tabWidget->setTransparent(!o->tabWidget->isTransparent());
+ break;
+ case ToggleMode::Unset:
+ case ToggleMode::Toggle:
+ _overlayMap.erase(it);
+ o->tabWidget->removeWidget(dock);
+ return false;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ if(toggle == ToggleMode::Unset)
+ return false;
+
+ if(dockPos == Qt::NoDockWidgetArea)
+ dockPos = getMainWindow()->dockWidgetArea(dock);
+ OverlayInfo *o;
+ switch(dockPos) {
+ case Qt::LeftDockWidgetArea:
+ o = &_left;
+ break;
+ case Qt::RightDockWidgetArea:
+ o = &_right;
+ break;
+ case Qt::TopDockWidgetArea:
+ o = &_top;
+ break;
+ case Qt::BottomDockWidgetArea:
+ o = &_bottom;
+ break;
+ default:
+ return false;
+ }
+ if(toggle == ToggleMode::Check && !o->tabWidget->count())
+ return false;
+ if(o->addWidget(dock)) {
+ if(toggle == ToggleMode::Transparent)
+ o->tabWidget->setTransparent(true);
+ }
+ refresh();
+ return true;
+ }
+
+ void refresh(QWidget *widget=nullptr, bool refreshStyle=false)
+ {
+ if(refreshStyle) {
+ OverlayStyleSheet::instance()->update();
+ updateStyle = true;
+ }
+
+ if(widget) {
+ auto tabWidget = findTabWidget(widget);
+ if(tabWidget && tabWidget->count()) {
+ for(auto o : _overlayInfos) {
+ if(tabWidget == o->tabWidget) {
+ tabWidget->touch();
+ break;
+ }
+ }
+ }
+ }
+ _timer.start(OverlayParams::getDockOverlayDelay());
+ }
+
+ void save()
+ {
+ _left.save();
+ _right.save();
+ _top.save();
+ _bottom.save();
+ }
+
+ void restore()
+ {
+ _left.restore();
+ _right.restore();
+ _top.restore();
+ _bottom.restore();
+ refresh();
+ }
+
+ void onTimer()
+ {
+ auto mdi = getMainWindow() ? getMainWindow()->getMdiArea() : nullptr;
+ if(!mdi)
+ return;
+
+ auto focus = findTabWidget(qApp->focusWidget());
+ if (focus && !focus->getSplitter()->isVisible())
+ focus = nullptr;
+ auto active = findTabWidget(qApp->widgetAt(QCursor::pos()));
+ if (active && !active->getSplitter()->isVisible())
+ active = nullptr;
+ OverlayTabWidget *reveal = nullptr;
+
+ bool updateFocus = false;
+ bool updateActive = false;
+
+ for(auto o : _overlayInfos) {
+ if(o->tabWidget->isTouched() || updateStyle) {
+ if(o->tabWidget == focus)
+ updateFocus = true;
+ else if(o->tabWidget == active)
+ updateActive = true;
+ else
+ o->tabWidget->setOverlayMode(true);
+ }
+ if(!o->tabWidget->getRevealTime().isNull()) {
+ if(o->tabWidget->getRevealTime()<= QTime::currentTime())
+ o->tabWidget->setRevealTime(QTime());
+ else
+ reveal = o->tabWidget;
+ }
+ }
+ updateStyle = false;
+
+ if (focus) {
+ if (focus->isOverlaid(OverlayTabWidget::QueryOption::TransparencyChanged) || updateFocus) {
+ focus->setOverlayMode(false);
+ focus->raise();
+ if(reveal == focus)
+ reveal = nullptr;
+ } else
+ focus->updateSplitterHandles();
+ }
+
+ if(active) {
+ if(active != focus && (active->isOverlaid(OverlayTabWidget::QueryOption::TransparencyChanged) || updateActive))
+ active->setOverlayMode(false);
+ active->raise();
+ if(reveal == active)
+ reveal = nullptr;
+ }
+
+ if(reveal && !reveal->splitter->isVisible()) {
+ reveal->setOverlayMode(false);
+ reveal->raise();
+ }
+
+ for(auto o : _overlayInfos) {
+ if(o->tabWidget != focus
+ && o->tabWidget != active
+ && o->tabWidget != reveal
+ && o->tabWidget->count()
+ && !o->tabWidget->isOverlaid(OverlayTabWidget::QueryOption::TransparencyNotChanged))
+ {
+ o->tabWidget->setOverlayMode(true);
+ }
+ }
+
+ int w = mdi->geometry().width();
+ int h = mdi->geometry().height();
+ auto tabbar = mdi->findChild();
+ if(tabbar)
+ h -= tabbar->height();
+
+ int naviCubeSize = NaviCube::getNaviCubeSize();
+ int naviCorner = OverlayParams::getDockOverlayCheckNaviCube() ?
+ OverlayParams::getCornerNaviCube() : -1;
+
+ QRect rect;
+ QRect rectBottom(0,0,0,0);
+
+ rect = _bottom.tabWidget->getRect();
+
+ QSize ofs = _bottom.tabWidget->getOffset();
+ int delta = _bottom.tabWidget->getSizeDelta();
+ h -= ofs.height();
+
+ auto getCubeSize = [naviCubeSize](OverlayInfo &info) -> int {
+ float scale = info.tabWidget->_imageScale;
+ if (scale == 0.0) {
+ scale = info.tabWidget->titleBar->grab().devicePixelRatio();
+ if (scale == 0.0)
+ scale = 1.0;
+ }
+ return naviCubeSize/scale + 10;
+ };
+
+ int cubeSize = getCubeSize(_bottom);
+ if(naviCorner == 2)
+ ofs.setWidth(ofs.width()+cubeSize);
+ int bw = w-10-ofs.width()-delta;
+ if(naviCorner == 3)
+ bw -= cubeSize;
+ if(bw < 10)
+ bw = 10;
+
+ // Bottom width is maintain the same to reduce QTextEdit re-layout
+ // which may be expensive if there are lots of text, e.g. for
+ // ReportView or PythonConsole.
+ _bottom.tabWidget->setRect(QRect(ofs.width(),h-rect.height(),bw,rect.height()));
+
+ if (_bottom.tabWidget->count()
+ && _bottom.tabWidget->isVisible()
+ && _bottom.tabWidget->getState() <= OverlayTabWidget::State::Normal)
+ rectBottom = _bottom.tabWidget->getRect();
+
+ QRect rectLeft(0,0,0,0);
+ rect = _left.tabWidget->getRect();
+
+ ofs = _left.tabWidget->getOffset();
+ cubeSize = getCubeSize(_left);
+ if(naviCorner == 0)
+ ofs.setWidth(ofs.width()+cubeSize);
+ delta = _left.tabWidget->getSizeDelta()+rectBottom.height();
+ if(naviCorner == 2 && cubeSize > rectBottom.height())
+ delta += cubeSize - rectBottom.height();
+ int lh = std::max(h-ofs.width()-delta, 10);
+
+ _left.tabWidget->setRect(QRect(ofs.height(),ofs.width(),rect.width(),lh));
+
+ if (_left.tabWidget->count()
+ && _left.tabWidget->isVisible()
+ && _left.tabWidget->getState() <= OverlayTabWidget::State::Normal)
+ rectLeft = _left.tabWidget->getRect();
+
+ QRect rectRight(0,0,0,0);
+ rect = _right.tabWidget->getRect();
+
+ ofs = _right.tabWidget->getOffset();
+ cubeSize = getCubeSize(_right);
+ if(naviCorner == 1)
+ ofs.setWidth(ofs.width()+cubeSize);
+ delta = _right.tabWidget->getSizeDelta()+rectBottom.height();
+ if(naviCorner == 3 && cubeSize > rectBottom.height())
+ delta += cubeSize - rectBottom.height();
+ int rh = std::max(h-ofs.width()-delta, 10);
+ w -= ofs.height();
+
+ _right.tabWidget->setRect(QRect(w-rect.width(),ofs.width(),rect.width(),rh));
+
+ if (_right.tabWidget->count()
+ && _right.tabWidget->isVisible()
+ && _right.tabWidget->getState() <= OverlayTabWidget::State::Normal)
+ rectRight = _right.tabWidget->getRect();
+
+ rect = _top.tabWidget->getRect();
+
+ ofs = _top.tabWidget->getOffset();
+ cubeSize = getCubeSize(_top);
+ delta = _top.tabWidget->getSizeDelta();
+ if(naviCorner == 0)
+ rectLeft.setWidth(std::max(rectLeft.width(), cubeSize));
+ else if(naviCorner == 1)
+ rectRight.setWidth(std::max(rectRight.width(), cubeSize));
+ int tw = w-rectLeft.width()-rectRight.width()-ofs.width()-delta;
+
+ _top.tabWidget->setRect(QRect(rectLeft.width()-ofs.width(),ofs.height(),tw,rect.height()));
+ }
+
+ void setOverlayMode(OverlayMode mode)
+ {
+ switch(mode) {
+ case OverlayManager::OverlayMode::DisableAll:
+ case OverlayManager::OverlayMode::EnableAll: {
+ auto docks = getMainWindow()->findChildren();
+ // put visible dock widget first
+ std::sort(docks.begin(),docks.end(),
+ [](const QDockWidget *a, const QDockWidget *b) {
+ return !a->visibleRegion().isEmpty() && b->visibleRegion().isEmpty();
+ });
+ for(auto dock : docks) {
+ if(mode == OverlayManager::OverlayMode::DisableAll)
+ toggleOverlay(dock, ToggleMode::Unset);
+ else
+ toggleOverlay(dock, ToggleMode::Set);
+ }
+ return;
+ }
+ case OverlayManager::OverlayMode::ToggleAll:
+ for(auto o : _overlayInfos) {
+ if(o->tabWidget->count()) {
+ setOverlayMode(OverlayManager::OverlayMode::DisableAll);
+ return;
+ }
+ }
+ setOverlayMode(OverlayManager::OverlayMode::EnableAll);
+ return;
+ case OverlayManager::OverlayMode::TransparentAll: {
+ bool found = false;
+ for(auto o : _overlayInfos) {
+ if(o->tabWidget->count())
+ found = true;
+ }
+ if(!found)
+ setOverlayMode(OverlayManager::OverlayMode::EnableAll);
+ }
+ // fall through
+ case OverlayManager::OverlayMode::TransparentNone:
+ for(auto o : _overlayInfos)
+ o->tabWidget->setTransparent(mode == OverlayManager::OverlayMode::TransparentAll);
+ refresh();
+ return;
+ case OverlayManager::OverlayMode::ToggleTransparentAll:
+ for(auto o : _overlayInfos) {
+ if(o->tabWidget->count() && o->tabWidget->isTransparent()) {
+ setOverlayMode(OverlayManager::OverlayMode::TransparentNone);
+ return;
+ }
+ }
+ setOverlayMode(OverlayManager::OverlayMode::TransparentAll);
+ return;
+ case OverlayManager::OverlayMode::ToggleLeft:
+ if (OverlayTabWidget::_LeftOverlay->isVisible())
+ OverlayTabWidget::_LeftOverlay->setState(OverlayTabWidget::State::Hidden);
+ else
+ OverlayTabWidget::_LeftOverlay->setState(OverlayTabWidget::State::Showing);
+ break;
+ case OverlayManager::OverlayMode::ToggleRight:
+ if (OverlayTabWidget::_RightOverlay->isVisible())
+ OverlayTabWidget::_RightOverlay->setState(OverlayTabWidget::State::Hidden);
+ else
+ OverlayTabWidget::_RightOverlay->setState(OverlayTabWidget::State::Showing);
+ break;
+ case OverlayManager::OverlayMode::ToggleTop:
+ if (OverlayTabWidget::_TopOverlay->isVisible())
+ OverlayTabWidget::_TopOverlay->setState(OverlayTabWidget::State::Hidden);
+ else
+ OverlayTabWidget::_TopOverlay->setState(OverlayTabWidget::State::Showing);
+ break;
+ case OverlayManager::OverlayMode::ToggleBottom:
+ if (OverlayTabWidget::_BottomOverlay->isVisible())
+ OverlayTabWidget::_BottomOverlay->setState(OverlayTabWidget::State::Hidden);
+ else
+ OverlayTabWidget::_BottomOverlay->setState(OverlayTabWidget::State::Showing);
+ break;
+ default:
+ break;
+ }
+
+ ToggleMode m;
+ QDockWidget *dock = nullptr;
+ for(auto w=qApp->widgetAt(QCursor::pos()); w; w=w->parentWidget()) {
+ dock = qobject_cast(w);
+ if(dock)
+ break;
+ auto tabWidget = qobject_cast(w);
+ if(tabWidget) {
+ dock = tabWidget->currentDockWidget();
+ if(dock)
+ break;
+ }
+ }
+ if(!dock) {
+ for(auto w=qApp->focusWidget(); w; w=w->parentWidget()) {
+ dock = qobject_cast(w);
+ if(dock)
+ break;
+ }
+ }
+
+ switch(mode) {
+ case OverlayManager::OverlayMode::ToggleActive:
+ m = ToggleMode::Toggle;
+ break;
+ case OverlayManager::OverlayMode::ToggleTransparent:
+ m = ToggleMode::Transparent;
+ break;
+ case OverlayManager::OverlayMode::EnableActive:
+ m = ToggleMode::Set;
+ break;
+ case OverlayManager::OverlayMode::DisableActive:
+ m = ToggleMode::Unset;
+ break;
+ default:
+ return;
+ }
+ toggleOverlay(dock, m);
+ }
+
+ void onToggleDockWidget(QDockWidget *dock, int checked)
+ {
+ if(!dock)
+ return;
+
+ auto it = _overlayMap.find(dock);
+ if(it == _overlayMap.end())
+ return;
+
+ OverlayTabWidget *tabWidget = it->second->tabWidget;
+ int index = tabWidget->dockWidgetIndex(dock);
+ if(index < 0)
+ return;
+ auto sizes = tabWidget->getSplitter()->sizes();
+ while(index >= sizes.size())
+ sizes.append(0);
+
+ if (checked < -1)
+ checked = 0;
+ else if (checked == 3) {
+ checked = 1;
+ sizes[index] = 0; // force expand the tab in full
+ } else if (checked <= 1) {
+ if (sizes[index] != 0 && tabWidget->isHidden())
+ checked = 1;
+ else {
+ // child widget inside splitter by right shouldn't been hidden, so
+ // we ignore the given toggle bit, but rely on its splitter size to
+ // decide.
+ checked = sizes[index] == 0 ? 1 : 0;
+ }
+ }
+ if(sizes[index]==0) {
+ if (!checked)
+ return;
+ tabWidget->setCurrent(dock);
+ tabWidget->onCurrentChanged(tabWidget->dockWidgetIndex(dock));
+ } else if (!checked) {
+ if (sizes[index] > 0 && sizes.size() > 1) {
+ int newtotal = 0;
+ int total = 0;
+ auto newsizes = sizes;
+ newsizes[index] = 0;
+ for (int i=0; idockWidget(i);
+ auto it = tabWidget->_sizemap.find(d);
+ if (it == tabWidget->_sizemap.end())
+ newsizes[i] = 0;
+ else {
+ if (newtotal == 0)
+ tabWidget->setCurrent(d);
+ newsizes[i] = it->second;
+ newtotal += it->second;
+ }
+ }
+ }
+ if (!newtotal) {
+ int expand = 0;
+ for (int i=0; i 0) {
+ ++expand;
+ break;
+ }
+ }
+ if (expand) {
+ int expansion = sizes[index];
+ int step = expansion / expand;
+ for (int i=0; isplitter->setSizes(newsizes);
+ tabWidget->saveTabs();
+ }
+ }
+ for (int i=0; i_sizemap[tabWidget->dockWidget(i)] = sizes[i];
+ }
+ if (checked)
+ tabWidget->setRevealTime(QTime::currentTime().addMSecs(
+ OverlayParams::getDockOverlayRevealDelay()));
+ refresh();
+ }
+
+ void onFocusChanged(QWidget *, QWidget *) {
+ refresh();
+ }
+
+ void setupTitleBar(QDockWidget *dock)
+ {
+ if(!dock->titleBarWidget())
+ dock->setTitleBarWidget(createTitleBar(dock));
+ }
+
+ QWidget *createTitleBar(QWidget *parent)
+ {
+ OverlayTitleBar *widget = new OverlayTitleBar(parent);
+ widget->setObjectName(QStringLiteral("OverlayTitle"));
+ QList actions;
+ if (auto tabWidget = qobject_cast(parent))
+ actions = tabWidget->actions();
+ else
+ actions = _actions;
+ widget->setTitleItem(OverlayTabWidget::prepareTitleWidget(widget, actions));
+ return widget;
+ }
+
+ void onAction(QAction *action) {
+ if(action == &_actOverlay) {
+ OverlayManager::instance()->setOverlayMode(OverlayManager::OverlayMode::ToggleActive);
+ } else if(action == &_actFloat || action == &_actClose) {
+ for(auto w=qApp->widgetAt(QCursor::pos());w;w=w->parentWidget()) {
+ auto dock = qobject_cast(w);
+ if(!dock)
+ continue;
+ setFocusView();
+ if(action == &_actClose) {
+ dock->toggleViewAction()->activate(QAction::Trigger);
+ } else {
+ auto it = _overlayMap.find(dock);
+ if(it != _overlayMap.end()) {
+ it->second->tabWidget->removeWidget(dock);
+ getMainWindow()->addDockWidget(it->second->dockArea, dock);
+ _overlayMap.erase(it);
+ dock->show();
+ dock->setFloating(true);
+ refresh();
+ } else
+ dock->setFloating(!dock->isFloating());
+ }
+ return;
+ }
+ } else {
+ auto tabWidget = qobject_cast(action->parent());
+ if(tabWidget)
+ tabWidget->onAction(action);
+ }
+ }
+
+ void retranslate()
+ {
+ _actOverlay.setToolTip(QObject::tr("Toggle overlay"));
+ _actFloat.setToolTip(QObject::tr("Toggle floating window"));
+ _actClose.setToolTip(QObject::tr("Close dock window"));
+ }
+
+ void floatDockWidget(QDockWidget *dock)
+ {
+ setFocusView();
+ auto it = _overlayMap.find(dock);
+ if (it != _overlayMap.end()) {
+ it->second->tabWidget->removeWidget(dock);
+ _overlayMap.erase(it);
+ }
+ dock->setFloating(true);
+ dock->show();
+ }
+
+ // Warning, the caller may be deleted during the call. So do not pass
+ // parameter using reference, pass by value instead.
+ void dragDockWidget(QPoint pos,
+ QWidget *srcWidget,
+ QPoint dragOffset,
+ QSize dragSize,
+ bool drop)
+ {
+ if (!getMainWindow())
+ return;
+ auto mdi = getMainWindow()->getMdiArea();
+ if (!mdi)
+ return;
+
+ auto dock = qobject_cast(srcWidget);
+ if (dock && dock->isFloating())
+ dock->move(pos - dragOffset);
+
+ OverlayTabWidget *src = nullptr;
+ int srcIndex = -1;
+ if (dock) {
+ auto it = _overlayMap.find(dock);
+ if (it != _overlayMap.end()) {
+ src = it->second->tabWidget;
+ srcIndex = src->dockWidgetIndex(dock);
+ }
+ }
+ else {
+ src = qobject_cast(srcWidget);
+ if (!src)
+ return;
+ for(int size : src->getSplitter()->sizes()) {
+ ++srcIndex;
+ if (size) {
+ dock = src->dockWidget(srcIndex);
+ break;
+ }
+ }
+ if (!dock)
+ return;
+ }
+
+ OverlayTabWidget *tabWidget = nullptr;
+ int resizeOffset = 0;
+ int index = -1;
+ QRect rect;
+ QRect rectMain(getMainWindow()->mapToGlobal(QPoint()),
+ getMainWindow()->size());
+ QRect rectMdi(mdi->mapToGlobal(QPoint()), mdi->size());
+
+ for (OverlayTabWidget *overlay : _Overlays) {
+ rect = QRect(mdi->mapToGlobal(overlay->rectOverlay.topLeft()),
+ overlay->rectOverlay.size());
+
+ QSize size(rect.width()*3/4, rect.height()*3/4);
+ QSize sideSize(rect.width()/4, rect.height()/4);
+
+ int dockArea = overlay->getDockArea();
+
+ if (dockArea == Qt::BottomDockWidgetArea) {
+ if (pos.y() < rect.bottom() && rect.bottom() - pos.y() < sideSize.height()) {
+ rect.setTop(rect.bottom() - OverlayParams::getDockOverlayMinimumSize());
+ rect.setBottom(rectMain.bottom());
+ rect.setLeft(rectMdi.left());
+ rect.setRight(rectMdi.right());
+ tabWidget = overlay;
+ index = -2;
+ break;
+ }
+ }
+ if (dockArea == Qt::LeftDockWidgetArea) {
+ if (pos.x() >= rect.left() && pos.x() - rect.left() < sideSize.width()) {
+ rect.setRight(rect.left() + OverlayParams::getDockOverlayMinimumSize());
+ rect.setLeft(rectMain.left());
+ rect.setTop(rectMdi.top());
+ rect.setBottom(rectMdi.bottom());
+ tabWidget = overlay;
+ index = -2;
+ break;
+ }
+ }
+ else if (dockArea == Qt::RightDockWidgetArea) {
+ if (pos.x() < rect.right() && rect.right() - pos.x() < sideSize.width()) {
+ rect.setLeft(rect.right() - OverlayParams::getDockOverlayMinimumSize());
+ rect.setRight(rectMain.right());
+ rect.setTop(rectMdi.top());
+ rect.setBottom(rectMdi.bottom());
+ tabWidget = overlay;
+ index = -2;
+ break;
+ }
+ }
+ else if (dockArea == Qt::TopDockWidgetArea) {
+ if (pos.y() >= rect.top() && pos.y() - rect.top() < sideSize.height()) {
+ rect.setBottom(rect.top() + OverlayParams::getDockOverlayMinimumSize());
+ rect.setTop(rectMain.top());
+ rect.setLeft(rectMdi.left());
+ rect.setRight(rectMdi.right());
+ tabWidget = overlay;
+ index = -2;
+ break;
+ }
+ }
+
+ switch(dockArea) {
+ case Qt::LeftDockWidgetArea:
+ rect.setWidth(size.width());
+ break;
+ case Qt::RightDockWidgetArea:
+ rect.setLeft(rect.right() - size.width());
+ break;
+ case Qt::TopDockWidgetArea:
+ rect.setHeight(size.height());
+ break;
+ default:
+ rect.setTop(rect.bottom() - size.height());
+ break;
+ }
+
+ if (!rect.contains(pos))
+ continue;
+
+ tabWidget = overlay;
+ index = -1;
+ int i = -1;
+
+ for (int size : overlay->getSplitter()->sizes()) {
+ ++i;
+ auto handle = overlay->getSplitter()->handle(i);
+ QWidget *w = overlay->dockWidget(i);
+ if (!handle || !w)
+ continue;
+ if (handle->rect().contains(handle->mapFromGlobal(pos))) {
+ QPoint pt = handle->mapToGlobal(QPoint());
+ QSize s = handle->size();
+ if (!size)
+ size = OverlayParams::getDockOverlayMinimumSize();
+ if (tabWidget != src)
+ size /= 2;
+ if (overlay->getSplitter()->orientation() == Qt::Vertical)
+ s.setHeight(s.height() + size);
+ else
+ s.setWidth(s.width() + size);
+ rect = QRect(pt, s);
+ index = i;
+ break;
+ }
+ if (!size)
+ continue;
+ if (w->rect().contains(w->mapFromGlobal(pos))) {
+ QPoint pt = overlay->getSplitter()->mapToGlobal(w->pos());
+ rect = QRect(pt, w->size());
+ if (tabWidget != src) {
+ if (overlay->getSplitter()->orientation() == Qt::Vertical) {
+ if (pos.y() > pt.y() + size/2) {
+ rect.setTop(rect.top() + size/2);
+ resizeOffset = -1;
+ ++i;
+ }
+ else
+ rect.setHeight(size/2);
+ }
+ else if (pos.x() > pt.x() + size/2) {
+ rect.setLeft(rect.left() + size/2);
+ resizeOffset = -1;
+ ++i;
+ }
+ else
+ rect.setWidth(size/2);
+ }
+ index = i;
+ break;
+ }
+ }
+ break;
+ };
+
+ OverlayTabWidget *dst = nullptr;
+ int dstIndex = -1;
+ QDockWidget *dstDock = nullptr;
+ Qt::DockWidgetArea dstDockArea;
+
+ if (!tabWidget) {
+ rect = QRect(pos - dragOffset, dragSize);
+ if (rect.width() < 50)
+ rect.setWidth(50);
+ if (rect.height() < 50)
+ rect.setHeight(50);
+
+ for(auto dockWidget : getMainWindow()->findChildren()) {
+ if (dockWidget == dock
+ || !dockWidget->isVisible()
+ || dockWidget->isFloating()
+ || _overlayMap.count(dockWidget))
+ continue;
+ if (dockWidget->rect().contains(dockWidget->mapFromGlobal(pos))) {
+ dstDock = dockWidget;
+ dstDockArea = getMainWindow()->dockWidgetArea(dstDock);
+ rect = QRect(dockWidget->mapToGlobal(QPoint()),
+ dockWidget->size());
+ break;
+ }
+ }
+ }
+ else {
+ dst = tabWidget;
+ dstIndex = index;
+ if (dstIndex == -1)
+ rect = QRect(mdi->mapToGlobal(tabWidget->rectOverlay.topLeft()),
+ tabWidget->rectOverlay.size());
+ }
+
+ bool outside = false;
+ if (!rectMain.contains(pos)) {
+ outside = true;
+ if (drop) {
+ if (!dock->isFloating()) {
+ if (src) {
+ _overlayMap.erase(dock);
+ src->removeWidget(dock);
+ }
+ setFocusView();
+ dock->setFloating(true);
+ dock->move(pos - dragOffset);
+ dock->show();
+ }
+ if (OverlayTabWidget::_DragFloating)
+ OverlayTabWidget::_DragFloating->hide();
+ } else if (!dock->isFloating()) {
+ if (!OverlayTabWidget::_DragFloating) {
+ OverlayTabWidget::_DragFloating = new QDockWidget(getMainWindow());
+ OverlayTabWidget::_DragFloating->setFloating(true);
+ }
+ OverlayTabWidget::_DragFloating->resize(dock->size());
+ OverlayTabWidget::_DragFloating->setWindowTitle(dock->windowTitle());
+ OverlayTabWidget::_DragFloating->show();
+ OverlayTabWidget::_DragFloating->move(pos - dragOffset);
+ }
+ if (OverlayTabWidget::_DragFrame)
+ OverlayTabWidget::_DragFrame->hide();
+ return;
+
+ } else if (!drop && OverlayTabWidget::_DragFrame && !OverlayTabWidget::_DragFrame->isVisible()) {
+ OverlayTabWidget::_DragFrame->raise();
+ OverlayTabWidget::_DragFrame->show();
+ if (OverlayTabWidget::_DragFloating)
+ OverlayTabWidget::_DragFloating->hide();
+ }
+
+ int insertDock = 0; // 0: tabify, -1: insert before, 1: insert after
+ if (!dst && dstDock) {
+ switch(dstDockArea) {
+ case Qt::LeftDockWidgetArea:
+ case Qt::RightDockWidgetArea:
+ if (pos.y() < rect.top() + rect.height()/4) {
+ insertDock = -1;
+ rect.setBottom(rect.top() + rect.height()/2);
+ }
+ else if (pos.y() > rect.bottom() - rect.height()/4) {
+ insertDock = 1;
+ int height = rect.height();
+ rect.setTop(rect.bottom() - height/4);
+ rect.setHeight(height/2);
+ }
+ break;
+ default:
+ if (pos.x() < rect.left() + rect.width()/4) {
+ insertDock = -1;
+ rect.setRight(rect.left() + rect.width()/2);
+ }
+ else if (pos.x() > rect.right() - rect.width()/4) {
+ insertDock = 1;
+ int width = rect.width();
+ rect.setLeft(rect.right() - width/4);
+ rect.setWidth(width/2);
+ }
+ break;
+ }
+ }
+
+ if (!drop) {
+ if (!OverlayTabWidget::_DragFrame)
+ OverlayTabWidget::_DragFrame = new OverlayDragFrame(getMainWindow());
+
+ rect = QRect(getMainWindow()->mapFromGlobal(rect.topLeft()), rect.size());
+ OverlayTabWidget::_DragFrame->setGeometry(rect);
+ if (!outside && !OverlayTabWidget::_DragFrame->isVisible()) {
+ OverlayTabWidget::_DragFrame->raise();
+ OverlayTabWidget::_DragFrame->show();
+ }
+ return;
+ }
+
+ if (src && src == dst && dstIndex != -2){
+ auto splitter = src->getSplitter();
+ if (dstIndex == -1) {
+ src->tabBar()->moveTab(srcIndex, 0);
+ src->setCurrentIndex(0);
+ src->onCurrentChanged(0);
+ }
+ else if (srcIndex != dstIndex) {
+ auto sizes = splitter->sizes();
+ src->tabBar()->moveTab(srcIndex, dstIndex);
+ splitter->setSizes(sizes);
+ src->onSplitterResize(dstIndex);
+ src->saveTabs();
+ }
+ return;
+ }
+
+ if (src) {
+ _overlayMap.erase(dock);
+ src->removeWidget(dock);
+ }
+
+ setFocusView();
+ if (!dst) {
+ if (dstDock) {
+ dock->setFloating(false);
+ if(insertDock == 0)
+ getMainWindow()->tabifyDockWidget(dstDock, dock);
+ else {
+ std::map docks;
+ for(auto dockWidget : getMainWindow()->findChildren()) {
+ if (dockWidget == dock
+ || !dockWidget->isVisible()
+ || getMainWindow()->dockWidgetArea(dockWidget) != dstDockArea)
+ continue;
+ auto pos = dockWidget->mapToGlobal(QPoint(0,0));
+ if (dstDockArea == Qt::LeftDockWidgetArea || dstDockArea == Qt::RightDockWidgetArea)
+ docks[pos.y()] = dockWidget;
+ else
+ docks[pos.x()] = dockWidget;
+ }
+ auto it = docks.begin();
+ for (;it != docks.end(); ++it) {
+ if (it->second == dstDock)
+ break;
+ }
+ if (insertDock > 0 && it != docks.end())
+ ++it;
+ for (auto iter = it; iter != docks.end(); ++iter)
+ getMainWindow()->removeDockWidget(iter->second);
+ getMainWindow()->addDockWidget(dstDockArea, dock);
+ dock->show();
+ for (auto iter = it; iter != docks.end(); ++iter) {
+ getMainWindow()->addDockWidget(dstDockArea, iter->second);
+ iter->second->show();
+ }
+ }
+ }
+ else {
+ dock->setFloating(true);
+ if(OverlayTabWidget::_DragFrame)
+ dock->setGeometry(QRect(OverlayTabWidget::_DragFrame->mapToGlobal(QPoint()),
+ OverlayTabWidget::_DragFrame->size()));
+ }
+ dock->show();
+ }
+ else if (dstIndex == -2) {
+ getMainWindow()->addDockWidget(dst->getDockArea(), dock);
+ dock->setFloating(false);
+ }
+ else {
+ auto sizes = dst->getSplitter()->sizes();
+ for (auto o : _overlayInfos) {
+ if (o->tabWidget == dst) {
+ o->addWidget(dock, false);
+ break;
+ }
+ }
+ index = dst->dockWidgetIndex(dock);
+ if (index >= 0) {
+ if (dstIndex < 0) {
+ dst->tabBar()->moveTab(index, 0);
+ dst->setCurrentIndex(0);
+ dst->onCurrentChanged(0);
+ }
+ else {
+ dst->tabBar()->moveTab(index, dstIndex);
+ int size = sizes[dstIndex + resizeOffset];
+ if (size) {
+ size /= 2;
+ sizes[dstIndex + resizeOffset] = size;
+ }
+ else
+ size = 50;
+ sizes.insert(dstIndex, size);
+ dst->setCurrentIndex(dstIndex);
+ dst->getSplitter()->setSizes(sizes);
+ dst->onSplitterResize(dstIndex);
+ dst->saveTabs();
+ }
+ dst->setRevealTime(QTime::currentTime().addMSecs(
+ OverlayParams::getDockOverlayRevealDelay()));
+ }
+ }
+
+ refresh();
+ }
+
+ void raiseAll()
+ {
+ if (raising)
+ return;
+ Base::StateLocker guard(raising);
+ for (OverlayTabWidget *tabWidget : _Overlays) {
+ if (tabWidget->isVisible())
+ tabWidget->raise();
+ }
+ }
+
+ void registerDockWidget(const QString &name, OverlayTabWidget *widget) {
+ if (name.size())
+ _dockWidgetNameMap[name] = widget;
+ }
+
+ void unregisterDockWidget(const QString &name, OverlayTabWidget *widget) {
+ auto it = _dockWidgetNameMap.find(name);
+ if (it != _dockWidgetNameMap.end() && it->second == widget)
+ _dockWidgetNameMap.erase(it);
+ }
+
+ void reload(OverlayManager::ReloadMode mode) {
+ if (mode == OverlayManager::ReloadMode::ReloadResume)
+ curReloadMode = mode = OverlayManager::ReloadMode::ReloadPending;
+ if (mode == OverlayManager::ReloadMode::ReloadPending) {
+ if (curReloadMode != OverlayManager::ReloadMode::ReloadPause) {
+ FC_LOG("reload pending");
+ _reloadTimer.start(100);
+ }
+ }
+ curReloadMode = mode;
+ if (mode == OverlayManager::ReloadMode::ReloadPause) {
+ FC_LOG("reload paused");
+ _reloadTimer.stop();
+ }
+ }
+};
+
+
+static OverlayManager * _instance;
+
+OverlayManager* OverlayManager::instance()
+{
+ if ( _instance == 0 )
+ _instance = new OverlayManager;
+ return _instance;
+}
+
+void OverlayManager::destruct()
+{
+ delete _instance;
+ _instance = 0;
+}
+
+OverlayManager::OverlayManager()
+{
+ d = new Private(this, getMainWindow());
+ qApp->installEventFilter(this);
+}
+
+OverlayManager::~OverlayManager()
+{
+ delete d;
+}
+
+void OverlayManager::setOverlayMode(OverlayMode mode)
+{
+ d->setOverlayMode(mode);
+}
+
+
+void OverlayManager::initDockWidget(QDockWidget *dw)
+{
+ QObject::connect(dw->toggleViewAction(), &QAction::triggered,
+ this, &OverlayManager::onToggleDockWidget);
+ QObject::connect(dw, &QDockWidget::visibilityChanged,
+ this, &OverlayManager::onDockVisibleChange);
+ if (auto widget = dw->widget()) {
+ QObject::connect(widget, &QWidget::windowTitleChanged,
+ this, &OverlayManager::onDockWidgetTitleChange);
+ }
+
+ QString name = dw->objectName();
+ if (name.size()) {
+ auto it = d->_dockWidgetNameMap.find(dw->objectName());
+ if (it != d->_dockWidgetNameMap.end()) {
+ for (auto o : d->_overlayInfos) {
+ if (o->tabWidget == it->second) {
+ o->addWidget(dw, true);
+ d->onToggleDockWidget(dw, 3);
+ break;
+ }
+ }
+ d->refresh();
+ }
+ }
+}
+
+void OverlayManager::setupDockWidget(QDockWidget *dw, int dockArea)
+{
+ (void)dockArea;
+ d->setupTitleBar(dw);
+}
+
+void OverlayManager::unsetupDockWidget(QDockWidget *dw)
+{
+ d->toggleOverlay(dw, ToggleMode::Unset);
+}
+
+void OverlayManager::onToggleDockWidget(bool checked)
+{
+ auto action = qobject_cast(sender());
+ if(!action)
+ return;
+ d->onToggleDockWidget(qobject_cast(action->parent()), checked);
+}
+
+void OverlayManager::onDockVisibleChange(bool visible)
+{
+ auto dock = qobject_cast(sender());
+ if(!dock)
+ return;
+ FC_TRACE("dock " << dock->objectName().toUtf8().constData()
+ << " visible change " << visible << ", " << dock->isVisible());
+}
+
+void OverlayManager::onTaskViewUpdate()
+{
+ auto taskview = qobject_cast(sender());
+ if (!taskview)
+ return;
+ QDockWidget *dock = nullptr;
+ for (QWidget *w=taskview; w; w=w->parentWidget()) {
+ if ((dock = qobject_cast(w)))
+ break;
+ }
+ if (dock) {
+ auto it = d->_overlayMap.find(dock);
+ if (it == d->_overlayMap.end()
+ || it->second->tabWidget->count() < 2
+ || it->second->tabWidget->getAutoMode() != OverlayTabWidget::AutoMode::TaskShow)
+ return;
+ d->onToggleDockWidget(dock, taskview->isEmpty() ? -2 : 2);
+ }
+}
+
+void OverlayManager::onDockWidgetTitleChange(const QString &title)
+{
+ if (title.isEmpty())
+ return;
+ auto widget = qobject_cast(sender());
+ QDockWidget *dock = nullptr;
+ for (QWidget *w=widget; w; w=w->parentWidget()) {
+ if ((dock = qobject_cast(w)))
+ break;
+ }
+ if(!dock)
+ return;
+ auto tabWidget = findTabWidget(dock);
+ if (!tabWidget)
+ return;
+ int index = tabWidget->dockWidgetIndex(dock);
+ if (index >= 0)
+ tabWidget->setTabText(index, title);
+}
+
+void OverlayManager::retranslate()
+{
+ d->retranslate();
+}
+
+void OverlayManager::refreshIcons()
+{
+ d->refreshIcons();
+}
+
+void OverlayManager::reload(ReloadMode mode)
+{
+ d->reload(mode);
+}
+
+void OverlayManager::raiseAll()
+{
+ d->raiseAll();
+}
+
+static inline bool
+isNear(const QPoint &a, const QPoint &b, int tol = 16)
+{
+ QPoint d = a - b;
+ return d.x()*d.x() + d.y()*d.y() < tol;
+}
+
+bool OverlayManager::eventFilter(QObject *o, QEvent *ev)
+{
+ if (d->intercepting || !getMainWindow() || !o->isWidgetType())
+ return false;
+ auto mdi = getMainWindow()->getMdiArea();
+ if (!mdi)
+ return false;
+
+ switch(ev->type()) {
+ case QEvent::Enter:
+ if (Selection().hasPreselection()
+ && !qobject_cast(o)
+ && !isUnderOverlay())
+ {
+ Selection().rmvPreselect();
+ }
+ break;
+ case QEvent::ZOrderChange: {
+ if(!d->raising && getMainWindow() && o == mdi) {
+ // On Windows, for some reason, it will raise mdi window on tab
+ // change in any docked widget, which will then obscure any overlay
+ // docked widget here.
+ for (auto child : getMainWindow()->children()) {
+ if (child == mdi || qobject_cast(child)) {
+ QMetaObject::invokeMethod(this, "raiseAll", Qt::QueuedConnection);
+ break;
+ }
+ if (qobject_cast(child))
+ break;
+ }
+ }
+ break;
+ }
+ case QEvent::Resize: {
+ if(getMainWindow() && o == mdi)
+ refresh();
+ return false;
+ }
+ case QEvent::KeyPress: {
+ QKeyEvent *ke = static_cast(ev);
+ bool accepted = false;
+ if (ke->modifiers() == Qt::NoModifier && ke->key() == Qt::Key_Escape) {
+ if (d->mouseTransparent) {
+ d->setMouseTransparent(false);
+ accepted = true;
+ } else if (OverlayTabWidget::_Dragging && OverlayTabWidget::_Dragging != o) {
+ if (auto titleBar = qobject_cast(OverlayTabWidget::_Dragging))
+ titleBar->endDrag();
+ else if (auto splitHandle = qobject_cast(OverlayTabWidget::_Dragging))
+ splitHandle->endDrag();
+ }
+ else if (!OverlayTabWidget::_Dragging) {
+ for (OverlayTabWidget *tabWidget : _Overlays) {
+ if (tabWidget->onEscape())
+ accepted = true;
+ }
+ }
+ }
+ if (accepted) {
+ ke->accept();
+ return true;
+ }
+ break;
+ }
+ case QEvent::Paint:
+ if (auto widget = qobject_cast(o)) {
+ // QAbstractItemView optimize redraw using its item delegate's
+ // visualRect(). However, if we are using QGraphicsEffects, the
+ // effect may touch areas outside of visualRect(), so
+ // OverlayTabWidget offers a timer for a delayed redraw.
+ widget = qobject_cast(widget->parentWidget());
+ if(widget) {
+ auto tabWidget = findTabWidget(widget, true);
+ if (tabWidget)
+ tabWidget->scheduleRepaint();
+ }
+ }
+ break;
+ // case QEvent::NativeGesture:
+ case QEvent::Wheel:
+ if (!OverlayParams::getDockOverlayWheelPassThrough())
+ return false;
+ // fall through
+ case QEvent::ContextMenu: {
+ auto cev = static_cast(ev);
+ if (cev->reason() != QContextMenuEvent::Mouse)
+ return false;
+ } // fall through
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseMove: {
+ if (OverlayTabWidget::_Dragging && OverlayTabWidget::_Dragging != o) {
+ if (auto titleBar = qobject_cast(OverlayTabWidget::_Dragging))
+ titleBar->endDrag();
+ else if (auto splitHandle = qobject_cast(OverlayTabWidget::_Dragging))
+ splitHandle->endDrag();
+ }
+ QWidget *grabber = QWidget::mouseGrabber();
+ d->lastIntercept = nullptr;
+ if (d->mouseTransparent || (grabber && grabber != d->_trackingOverlay))
+ return false;
+ if (qobject_cast(o))
+ return false;
+ if (ev->type() != QEvent::Wheel) {
+ if (qobject_cast(o))
+ return false;
+ } else if (qobject_cast(o))
+ return false;
+
+ if (d->_trackingWidget) {
+ if(!isTreeViewDragging())
+ d->interceptEvent(d->_trackingWidget, ev);
+ if(isTreeViewDragging()
+ || ev->type() == QEvent::MouseButtonRelease
+ || QApplication::mouseButtons() == Qt::NoButton)
+ {
+ d->_trackingWidget = nullptr;
+ if (d->_trackingOverlay == grabber
+ && ev->type() == QEvent::MouseButtonRelease)
+ {
+ d->_trackingOverlay = nullptr;
+ // Must not release mouse here, because otherwise the event
+ // will find its way to the actual widget under cursor.
+ // Instead, return false here to let OverlayTabWidget::event()
+ // release the mouse.
+ return false;
+ }
+ if(d->_trackingOverlay && grabber == d->_trackingOverlay)
+ d->_trackingOverlay->releaseMouse();
+ d->_trackingOverlay = nullptr;
+ }
+ // Must return true here to filter the event, otherwise ContextMenu
+ // event may be routed to the actual widget. Other types of event
+ // probably do not matter.
+ return true;
+ } else if (ev->type() != QEvent::MouseButtonPress
+ && ev->type() != QEvent::MouseButtonDblClick
+ && QApplication::mouseButtons() != Qt::NoButton)
+ return false;
+
+ if(isTreeViewDragging())
+ return false;
+
+ OverlayTabWidget *activeTabWidget = nullptr;
+ int hit = 0;
+ QPoint pos = QCursor::pos();
+ if (OverlayParams::getDockOverlayAutoMouseThrough()
+ && ev->type() != QEvent::Wheel
+ && pos == d->_lastPos)
+ {
+ hit = 1;
+ } else if (ev->type() == QEvent::Wheel
+ && !d->wheelDelay.isNull()
+ && (isNear(pos, d->wheelPos) || d->wheelDelay > QTime::currentTime()))
+ {
+ d->wheelDelay = QTime::currentTime().addMSecs(
+ OverlayParams::getDockOverlayWheelDelay());
+ d->wheelPos = pos;
+ return false;
+ } else {
+ for(auto widget=qApp->widgetAt(pos); widget ; widget=widget->parentWidget()) {
+ int type = widget->windowType();
+ if (type != Qt::Widget && type != Qt::Window) {
+ if (type != Qt::SubWindow)
+ hit = -1;
+ break;
+ }
+ if (ev->type() == QEvent::Wheel) {
+ if (qobject_cast(widget))
+ activeTabWidget = qobject_cast(widget->parentWidget());
+ else if (qobject_cast(widget)) {
+ auto parent = widget->parentWidget();
+ if (parent)
+ activeTabWidget = qobject_cast(parent->parentWidget());
+ }
+ if (activeTabWidget)
+ break;
+ }
+ if (auto tabWidget = qobject_cast(widget)) {
+ if (tabWidget->testAlpha(pos, ev->type() == QEvent::Wheel ? 4 : 1) == 0)
+ activeTabWidget = tabWidget;
+ break;
+ }
+ }
+ if (activeTabWidget) {
+ hit = OverlayParams::getDockOverlayAutoMouseThrough();
+ d->_lastPos = pos;
+ }
+ }
+
+ for (OverlayTabWidget *tabWidget : _Overlays) {
+ if (tabWidget->getProxyWidget()->hitTest(pos) == OverlayProxyWidget::HitTest::HitInner) {
+ if ((ev->type() == QEvent::MouseButtonRelease
+ || ev->type() == QEvent::MouseButtonPress)
+ && static_cast(ev)->button() == Qt::LeftButton)
+ {
+ if (ev->type() == QEvent::MouseButtonRelease)
+ tabWidget->getProxyWidget()->onMousePress();
+ return true;
+ }
+ }
+ }
+
+ if (hit <= 0) {
+ d->_lastPos.setX(INT_MAX);
+ if (ev->type() == QEvent::Wheel) {
+ d->wheelDelay = QTime::currentTime().addMSecs(OverlayParams::getDockOverlayWheelDelay());
+ d->wheelPos = pos;
+ }
+ return false;
+ }
+
+ auto hitWidget = mdi->childAt(mdi->mapFromGlobal(pos));
+ if (!hitWidget)
+ return false;
+
+ if (!activeTabWidget)
+ activeTabWidget = findTabWidget(qApp->widgetAt(QCursor::pos()));
+ if(!activeTabWidget || !activeTabWidget->isTransparent())
+ return false;
+
+ ev->accept();
+ d->interceptEvent(hitWidget, ev);
+ if (ev->isAccepted() && ev->type() == QEvent::MouseButtonPress) {
+ hitWidget->setFocus();
+ d->_trackingWidget = hitWidget;
+ d->_trackingOverlay = activeTabWidget;
+ d->_trackingOverlay->grabMouse();
+ }
+ return true;
+ }
+ default:
+ break;
+ }
+ return false;
+}
+
+namespace {
+class MouseGrabberGuard {
+public:
+ MouseGrabberGuard(QWidget *grabber)
+ {
+ if (grabber && grabber == QWidget::mouseGrabber()) {
+ _grabber = grabber;
+ _grabber->releaseMouse();
+ }
+ }
+ ~MouseGrabberGuard()
+ {
+ if (_grabber)
+ _grabber->grabMouse();
+ }
+
+ QPointer _grabber;
+};
+}// anonymous namespace
+
+void OverlayManager::Private::interceptEvent(QWidget *widget, QEvent *ev)
+{
+ Base::StateLocker guard(this->intercepting);
+ MouseGrabberGuard grabberGuard(_trackingOverlay);
+
+ lastIntercept = nullptr;
+ auto getChildAt = [](QWidget *w, const QPoint &pos) {
+ QWidget *res = w;
+ for (; w; w = w->childAt(w->mapFromGlobal(pos))) {
+ if (auto scrollArea = qobject_cast(w)) {
+ return scrollArea->viewport();
+ }
+ res = w;
+ }
+ return res;
+ };
+
+ switch(ev->type()) {
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseMove:
+ case QEvent::MouseButtonDblClick: {
+ auto me = static_cast(ev);
+ lastIntercept = getChildAt(widget, me->globalPos());
+ QMouseEvent mouseEvent(ev->type(),
+ lastIntercept->mapFromGlobal(me->globalPos()),
+ me->screenPos(),
+ me->button(),
+ me->buttons(),
+ me->modifiers());
+ QApplication::sendEvent(lastIntercept, &mouseEvent);
+ break;
+ }
+ case QEvent::Wheel: {
+ auto we = static_cast(ev);
+ lastIntercept = getChildAt(widget, we->globalPos());
+#if QT_VERSION >= QT_VERSION_CHECK(5,12,0)
+ QWheelEvent wheelEvent(lastIntercept->mapFromGlobal(we->globalPos()),
+ we->globalPos(),
+ we->pixelDelta(),
+ we->angleDelta(),
+ we->buttons(),
+ we->modifiers(),
+ we->phase(),
+ we->inverted(),
+ we->source());
+#else
+ QWheelEvent wheelEvent(lastIntercept->mapFromGlobal(we->globalPos()),
+ we->globalPos(),
+ we->pixelDelta(),
+ we->angleDelta(),
+ 0,
+ Qt::Vertical,
+ we->buttons(),
+ we->modifiers(),
+ we->phase(),
+ we->source(),
+ we->inverted());
+#endif
+ QApplication::sendEvent(lastIntercept, &wheelEvent);
+ break;
+ }
+ case QEvent::ContextMenu: {
+ auto ce = static_cast(ev);
+ lastIntercept = getChildAt(widget, ce->globalPos());
+ QContextMenuEvent contextMenuEvent(ce->reason(),
+ lastIntercept->mapFromGlobal(ce->globalPos()),
+ ce->globalPos());
+ QApplication::sendEvent(lastIntercept, &contextMenuEvent);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void OverlayManager::refresh(QWidget *widget, bool refreshStyle)
+{
+ d->refresh(widget, refreshStyle);
+}
+
+void OverlayManager::setMouseTransparent(bool enabled)
+{
+ d->setMouseTransparent(enabled);
+}
+
+bool OverlayManager::isMouseTransparent() const
+{
+ return d->mouseTransparent;
+}
+
+bool OverlayManager::isUnderOverlay() const
+{
+ return OverlayParams::getDockOverlayAutoMouseThrough()
+ && findTabWidget(qApp->widgetAt(QCursor::pos()), true);
+}
+
+void OverlayManager::save()
+{
+ d->save();
+}
+
+void OverlayManager::restore()
+{
+ d->restore();
+
+ if (Control().taskPanel())
+ connect(Control().taskPanel(), &TaskView::TaskView::taskUpdate,
+ this, &OverlayManager::onTaskViewUpdate);
+}
+
+void OverlayManager::setupTitleBar(QDockWidget *dock)
+{
+ d->setupTitleBar(dock);
+}
+
+void OverlayManager::onFocusChanged(QWidget *old, QWidget *now)
+{
+ d->onFocusChanged(old, now);
+}
+
+void OverlayManager::onAction()
+{
+ QAction *action = qobject_cast(sender());
+ if(action)
+ d->onAction(action);
+}
+
+void OverlayManager::dragDockWidget(const QPoint &pos,
+ QWidget *src,
+ const QPoint &offset,
+ const QSize &size,
+ bool drop)
+{
+ d->dragDockWidget(pos, src, offset, size, drop);
+}
+
+void OverlayManager::floatDockWidget(QDockWidget *dock)
+{
+ d->floatDockWidget(dock);
+}
+
+void OverlayManager::registerDockWidget(const QString &name, OverlayTabWidget *widget)
+{
+ d->registerDockWidget(name, widget);
+}
+
+void OverlayManager::unregisterDockWidget(const QString &name, OverlayTabWidget *widget)
+{
+ d->unregisterDockWidget(name, widget);
+}
+
+QWidget *OverlayManager::getLastMouseInterceptWidget() const
+{
+ return d->lastIntercept;
+}
+
+const QString &OverlayManager::getStyleSheet() const
+{
+ return OverlayStyleSheet::instance()->activeStyleSheet;
+}
+
+bool OverlayManager::getHideTab() const
+{
+ return OverlayStyleSheet::instance()->hideTab;
+}
+
+void OverlayManager::setFocusView()
+{
+ auto view = getMainWindow()->activeWindow();
+ if (!view)
+ view = Application::Instance->activeView();
+ if (view)
+ view->setFocus();
+}
+
+#include "moc_OverlayManager.cpp"
diff --git a/src/Gui/OverlayManager.h b/src/Gui/OverlayManager.h
new file mode 100644
index 0000000000..26e89fe947
--- /dev/null
+++ b/src/Gui/OverlayManager.h
@@ -0,0 +1,190 @@
+/****************************************************************************
+ * Copyright (c) 2022 Zheng Lei (realthunder) *
+ * *
+ * 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 FC_OVERLAYMANAGER_H
+#define FC_OVERLAYMANAGER_H
+
+#include
+
+class QAction;
+class QDockWidget;
+class QString;
+class QPoint;
+class QWidget;
+
+namespace Gui {
+
+class OverlayTabWidget;
+
+/// Class that manages overlay dockable widgets
+class GuiExport OverlayManager : public QObject {
+ Q_OBJECT
+public:
+ OverlayManager();
+ virtual ~OverlayManager();
+
+ /// restore states
+ void restore();
+ /// save states
+ void save();
+ /// Retranslate text on language change
+ void retranslate();
+ /// Reload icon images
+ void refreshIcons();
+
+ /// Reload mode
+ enum class ReloadMode {
+ /// Reload is pending
+ ReloadPending = 0,
+ /// Reload is paused
+ ReloadPause = 1,
+ /// Resume state reload
+ ReloadResume = 2,
+ };
+ /** Set reload mode
+ *
+ * An internal timer is used to batch handle all relevant parameter
+ * changes. The function is provided to let other code temporarily disable
+ * the timer before changing the parameter, and then resume it after done.
+ */
+ void reload(ReloadMode mode = ReloadMode::ReloadPending);
+
+ /** Refresh overlay internal layout
+ * @param widget: optional source widget that triggers the refresh
+ * @param refreshStyle: whether to reload stylesheet
+ */
+ void refresh(QWidget *widget=nullptr, bool refreshStyle=false);
+
+ /// Setup title bar for a QDockWidget
+ void setupTitleBar(QDockWidget *);
+
+ /// Overlay mode
+ enum class OverlayMode {
+ /// Toggle the focused widget between normal and overlay on top of MDI client area
+ ToggleActive,
+ /// Toggle overlay dock widget background between opaque and transparent
+ ToggleTransparent,
+ /// Make the focused widget switch to overlay on top of MDI client area
+ EnableActive,
+ /// Make the focused widget switch back to normal dockable widget
+ DisableActive,
+ /// Make all docked widget switch to overlay
+ EnableAll,
+ /// Make all docked widget switch back to normal
+ DisableAll,
+ /// Toggle all docked widget between normal and overlay
+ ToggleAll,
+ /// Set all overlay dock widget to transparent background
+ TransparentAll,
+ /// Set all overlay dock widget to opaque background
+ TransparentNone,
+ /// Toggle all overlay dock widget background between opaque and transparent
+ ToggleTransparentAll,
+ /// Toggle show/hide of the left docked widgets
+ ToggleLeft,
+ /// Toggle show/hide of the right docked widgets
+ ToggleRight,
+ /// Toggle show/hide of the top docked widgets
+ ToggleTop,
+ /// Toggle show/hide of the bottom docked widgets
+ ToggleBottom,
+ };
+ /// Set overlay mode
+ void setOverlayMode(OverlayMode mode);
+
+ /// Enable/disable mouse transparent mode
+ void setMouseTransparent(bool enabled);
+ /// Report if mouse transparent mode is active
+ bool isMouseTransparent() const;
+
+ /// Check if the cursor is within an overlay docked widget
+ bool isUnderOverlay() const;
+
+ /// Initialize a newly created dock widget
+ void initDockWidget(QDockWidget *);
+ /// Prepare a dock widget for overlay display
+ void setupDockWidget(QDockWidget *, int dockArea = Qt::NoDockWidgetArea);
+ /// Switch a dock widget back to normal display
+ void unsetupDockWidget(QDockWidget *);
+
+ /** Mouse event handler for dragging a dock widget
+ * @param pos: mouse cursor position
+ * @param widget: dragging widget, can either be a QDockWidget if it is
+ * floating, or a OverlayTabWidget if docked in overlay mode
+ * @param offset: offset from the mouse cursor to the widget origin
+ * @param size: widget size before dragging start
+ * @param drop: whether to drop after drag to the position
+ */
+ void dragDockWidget(const QPoint &pos,
+ QWidget *widget,
+ const QPoint &offset,
+ const QSize &size,
+ bool drop = false);
+
+ /// Float an overlay docked widget
+ void floatDockWidget(QDockWidget *);
+
+ /// Return the last widget whose mouse event got intercepted by the overlay manager for mouse pass through
+ QWidget *getLastMouseInterceptWidget() const;
+
+ /// Return the stylesheet for overlay widgets
+ const QString &getStyleSheet() const;
+
+ /// Check whether to hide tab in overlay dock widget
+ bool getHideTab() const;
+
+ /// Helper function to set focus when switching active sub window
+ static void setFocusView();
+
+ /// Return the singleton instance of the overlay manager
+ static OverlayManager * instance();
+ /// Destroy the overlay manager
+ static void destruct();
+
+ class Private;
+
+protected:
+ bool eventFilter(QObject *, QEvent *ev);
+
+ /// Register a named docked widget with an overlay tab widget
+ void registerDockWidget(const QString &name, OverlayTabWidget *);
+ /// Unregister a named docked widget with an overlay tab widget
+ void unregisterDockWidget(const QString &name, OverlayTabWidget *);
+
+private:
+ void onToggleDockWidget(bool checked);
+ void onDockVisibleChange(bool visible);
+ void onDockWidgetTitleChange(const QString &);
+ void onTaskViewUpdate();
+ void onFocusChanged(QWidget *, QWidget *);
+ void onAction();
+ void raiseAll();
+
+private:
+ friend class Private;
+ friend class OverlayTabWidget;
+ Private * d;
+};
+
+} // namespace Gui
+
+#endif // FC_OVERLAYMANAGER_H
diff --git a/src/Gui/OverlayParams.cpp b/src/Gui/OverlayParams.cpp
new file mode 100644
index 0000000000..ae92fd6e1e
--- /dev/null
+++ b/src/Gui/OverlayParams.cpp
@@ -0,0 +1,1151 @@
+/****************************************************************************
+ * Copyright (c) 2022 Zheng Lei (realthunder) *
+ * *
+ * 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"
+#include "OverlayManager.h"
+
+/*[[[cog
+import OverlayParams
+OverlayParams.define()
+]]]*/
+
+// Auto generated code (Tools/params_utils.py:166)
+#include
+#include
+#include
+#include "OverlayParams.h"
+using namespace Gui;
+
+// Auto generated code (Tools/params_utils.py:175)
+namespace {
+class OverlayParamsP: public ParameterGrp::ObserverType {
+public:
+ ParameterGrp::handle handle;
+ std::unordered_map funcs;
+
+ long CornerNaviCube;
+ bool DockOverlayAutoView;
+ long DockOverlayDelay;
+ long DockOverlayRevealDelay;
+ long DockOverlaySplitterHandleTimeout;
+ bool DockOverlayActivateOnHover;
+ bool DockOverlayAutoMouseThrough;
+ bool DockOverlayWheelPassThrough;
+ long DockOverlayWheelDelay;
+ long DockOverlayAlphaRadius;
+ bool DockOverlayCheckNaviCube;
+ long DockOverlayHintTriggerSize;
+ long DockOverlayHintSize;
+ long DockOverlayHintLeftLength;
+ long DockOverlayHintRightLength;
+ long DockOverlayHintTopLength;
+ long DockOverlayHintBottomLength;
+ long DockOverlayHintLeftOffset;
+ long DockOverlayHintRightOffset;
+ long DockOverlayHintTopOffset;
+ long DockOverlayHintBottomOffset;
+ bool DockOverlayHintTabBar;
+ bool DockOverlayHideTabBar;
+ long DockOverlayHintDelay;
+ long DockOverlayAnimationDuration;
+ long DockOverlayAnimationCurve;
+ bool DockOverlayHidePropertyViewScrollBar;
+ long DockOverlayMinimumSize;
+
+ // Auto generated code (Tools/params_utils.py:203)
+ OverlayParamsP() {
+ handle = App::GetApplication().GetParameterGroupByPath("User parameter:BaseApp/Preferences/View");
+ handle->Attach(this);
+
+ CornerNaviCube = handle->GetInt("CornerNaviCube", 1);
+ funcs["CornerNaviCube"] = &OverlayParamsP::updateCornerNaviCube;
+ DockOverlayAutoView = handle->GetBool("DockOverlayAutoView", true);
+ funcs["DockOverlayAutoView"] = &OverlayParamsP::updateDockOverlayAutoView;
+ DockOverlayDelay = handle->GetInt("DockOverlayDelay", 200);
+ funcs["DockOverlayDelay"] = &OverlayParamsP::updateDockOverlayDelay;
+ DockOverlayRevealDelay = handle->GetInt("DockOverlayRevealDelay", 2000);
+ funcs["DockOverlayRevealDelay"] = &OverlayParamsP::updateDockOverlayRevealDelay;
+ DockOverlaySplitterHandleTimeout = handle->GetInt("DockOverlaySplitterHandleTimeout", 0);
+ funcs["DockOverlaySplitterHandleTimeout"] = &OverlayParamsP::updateDockOverlaySplitterHandleTimeout;
+ DockOverlayActivateOnHover = handle->GetBool("DockOverlayActivateOnHover", true);
+ funcs["DockOverlayActivateOnHover"] = &OverlayParamsP::updateDockOverlayActivateOnHover;
+ DockOverlayAutoMouseThrough = handle->GetBool("DockOverlayAutoMouseThrough", true);
+ funcs["DockOverlayAutoMouseThrough"] = &OverlayParamsP::updateDockOverlayAutoMouseThrough;
+ DockOverlayWheelPassThrough = handle->GetBool("DockOverlayWheelPassThrough", true);
+ funcs["DockOverlayWheelPassThrough"] = &OverlayParamsP::updateDockOverlayWheelPassThrough;
+ DockOverlayWheelDelay = handle->GetInt("DockOverlayWheelDelay", 1000);
+ funcs["DockOverlayWheelDelay"] = &OverlayParamsP::updateDockOverlayWheelDelay;
+ DockOverlayAlphaRadius = handle->GetInt("DockOverlayAlphaRadius", 2);
+ funcs["DockOverlayAlphaRadius"] = &OverlayParamsP::updateDockOverlayAlphaRadius;
+ DockOverlayCheckNaviCube = handle->GetBool("DockOverlayCheckNaviCube", true);
+ funcs["DockOverlayCheckNaviCube"] = &OverlayParamsP::updateDockOverlayCheckNaviCube;
+ DockOverlayHintTriggerSize = handle->GetInt("DockOverlayHintTriggerSize", 16);
+ funcs["DockOverlayHintTriggerSize"] = &OverlayParamsP::updateDockOverlayHintTriggerSize;
+ DockOverlayHintSize = handle->GetInt("DockOverlayHintSize", 8);
+ funcs["DockOverlayHintSize"] = &OverlayParamsP::updateDockOverlayHintSize;
+ DockOverlayHintLeftLength = handle->GetInt("DockOverlayHintLeftLength", 100);
+ funcs["DockOverlayHintLeftLength"] = &OverlayParamsP::updateDockOverlayHintLeftLength;
+ DockOverlayHintRightLength = handle->GetInt("DockOverlayHintRightLength", 100);
+ funcs["DockOverlayHintRightLength"] = &OverlayParamsP::updateDockOverlayHintRightLength;
+ DockOverlayHintTopLength = handle->GetInt("DockOverlayHintTopLength", 100);
+ funcs["DockOverlayHintTopLength"] = &OverlayParamsP::updateDockOverlayHintTopLength;
+ DockOverlayHintBottomLength = handle->GetInt("DockOverlayHintBottomLength", 100);
+ funcs["DockOverlayHintBottomLength"] = &OverlayParamsP::updateDockOverlayHintBottomLength;
+ DockOverlayHintLeftOffset = handle->GetInt("DockOverlayHintLeftOffset", 0);
+ funcs["DockOverlayHintLeftOffset"] = &OverlayParamsP::updateDockOverlayHintLeftOffset;
+ DockOverlayHintRightOffset = handle->GetInt("DockOverlayHintRightOffset", 0);
+ funcs["DockOverlayHintRightOffset"] = &OverlayParamsP::updateDockOverlayHintRightOffset;
+ DockOverlayHintTopOffset = handle->GetInt("DockOverlayHintTopOffset", 0);
+ funcs["DockOverlayHintTopOffset"] = &OverlayParamsP::updateDockOverlayHintTopOffset;
+ DockOverlayHintBottomOffset = handle->GetInt("DockOverlayHintBottomOffset", 0);
+ funcs["DockOverlayHintBottomOffset"] = &OverlayParamsP::updateDockOverlayHintBottomOffset;
+ DockOverlayHintTabBar = handle->GetBool("DockOverlayHintTabBar", false);
+ funcs["DockOverlayHintTabBar"] = &OverlayParamsP::updateDockOverlayHintTabBar;
+ DockOverlayHideTabBar = handle->GetBool("DockOverlayHideTabBar", true);
+ funcs["DockOverlayHideTabBar"] = &OverlayParamsP::updateDockOverlayHideTabBar;
+ DockOverlayHintDelay = handle->GetInt("DockOverlayHintDelay", 200);
+ funcs["DockOverlayHintDelay"] = &OverlayParamsP::updateDockOverlayHintDelay;
+ DockOverlayAnimationDuration = handle->GetInt("DockOverlayAnimationDuration", 200);
+ funcs["DockOverlayAnimationDuration"] = &OverlayParamsP::updateDockOverlayAnimationDuration;
+ DockOverlayAnimationCurve = handle->GetInt("DockOverlayAnimationCurve", 7);
+ funcs["DockOverlayAnimationCurve"] = &OverlayParamsP::updateDockOverlayAnimationCurve;
+ DockOverlayHidePropertyViewScrollBar = handle->GetBool("DockOverlayHidePropertyViewScrollBar", false);
+ funcs["DockOverlayHidePropertyViewScrollBar"] = &OverlayParamsP::updateDockOverlayHidePropertyViewScrollBar;
+ DockOverlayMinimumSize = handle->GetInt("DockOverlayMinimumSize", 30);
+ funcs["DockOverlayMinimumSize"] = &OverlayParamsP::updateDockOverlayMinimumSize;
+ }
+
+ // Auto generated code (Tools/params_utils.py:217)
+ ~OverlayParamsP() {
+ }
+
+ // Auto generated code (Tools/params_utils.py:222)
+ void OnChange(Base::Subject &, const char* sReason) {
+ if(!sReason)
+ return;
+ auto it = funcs.find(sReason);
+ if(it == funcs.end())
+ return;
+ it->second(this);
+
+ }
+
+
+ // Auto generated code (Tools/params_utils.py:244)
+ static void updateCornerNaviCube(OverlayParamsP *self) {
+ auto v = self->handle->GetInt("CornerNaviCube", 1);
+ if (self->CornerNaviCube != v) {
+ self->CornerNaviCube = v;
+ OverlayParams::onCornerNaviCubeChanged();
+ }
+ }
+ // Auto generated code (Tools/params_utils.py:244)
+ static void updateDockOverlayAutoView(OverlayParamsP *self) {
+ auto v = self->handle->GetBool("DockOverlayAutoView", true);
+ if (self->DockOverlayAutoView != v) {
+ self->DockOverlayAutoView = v;
+ OverlayParams::onDockOverlayAutoViewChanged();
+ }
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayDelay(OverlayParamsP *self) {
+ self->DockOverlayDelay = self->handle->GetInt("DockOverlayDelay", 200);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayRevealDelay(OverlayParamsP *self) {
+ self->DockOverlayRevealDelay = self->handle->GetInt("DockOverlayRevealDelay", 2000);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlaySplitterHandleTimeout(OverlayParamsP *self) {
+ self->DockOverlaySplitterHandleTimeout = self->handle->GetInt("DockOverlaySplitterHandleTimeout", 0);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayActivateOnHover(OverlayParamsP *self) {
+ self->DockOverlayActivateOnHover = self->handle->GetBool("DockOverlayActivateOnHover", true);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayAutoMouseThrough(OverlayParamsP *self) {
+ self->DockOverlayAutoMouseThrough = self->handle->GetBool("DockOverlayAutoMouseThrough", true);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayWheelPassThrough(OverlayParamsP *self) {
+ self->DockOverlayWheelPassThrough = self->handle->GetBool("DockOverlayWheelPassThrough", true);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayWheelDelay(OverlayParamsP *self) {
+ self->DockOverlayWheelDelay = self->handle->GetInt("DockOverlayWheelDelay", 1000);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayAlphaRadius(OverlayParamsP *self) {
+ self->DockOverlayAlphaRadius = self->handle->GetInt("DockOverlayAlphaRadius", 2);
+ }
+ // Auto generated code (Tools/params_utils.py:244)
+ static void updateDockOverlayCheckNaviCube(OverlayParamsP *self) {
+ auto v = self->handle->GetBool("DockOverlayCheckNaviCube", true);
+ if (self->DockOverlayCheckNaviCube != v) {
+ self->DockOverlayCheckNaviCube = v;
+ OverlayParams::onDockOverlayCheckNaviCubeChanged();
+ }
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHintTriggerSize(OverlayParamsP *self) {
+ self->DockOverlayHintTriggerSize = self->handle->GetInt("DockOverlayHintTriggerSize", 16);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHintSize(OverlayParamsP *self) {
+ self->DockOverlayHintSize = self->handle->GetInt("DockOverlayHintSize", 8);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHintLeftLength(OverlayParamsP *self) {
+ self->DockOverlayHintLeftLength = self->handle->GetInt("DockOverlayHintLeftLength", 100);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHintRightLength(OverlayParamsP *self) {
+ self->DockOverlayHintRightLength = self->handle->GetInt("DockOverlayHintRightLength", 100);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHintTopLength(OverlayParamsP *self) {
+ self->DockOverlayHintTopLength = self->handle->GetInt("DockOverlayHintTopLength", 100);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHintBottomLength(OverlayParamsP *self) {
+ self->DockOverlayHintBottomLength = self->handle->GetInt("DockOverlayHintBottomLength", 100);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHintLeftOffset(OverlayParamsP *self) {
+ self->DockOverlayHintLeftOffset = self->handle->GetInt("DockOverlayHintLeftOffset", 0);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHintRightOffset(OverlayParamsP *self) {
+ self->DockOverlayHintRightOffset = self->handle->GetInt("DockOverlayHintRightOffset", 0);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHintTopOffset(OverlayParamsP *self) {
+ self->DockOverlayHintTopOffset = self->handle->GetInt("DockOverlayHintTopOffset", 0);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHintBottomOffset(OverlayParamsP *self) {
+ self->DockOverlayHintBottomOffset = self->handle->GetInt("DockOverlayHintBottomOffset", 0);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHintTabBar(OverlayParamsP *self) {
+ self->DockOverlayHintTabBar = self->handle->GetBool("DockOverlayHintTabBar", false);
+ }
+ // Auto generated code (Tools/params_utils.py:244)
+ static void updateDockOverlayHideTabBar(OverlayParamsP *self) {
+ auto v = self->handle->GetBool("DockOverlayHideTabBar", true);
+ if (self->DockOverlayHideTabBar != v) {
+ self->DockOverlayHideTabBar = v;
+ OverlayParams::onDockOverlayHideTabBarChanged();
+ }
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHintDelay(OverlayParamsP *self) {
+ self->DockOverlayHintDelay = self->handle->GetInt("DockOverlayHintDelay", 200);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayAnimationDuration(OverlayParamsP *self) {
+ self->DockOverlayAnimationDuration = self->handle->GetInt("DockOverlayAnimationDuration", 200);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayAnimationCurve(OverlayParamsP *self) {
+ self->DockOverlayAnimationCurve = self->handle->GetInt("DockOverlayAnimationCurve", 7);
+ }
+ // Auto generated code (Tools/params_utils.py:238)
+ static void updateDockOverlayHidePropertyViewScrollBar(OverlayParamsP *self) {
+ self->DockOverlayHidePropertyViewScrollBar = self->handle->GetBool("DockOverlayHidePropertyViewScrollBar", false);
+ }
+ // Auto generated code (Tools/params_utils.py:244)
+ static void updateDockOverlayMinimumSize(OverlayParamsP *self) {
+ auto v = self->handle->GetInt("DockOverlayMinimumSize", 30);
+ if (self->DockOverlayMinimumSize != v) {
+ self->DockOverlayMinimumSize = v;
+ OverlayParams::onDockOverlayMinimumSizeChanged();
+ }
+ }
+};
+
+// Auto generated code (Tools/params_utils.py:256)
+OverlayParamsP *instance() {
+ static OverlayParamsP *inst = new OverlayParamsP;
+ return inst;
+}
+
+} // Anonymous namespace
+
+// Auto generated code (Tools/params_utils.py:265)
+ParameterGrp::handle OverlayParams::getHandle() {
+ return instance()->handle;
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docCornerNaviCube() {
+ return "";
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getCornerNaviCube() {
+ return instance()->CornerNaviCube;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultCornerNaviCube() {
+ const static long def = 1;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setCornerNaviCube(const long &v) {
+ instance()->handle->SetInt("CornerNaviCube",v);
+ instance()->CornerNaviCube = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeCornerNaviCube() {
+ instance()->handle->RemoveInt("CornerNaviCube");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayAutoView() {
+ return "";
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const bool & OverlayParams::getDockOverlayAutoView() {
+ return instance()->DockOverlayAutoView;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const bool & OverlayParams::defaultDockOverlayAutoView() {
+ const static bool def = true;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayAutoView(const bool &v) {
+ instance()->handle->SetBool("DockOverlayAutoView",v);
+ instance()->DockOverlayAutoView = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayAutoView() {
+ instance()->handle->RemoveBool("DockOverlayAutoView");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayDelay() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Overlay dock (re),layout delay.");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayDelay() {
+ return instance()->DockOverlayDelay;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayDelay() {
+ const static long def = 200;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayDelay(const long &v) {
+ instance()->handle->SetInt("DockOverlayDelay",v);
+ instance()->DockOverlayDelay = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayDelay() {
+ instance()->handle->RemoveInt("DockOverlayDelay");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayRevealDelay() {
+ return "";
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayRevealDelay() {
+ return instance()->DockOverlayRevealDelay;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayRevealDelay() {
+ const static long def = 2000;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayRevealDelay(const long &v) {
+ instance()->handle->SetInt("DockOverlayRevealDelay",v);
+ instance()->DockOverlayRevealDelay = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayRevealDelay() {
+ instance()->handle->RemoveInt("DockOverlayRevealDelay");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlaySplitterHandleTimeout() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Overlay splitter handle auto hide delay. Set zero to disable auto hiding.");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlaySplitterHandleTimeout() {
+ return instance()->DockOverlaySplitterHandleTimeout;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlaySplitterHandleTimeout() {
+ const static long def = 0;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlaySplitterHandleTimeout(const long &v) {
+ instance()->handle->SetInt("DockOverlaySplitterHandleTimeout",v);
+ instance()->DockOverlaySplitterHandleTimeout = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlaySplitterHandleTimeout() {
+ instance()->handle->RemoveInt("DockOverlaySplitterHandleTimeout");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayActivateOnHover() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Show auto hidden dock overlay on mouse over.\n"
+"If disabled, then show on mouse click.");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const bool & OverlayParams::getDockOverlayActivateOnHover() {
+ return instance()->DockOverlayActivateOnHover;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const bool & OverlayParams::defaultDockOverlayActivateOnHover() {
+ const static bool def = true;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayActivateOnHover(const bool &v) {
+ instance()->handle->SetBool("DockOverlayActivateOnHover",v);
+ instance()->DockOverlayActivateOnHover = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayActivateOnHover() {
+ instance()->handle->RemoveBool("DockOverlayActivateOnHover");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayAutoMouseThrough() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto mouse click through transparent part of dock overlay.");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const bool & OverlayParams::getDockOverlayAutoMouseThrough() {
+ return instance()->DockOverlayAutoMouseThrough;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const bool & OverlayParams::defaultDockOverlayAutoMouseThrough() {
+ const static bool def = true;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayAutoMouseThrough(const bool &v) {
+ instance()->handle->SetBool("DockOverlayAutoMouseThrough",v);
+ instance()->DockOverlayAutoMouseThrough = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayAutoMouseThrough() {
+ instance()->handle->RemoveBool("DockOverlayAutoMouseThrough");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayWheelPassThrough() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto pass through mouse wheel event on transparent dock overlay.");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const bool & OverlayParams::getDockOverlayWheelPassThrough() {
+ return instance()->DockOverlayWheelPassThrough;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const bool & OverlayParams::defaultDockOverlayWheelPassThrough() {
+ const static bool def = true;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayWheelPassThrough(const bool &v) {
+ instance()->handle->SetBool("DockOverlayWheelPassThrough",v);
+ instance()->DockOverlayWheelPassThrough = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayWheelPassThrough() {
+ instance()->handle->RemoveBool("DockOverlayWheelPassThrough");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayWheelDelay() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Delay capturing mouse wheel event for passing through if it is\n"
+"previously handled by other widget.");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayWheelDelay() {
+ return instance()->DockOverlayWheelDelay;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayWheelDelay() {
+ const static long def = 1000;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayWheelDelay(const long &v) {
+ instance()->handle->SetInt("DockOverlayWheelDelay",v);
+ instance()->DockOverlayWheelDelay = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayWheelDelay() {
+ instance()->handle->RemoveInt("DockOverlayWheelDelay");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayAlphaRadius() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"If auto mouse click through is enabled, then this radius\n"
+"defines a region of alpha test under the mouse cursor.\n"
+"Auto click through is only activated if all pixels within\n"
+"the region are non-opaque.");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayAlphaRadius() {
+ return instance()->DockOverlayAlphaRadius;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayAlphaRadius() {
+ const static long def = 2;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayAlphaRadius(const long &v) {
+ instance()->handle->SetInt("DockOverlayAlphaRadius",v);
+ instance()->DockOverlayAlphaRadius = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayAlphaRadius() {
+ instance()->handle->RemoveInt("DockOverlayAlphaRadius");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayCheckNaviCube() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Leave space for Navigation Cube in dock overlay");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const bool & OverlayParams::getDockOverlayCheckNaviCube() {
+ return instance()->DockOverlayCheckNaviCube;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const bool & OverlayParams::defaultDockOverlayCheckNaviCube() {
+ const static bool def = true;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayCheckNaviCube(const bool &v) {
+ instance()->handle->SetBool("DockOverlayCheckNaviCube",v);
+ instance()->DockOverlayCheckNaviCube = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayCheckNaviCube() {
+ instance()->handle->RemoveBool("DockOverlayCheckNaviCube");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHintTriggerSize() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto hide hint visual display triggering width");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayHintTriggerSize() {
+ return instance()->DockOverlayHintTriggerSize;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayHintTriggerSize() {
+ const static long def = 16;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHintTriggerSize(const long &v) {
+ instance()->handle->SetInt("DockOverlayHintTriggerSize",v);
+ instance()->DockOverlayHintTriggerSize = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHintTriggerSize() {
+ instance()->handle->RemoveInt("DockOverlayHintTriggerSize");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHintSize() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto hide hint visual display width");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayHintSize() {
+ return instance()->DockOverlayHintSize;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayHintSize() {
+ const static long def = 8;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHintSize(const long &v) {
+ instance()->handle->SetInt("DockOverlayHintSize",v);
+ instance()->DockOverlayHintSize = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHintSize() {
+ instance()->handle->RemoveInt("DockOverlayHintSize");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHintLeftLength() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto hide hint visual display length for left panel. Set to zero to fill the space.");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayHintLeftLength() {
+ return instance()->DockOverlayHintLeftLength;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayHintLeftLength() {
+ const static long def = 100;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHintLeftLength(const long &v) {
+ instance()->handle->SetInt("DockOverlayHintLeftLength",v);
+ instance()->DockOverlayHintLeftLength = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHintLeftLength() {
+ instance()->handle->RemoveInt("DockOverlayHintLeftLength");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHintRightLength() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto hide hint visual display length for right panel. Set to zero to fill the space.");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayHintRightLength() {
+ return instance()->DockOverlayHintRightLength;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayHintRightLength() {
+ const static long def = 100;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHintRightLength(const long &v) {
+ instance()->handle->SetInt("DockOverlayHintRightLength",v);
+ instance()->DockOverlayHintRightLength = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHintRightLength() {
+ instance()->handle->RemoveInt("DockOverlayHintRightLength");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHintTopLength() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto hide hint visual display length for top panel. Set to zero to fill the space.");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayHintTopLength() {
+ return instance()->DockOverlayHintTopLength;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayHintTopLength() {
+ const static long def = 100;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHintTopLength(const long &v) {
+ instance()->handle->SetInt("DockOverlayHintTopLength",v);
+ instance()->DockOverlayHintTopLength = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHintTopLength() {
+ instance()->handle->RemoveInt("DockOverlayHintTopLength");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHintBottomLength() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto hide hint visual display length for bottom panel. Set to zero to fill the space.");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayHintBottomLength() {
+ return instance()->DockOverlayHintBottomLength;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayHintBottomLength() {
+ const static long def = 100;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHintBottomLength(const long &v) {
+ instance()->handle->SetInt("DockOverlayHintBottomLength",v);
+ instance()->DockOverlayHintBottomLength = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHintBottomLength() {
+ instance()->handle->RemoveInt("DockOverlayHintBottomLength");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHintLeftOffset() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto hide hint visual display offset for left panel");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayHintLeftOffset() {
+ return instance()->DockOverlayHintLeftOffset;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayHintLeftOffset() {
+ const static long def = 0;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHintLeftOffset(const long &v) {
+ instance()->handle->SetInt("DockOverlayHintLeftOffset",v);
+ instance()->DockOverlayHintLeftOffset = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHintLeftOffset() {
+ instance()->handle->RemoveInt("DockOverlayHintLeftOffset");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHintRightOffset() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto hide hint visual display offset for right panel");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayHintRightOffset() {
+ return instance()->DockOverlayHintRightOffset;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayHintRightOffset() {
+ const static long def = 0;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHintRightOffset(const long &v) {
+ instance()->handle->SetInt("DockOverlayHintRightOffset",v);
+ instance()->DockOverlayHintRightOffset = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHintRightOffset() {
+ instance()->handle->RemoveInt("DockOverlayHintRightOffset");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHintTopOffset() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto hide hint visual display offset for top panel");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayHintTopOffset() {
+ return instance()->DockOverlayHintTopOffset;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayHintTopOffset() {
+ const static long def = 0;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHintTopOffset(const long &v) {
+ instance()->handle->SetInt("DockOverlayHintTopOffset",v);
+ instance()->DockOverlayHintTopOffset = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHintTopOffset() {
+ instance()->handle->RemoveInt("DockOverlayHintTopOffset");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHintBottomOffset() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto hide hint visual display offset for bottom panel");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayHintBottomOffset() {
+ return instance()->DockOverlayHintBottomOffset;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayHintBottomOffset() {
+ const static long def = 0;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHintBottomOffset(const long &v) {
+ instance()->handle->SetInt("DockOverlayHintBottomOffset",v);
+ instance()->DockOverlayHintBottomOffset = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHintBottomOffset() {
+ instance()->handle->RemoveInt("DockOverlayHintBottomOffset");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHintTabBar() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Show tab bar on mouse over when auto hide");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const bool & OverlayParams::getDockOverlayHintTabBar() {
+ return instance()->DockOverlayHintTabBar;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const bool & OverlayParams::defaultDockOverlayHintTabBar() {
+ const static bool def = false;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHintTabBar(const bool &v) {
+ instance()->handle->SetBool("DockOverlayHintTabBar",v);
+ instance()->DockOverlayHintTabBar = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHintTabBar() {
+ instance()->handle->RemoveBool("DockOverlayHintTabBar");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHideTabBar() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Hide tab bar in dock overlay");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const bool & OverlayParams::getDockOverlayHideTabBar() {
+ return instance()->DockOverlayHideTabBar;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const bool & OverlayParams::defaultDockOverlayHideTabBar() {
+ const static bool def = true;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHideTabBar(const bool &v) {
+ instance()->handle->SetBool("DockOverlayHideTabBar",v);
+ instance()->DockOverlayHideTabBar = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHideTabBar() {
+ instance()->handle->RemoveBool("DockOverlayHideTabBar");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHintDelay() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Delay before show hint visual");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayHintDelay() {
+ return instance()->DockOverlayHintDelay;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayHintDelay() {
+ const static long def = 200;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHintDelay(const long &v) {
+ instance()->handle->SetInt("DockOverlayHintDelay",v);
+ instance()->DockOverlayHintDelay = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHintDelay() {
+ instance()->handle->RemoveInt("DockOverlayHintDelay");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayAnimationDuration() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto hide animation duration, 0 to disable");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayAnimationDuration() {
+ return instance()->DockOverlayAnimationDuration;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayAnimationDuration() {
+ const static long def = 200;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayAnimationDuration(const long &v) {
+ instance()->handle->SetInt("DockOverlayAnimationDuration",v);
+ instance()->DockOverlayAnimationDuration = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayAnimationDuration() {
+ instance()->handle->RemoveInt("DockOverlayAnimationDuration");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayAnimationCurve() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Auto hide animation curve type");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayAnimationCurve() {
+ return instance()->DockOverlayAnimationCurve;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayAnimationCurve() {
+ const static long def = 7;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayAnimationCurve(const long &v) {
+ instance()->handle->SetInt("DockOverlayAnimationCurve",v);
+ instance()->DockOverlayAnimationCurve = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayAnimationCurve() {
+ instance()->handle->RemoveInt("DockOverlayAnimationCurve");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayHidePropertyViewScrollBar() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Hide property view scroll bar in dock overlay");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const bool & OverlayParams::getDockOverlayHidePropertyViewScrollBar() {
+ return instance()->DockOverlayHidePropertyViewScrollBar;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const bool & OverlayParams::defaultDockOverlayHidePropertyViewScrollBar() {
+ const static bool def = false;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayHidePropertyViewScrollBar(const bool &v) {
+ instance()->handle->SetBool("DockOverlayHidePropertyViewScrollBar",v);
+ instance()->DockOverlayHidePropertyViewScrollBar = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayHidePropertyViewScrollBar() {
+ instance()->handle->RemoveBool("DockOverlayHidePropertyViewScrollBar");
+}
+
+// Auto generated code (Tools/params_utils.py:288)
+const char *OverlayParams::docDockOverlayMinimumSize() {
+ return QT_TRANSLATE_NOOP("OverlayParams",
+"Minimum overlay dock widget width/height");
+}
+
+// Auto generated code (Tools/params_utils.py:294)
+const long & OverlayParams::getDockOverlayMinimumSize() {
+ return instance()->DockOverlayMinimumSize;
+}
+
+// Auto generated code (Tools/params_utils.py:300)
+const long & OverlayParams::defaultDockOverlayMinimumSize() {
+ const static long def = 30;
+ return def;
+}
+
+// Auto generated code (Tools/params_utils.py:307)
+void OverlayParams::setDockOverlayMinimumSize(const long &v) {
+ instance()->handle->SetInt("DockOverlayMinimumSize",v);
+ instance()->DockOverlayMinimumSize = v;
+}
+
+// Auto generated code (Tools/params_utils.py:314)
+void OverlayParams::removeDockOverlayMinimumSize() {
+ instance()->handle->RemoveInt("DockOverlayMinimumSize");
+}
+
+// Auto generated code (Gui/OverlayParams.py:172)
+const std::vector OverlayParams::AnimationCurveTypes = {
+ QStringLiteral("Linear"),
+ QStringLiteral("InQuad"),
+ QStringLiteral("OutQuad"),
+ QStringLiteral("InOutQuad"),
+ QStringLiteral("OutInQuad"),
+ QStringLiteral("InCubic"),
+ QStringLiteral("OutCubic"),
+ QStringLiteral("InOutCubic"),
+ QStringLiteral("OutInCubic"),
+ QStringLiteral("InQuart"),
+ QStringLiteral("OutQuart"),
+ QStringLiteral("InOutQuart"),
+ QStringLiteral("OutInQuart"),
+ QStringLiteral("InQuint"),
+ QStringLiteral("OutQuint"),
+ QStringLiteral("InOutQuint"),
+ QStringLiteral("OutInQuint"),
+ QStringLiteral("InSine"),
+ QStringLiteral("OutSine"),
+ QStringLiteral("InOutSine"),
+ QStringLiteral("OutInSine"),
+ QStringLiteral("InExpo"),
+ QStringLiteral("OutExpo"),
+ QStringLiteral("InOutExpo"),
+ QStringLiteral("OutInExpo"),
+ QStringLiteral("InCirc"),
+ QStringLiteral("OutCirc"),
+ QStringLiteral("InOutCirc"),
+ QStringLiteral("OutInCirc"),
+ QStringLiteral("InElastic"),
+ QStringLiteral("OutElastic"),
+ QStringLiteral("InOutElastic"),
+ QStringLiteral("OutInElastic"),
+ QStringLiteral("InBack"),
+ QStringLiteral("OutBack"),
+ QStringLiteral("InOutBack"),
+ QStringLiteral("OutInBack"),
+ QStringLiteral("InBounce"),
+ QStringLiteral("OutBounce"),
+ QStringLiteral("InOutBounce"),
+ QStringLiteral("OutInBounce"),
+};
+//[[[end]]]
+
+void OverlayParams::onDockOverlayAutoViewChanged() {
+ OverlayManager::instance()->refresh();
+}
+
+void OverlayParams::onCornerNaviCubeChanged() {
+ OverlayManager::instance()->refresh();
+}
+
+void OverlayParams::onDockOverlayCheckNaviCubeChanged() {
+ OverlayManager::instance()->refresh();
+}
+
+void OverlayParams::onDockOverlayHideTabBarChanged() {
+ OverlayManager::instance()->refresh(nullptr, true);
+}
+
+void OverlayParams::onDockOverlayMinimumSizeChanged() {
+ OverlayManager::instance()->refresh();
+}
+
diff --git a/src/Gui/OverlayParams.h b/src/Gui/OverlayParams.h
new file mode 100644
index 0000000000..461d082863
--- /dev/null
+++ b/src/Gui/OverlayParams.h
@@ -0,0 +1,422 @@
+/****************************************************************************
+ * Copyright (c) 2022 Zheng Lei (realthunder) *
+ * *
+ * 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_OVERLAY_PARAMS_H
+#define GUI_OVERLAY_PARAMS_H
+
+/*[[[cog
+import OverlayParams
+OverlayParams.declare()
+]]]*/
+
+// Auto generated code (Gui/OverlayParams.py:158)
+#include
+
+// Auto generated code (Tools/params_utils.py:72)
+#include
+
+
+// Auto generated code (Tools/params_utils.py:78)
+namespace Gui {
+/** Convenient class to obtain overlay widgets related parameters
+
+ * The parameters are under group "User parameter:BaseApp/Preferences/View"
+ *
+ * This class is auto generated by Gui/OverlayParams.py. Modify that file
+ * instead of this one, if you want to add any parameter. You need
+ * to install Cog Python package for code generation:
+ * @code
+ * pip install cogapp
+ * @endcode
+ *
+ * Once modified, you can regenerate the header and the source file,
+ * @code
+ * python3 -m cogapp -r Gui/OverlayParams.h Gui/OverlayParams.cpp
+ * @endcode
+ *
+ * You can add a new parameter by adding lines in Gui/OverlayParams.py. Available
+ * parameter types are 'Int, UInt, String, Bool, Float'. For example, to add
+ * a new Int type parameter,
+ * @code
+ * ParamInt(parameter_name, default_value, documentation, on_change=False)
+ * @endcode
+ *
+ * If there is special handling on parameter change, pass in on_change=True.
+ * And you need to provide a function implementation in Gui/OverlayParams.cpp with
+ * the following signature.
+ * @code
+ * void OverlayParams:onChanged()
+ * @endcode
+ */
+class GuiExport OverlayParams {
+public:
+ static ParameterGrp::handle getHandle();
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter CornerNaviCube
+ static const long & getCornerNaviCube();
+ static const long & defaultCornerNaviCube();
+ static void removeCornerNaviCube();
+ static void setCornerNaviCube(const long &v);
+ static const char *docCornerNaviCube();
+ static void onCornerNaviCubeChanged();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayAutoView
+ static const bool & getDockOverlayAutoView();
+ static const bool & defaultDockOverlayAutoView();
+ static void removeDockOverlayAutoView();
+ static void setDockOverlayAutoView(const bool &v);
+ static const char *docDockOverlayAutoView();
+ static void onDockOverlayAutoViewChanged();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayDelay
+ ///
+ /// Overlay dock (re),layout delay.
+ static const long & getDockOverlayDelay();
+ static const long & defaultDockOverlayDelay();
+ static void removeDockOverlayDelay();
+ static void setDockOverlayDelay(const long &v);
+ static const char *docDockOverlayDelay();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayRevealDelay
+ static const long & getDockOverlayRevealDelay();
+ static const long & defaultDockOverlayRevealDelay();
+ static void removeDockOverlayRevealDelay();
+ static void setDockOverlayRevealDelay(const long &v);
+ static const char *docDockOverlayRevealDelay();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlaySplitterHandleTimeout
+ ///
+ /// Overlay splitter handle auto hide delay. Set zero to disable auto hiding.
+ static const long & getDockOverlaySplitterHandleTimeout();
+ static const long & defaultDockOverlaySplitterHandleTimeout();
+ static void removeDockOverlaySplitterHandleTimeout();
+ static void setDockOverlaySplitterHandleTimeout(const long &v);
+ static const char *docDockOverlaySplitterHandleTimeout();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayActivateOnHover
+ ///
+ /// Show auto hidden dock overlay on mouse over.
+ /// If disabled, then show on mouse click.
+ static const bool & getDockOverlayActivateOnHover();
+ static const bool & defaultDockOverlayActivateOnHover();
+ static void removeDockOverlayActivateOnHover();
+ static void setDockOverlayActivateOnHover(const bool &v);
+ static const char *docDockOverlayActivateOnHover();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayAutoMouseThrough
+ ///
+ /// Auto mouse click through transparent part of dock overlay.
+ static const bool & getDockOverlayAutoMouseThrough();
+ static const bool & defaultDockOverlayAutoMouseThrough();
+ static void removeDockOverlayAutoMouseThrough();
+ static void setDockOverlayAutoMouseThrough(const bool &v);
+ static const char *docDockOverlayAutoMouseThrough();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayWheelPassThrough
+ ///
+ /// Auto pass through mouse wheel event on transparent dock overlay.
+ static const bool & getDockOverlayWheelPassThrough();
+ static const bool & defaultDockOverlayWheelPassThrough();
+ static void removeDockOverlayWheelPassThrough();
+ static void setDockOverlayWheelPassThrough(const bool &v);
+ static const char *docDockOverlayWheelPassThrough();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayWheelDelay
+ ///
+ /// Delay capturing mouse wheel event for passing through if it is
+ /// previously handled by other widget.
+ static const long & getDockOverlayWheelDelay();
+ static const long & defaultDockOverlayWheelDelay();
+ static void removeDockOverlayWheelDelay();
+ static void setDockOverlayWheelDelay(const long &v);
+ static const char *docDockOverlayWheelDelay();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayAlphaRadius
+ ///
+ /// If auto mouse click through is enabled, then this radius
+ /// defines a region of alpha test under the mouse cursor.
+ /// Auto click through is only activated if all pixels within
+ /// the region are non-opaque.
+ static const long & getDockOverlayAlphaRadius();
+ static const long & defaultDockOverlayAlphaRadius();
+ static void removeDockOverlayAlphaRadius();
+ static void setDockOverlayAlphaRadius(const long &v);
+ static const char *docDockOverlayAlphaRadius();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayCheckNaviCube
+ ///
+ /// Leave space for Navigation Cube in dock overlay
+ static const bool & getDockOverlayCheckNaviCube();
+ static const bool & defaultDockOverlayCheckNaviCube();
+ static void removeDockOverlayCheckNaviCube();
+ static void setDockOverlayCheckNaviCube(const bool &v);
+ static const char *docDockOverlayCheckNaviCube();
+ static void onDockOverlayCheckNaviCubeChanged();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHintTriggerSize
+ ///
+ /// Auto hide hint visual display triggering width
+ static const long & getDockOverlayHintTriggerSize();
+ static const long & defaultDockOverlayHintTriggerSize();
+ static void removeDockOverlayHintTriggerSize();
+ static void setDockOverlayHintTriggerSize(const long &v);
+ static const char *docDockOverlayHintTriggerSize();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHintSize
+ ///
+ /// Auto hide hint visual display width
+ static const long & getDockOverlayHintSize();
+ static const long & defaultDockOverlayHintSize();
+ static void removeDockOverlayHintSize();
+ static void setDockOverlayHintSize(const long &v);
+ static const char *docDockOverlayHintSize();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHintLeftLength
+ ///
+ /// Auto hide hint visual display length for left panel. Set to zero to fill the space.
+ static const long & getDockOverlayHintLeftLength();
+ static const long & defaultDockOverlayHintLeftLength();
+ static void removeDockOverlayHintLeftLength();
+ static void setDockOverlayHintLeftLength(const long &v);
+ static const char *docDockOverlayHintLeftLength();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHintRightLength
+ ///
+ /// Auto hide hint visual display length for right panel. Set to zero to fill the space.
+ static const long & getDockOverlayHintRightLength();
+ static const long & defaultDockOverlayHintRightLength();
+ static void removeDockOverlayHintRightLength();
+ static void setDockOverlayHintRightLength(const long &v);
+ static const char *docDockOverlayHintRightLength();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHintTopLength
+ ///
+ /// Auto hide hint visual display length for top panel. Set to zero to fill the space.
+ static const long & getDockOverlayHintTopLength();
+ static const long & defaultDockOverlayHintTopLength();
+ static void removeDockOverlayHintTopLength();
+ static void setDockOverlayHintTopLength(const long &v);
+ static const char *docDockOverlayHintTopLength();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHintBottomLength
+ ///
+ /// Auto hide hint visual display length for bottom panel. Set to zero to fill the space.
+ static const long & getDockOverlayHintBottomLength();
+ static const long & defaultDockOverlayHintBottomLength();
+ static void removeDockOverlayHintBottomLength();
+ static void setDockOverlayHintBottomLength(const long &v);
+ static const char *docDockOverlayHintBottomLength();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHintLeftOffset
+ ///
+ /// Auto hide hint visual display offset for left panel
+ static const long & getDockOverlayHintLeftOffset();
+ static const long & defaultDockOverlayHintLeftOffset();
+ static void removeDockOverlayHintLeftOffset();
+ static void setDockOverlayHintLeftOffset(const long &v);
+ static const char *docDockOverlayHintLeftOffset();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHintRightOffset
+ ///
+ /// Auto hide hint visual display offset for right panel
+ static const long & getDockOverlayHintRightOffset();
+ static const long & defaultDockOverlayHintRightOffset();
+ static void removeDockOverlayHintRightOffset();
+ static void setDockOverlayHintRightOffset(const long &v);
+ static const char *docDockOverlayHintRightOffset();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHintTopOffset
+ ///
+ /// Auto hide hint visual display offset for top panel
+ static const long & getDockOverlayHintTopOffset();
+ static const long & defaultDockOverlayHintTopOffset();
+ static void removeDockOverlayHintTopOffset();
+ static void setDockOverlayHintTopOffset(const long &v);
+ static const char *docDockOverlayHintTopOffset();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHintBottomOffset
+ ///
+ /// Auto hide hint visual display offset for bottom panel
+ static const long & getDockOverlayHintBottomOffset();
+ static const long & defaultDockOverlayHintBottomOffset();
+ static void removeDockOverlayHintBottomOffset();
+ static void setDockOverlayHintBottomOffset(const long &v);
+ static const char *docDockOverlayHintBottomOffset();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHintTabBar
+ ///
+ /// Show tab bar on mouse over when auto hide
+ static const bool & getDockOverlayHintTabBar();
+ static const bool & defaultDockOverlayHintTabBar();
+ static void removeDockOverlayHintTabBar();
+ static void setDockOverlayHintTabBar(const bool &v);
+ static const char *docDockOverlayHintTabBar();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHideTabBar
+ ///
+ /// Hide tab bar in dock overlay
+ static const bool & getDockOverlayHideTabBar();
+ static const bool & defaultDockOverlayHideTabBar();
+ static void removeDockOverlayHideTabBar();
+ static void setDockOverlayHideTabBar(const bool &v);
+ static const char *docDockOverlayHideTabBar();
+ static void onDockOverlayHideTabBarChanged();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHintDelay
+ ///
+ /// Delay before show hint visual
+ static const long & getDockOverlayHintDelay();
+ static const long & defaultDockOverlayHintDelay();
+ static void removeDockOverlayHintDelay();
+ static void setDockOverlayHintDelay(const long &v);
+ static const char *docDockOverlayHintDelay();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayAnimationDuration
+ ///
+ /// Auto hide animation duration, 0 to disable
+ static const long & getDockOverlayAnimationDuration();
+ static const long & defaultDockOverlayAnimationDuration();
+ static void removeDockOverlayAnimationDuration();
+ static void setDockOverlayAnimationDuration(const long &v);
+ static const char *docDockOverlayAnimationDuration();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayAnimationCurve
+ ///
+ /// Auto hide animation curve type
+ static const long & getDockOverlayAnimationCurve();
+ static const long & defaultDockOverlayAnimationCurve();
+ static void removeDockOverlayAnimationCurve();
+ static void setDockOverlayAnimationCurve(const long &v);
+ static const char *docDockOverlayAnimationCurve();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayHidePropertyViewScrollBar
+ ///
+ /// Hide property view scroll bar in dock overlay
+ static const bool & getDockOverlayHidePropertyViewScrollBar();
+ static const bool & defaultDockOverlayHidePropertyViewScrollBar();
+ static void removeDockOverlayHidePropertyViewScrollBar();
+ static void setDockOverlayHidePropertyViewScrollBar(const bool &v);
+ static const char *docDockOverlayHidePropertyViewScrollBar();
+ //@}
+
+ // Auto generated code (Tools/params_utils.py:122)
+ //@{
+ /// Accessor for parameter DockOverlayMinimumSize
+ ///
+ /// Minimum overlay dock widget width/height
+ static const long & getDockOverlayMinimumSize();
+ static const long & defaultDockOverlayMinimumSize();
+ static void removeDockOverlayMinimumSize();
+ static void setDockOverlayMinimumSize(const long &v);
+ static const char *docDockOverlayMinimumSize();
+ static void onDockOverlayMinimumSizeChanged();
+ //@}
+
+ // Auto generated code (Gui/OverlayParams.py:164)
+ static const std::vector AnimationCurveTypes;
+
+// Auto generated code (Tools/params_utils.py:150)
+}; // class OverlayParams
+} // namespace Gui
+//[[[end]]]
+
+#endif // GUI_OVERLAY_PARAMS_H
diff --git a/src/Gui/OverlayParams.py b/src/Gui/OverlayParams.py
new file mode 100644
index 0000000000..33e731ff19
--- /dev/null
+++ b/src/Gui/OverlayParams.py
@@ -0,0 +1,182 @@
+# -*- coding: utf-8 -*-
+# ***************************************************************************
+# * Copyright (c) 2022 Zheng Lei (realthunder) *
+# * *
+# * This program is free software; you can redistribute it and/or modify *
+# * it under the terms of the GNU Lesser General Public License (LGPL) *
+# * as published by the Free Software Foundation; either version 2 of *
+# * the License, or (at your option) any later version. *
+# * for detail see the LICENCE text file. *
+# * *
+# * This program 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 program; if not, write to the Free Software *
+# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+# * USA *
+# * *
+# ***************************************************************************
+'''Auto code generator for overlay widgets related parameters in Preferences/View
+'''
+import cog
+import inspect, sys
+from os import sys, path
+
+# import Tools/params_utils.py
+sys.path.append(path.join(path.dirname(path.dirname(path.abspath(__file__))), 'Tools'))
+import params_utils
+
+from params_utils import ParamBool, ParamInt, ParamString, ParamUInt, ParamHex, \
+ ParamFloat, ParamProxy, ParamLinePattern, ParamFile, \
+ ParamComboBox, ParamColor, ParamSpinBox, auto_comment
+
+NameSpace = 'Gui'
+ClassName = 'OverlayParams'
+ParamPath = 'User parameter:BaseApp/Preferences/View'
+ClassDoc = 'Convenient class to obtain overlay widgets related parameters'
+
+AnimationCurveTypes = (
+ "Linear",
+ "InQuad",
+ "OutQuad",
+ "InOutQuad",
+ "OutInQuad",
+ "InCubic",
+ "OutCubic",
+ "InOutCubic",
+ "OutInCubic",
+ "InQuart",
+ "OutQuart",
+ "InOutQuart",
+ "OutInQuart",
+ "InQuint",
+ "OutQuint",
+ "InOutQuint",
+ "OutInQuint",
+ "InSine",
+ "OutSine",
+ "InOutSine",
+ "OutInSine",
+ "InExpo",
+ "OutExpo",
+ "InOutExpo",
+ "OutInExpo",
+ "InCirc",
+ "OutCirc",
+ "InOutCirc",
+ "OutInCirc",
+ "InElastic",
+ "OutElastic",
+ "InOutElastic",
+ "OutInElastic",
+ "InBack",
+ "OutBack",
+ "InOutBack",
+ "OutInBack",
+ "InBounce",
+ "OutBounce",
+ "InOutBounce",
+ "OutInBounce",
+)
+
+class ParamAnimationCurve(ParamProxy):
+ WidgetType = 'Gui::PrefComboBox'
+
+ def widget_setter(self, _param):
+ return None
+
+ def init_widget(self, param, row, group_name):
+ super().init_widget(param, row, group_name)
+ cog.out(f'''
+ {auto_comment()}
+ for (const auto &item : OverlayParams::AnimationCurveTypes)
+ {param.widget_name}->addItem(item);''')
+ cog.out(f'''
+ {param.widget_name}->setCurrentIndex({param.namespace}::{param.class_name}::default{param.name}());''')
+
+Params = [
+ ParamInt('CornerNaviCube', 1, on_change=True),
+ ParamBool('DockOverlayAutoView', True, on_change=True, title="Auto hide in non 3D view"),
+ ParamInt('DockOverlayDelay', 200, "Overlay dock (re),layout delay.", title="Layout delay (ms)", proxy=ParamSpinBox(0, 5000, 100)),
+ ParamInt('DockOverlayRevealDelay', 2000),
+ ParamInt('DockOverlaySplitterHandleTimeout', 0, title="Splitter auto hide delay (ms)", proxy=ParamSpinBox(0, 99999, 100),
+ doc="Overlay splitter handle auto hide delay. Set zero to disable auto hiding."),
+ ParamBool('DockOverlayActivateOnHover', True, title="Activate on hover",
+ doc="Show auto hidden dock overlay on mouse over.\n"
+ "If disabled, then show on mouse click."),
+ ParamBool('DockOverlayAutoMouseThrough', True,
+ "Auto mouse click through transparent part of dock overlay.", title="Auto mouse pass through"),
+ ParamBool('DockOverlayWheelPassThrough', True,
+ "Auto pass through mouse wheel event on transparent dock overlay.", title="Auto mouse wheel pass through"),
+ ParamInt('DockOverlayWheelDelay', 1000, title="Delay mouse wheel pass through (ms)", proxy=ParamSpinBox(0, 99999, 1),
+ doc="Delay capturing mouse wheel event for passing through if it is\n"
+ "previously handled by other widget."),
+ ParamInt('DockOverlayAlphaRadius', 2, title="Alpha test radius", proxy=ParamSpinBox(1, 100, 1), doc=\
+ "If auto mouse click through is enabled, then this radius\n"
+ "defines a region of alpha test under the mouse cursor.\n"
+ "Auto click through is only activated if all pixels within\n"
+ "the region are non-opaque."),
+ ParamBool('DockOverlayCheckNaviCube', True, on_change=True, title="Check Navigation Cube",
+ doc="Leave space for Navigation Cube in dock overlay"),
+ ParamInt('DockOverlayHintTriggerSize', 16, title="Hint trigger size", proxy=ParamSpinBox(1, 100, 1),
+ doc="Auto hide hint visual display triggering width"),
+ ParamInt('DockOverlayHintSize', 8, title="Hint width", proxy=ParamSpinBox(1, 100, 1),
+ doc="Auto hide hint visual display width"),
+ ParamInt('DockOverlayHintLeftLength', 100, title='Left panel hint length', proxy=ParamSpinBox(0, 10000, 10),
+ doc="Auto hide hint visual display length for left panel. Set to zero to fill the space."),
+ ParamInt('DockOverlayHintRightLength', 100, title='Right panel hint length', proxy=ParamSpinBox(0, 10000, 10),
+ doc="Auto hide hint visual display length for right panel. Set to zero to fill the space."),
+ ParamInt('DockOverlayHintTopLength', 100, title='Top panel hint length', proxy=ParamSpinBox(0, 10000, 10),
+ doc="Auto hide hint visual display length for top panel. Set to zero to fill the space."),
+ ParamInt('DockOverlayHintBottomLength', 100, title='Bottom panel hint length', proxy=ParamSpinBox(0, 10000, 10),
+ doc="Auto hide hint visual display length for bottom panel. Set to zero to fill the space."),
+ ParamInt('DockOverlayHintLeftOffset', 0, title='Left panel hint offset', proxy=ParamSpinBox(0, 10000, 10),
+ doc="Auto hide hint visual display offset for left panel"),
+ ParamInt('DockOverlayHintRightOffset', 0, title='Right panel hint offset', proxy=ParamSpinBox(0, 10000, 10),
+ doc="Auto hide hint visual display offset for right panel"),
+ ParamInt('DockOverlayHintTopOffset', 0, title='Top panel hint offset', proxy=ParamSpinBox(0, 10000, 10),
+ doc="Auto hide hint visual display offset for top panel"),
+ ParamInt('DockOverlayHintBottomOffset', 0, title='Bottom panel hint offset', proxy=ParamSpinBox(0, 10000, 10),
+ doc="Auto hide hint visual display offset for bottom panel"),
+ ParamBool('DockOverlayHintTabBar', False, "Show tab bar on mouse over when auto hide", title="Hint show tab bar"),
+ ParamBool('DockOverlayHideTabBar', True, on_change=True, doc="Hide tab bar in dock overlay", title='Hide tab bar'),
+ ParamInt('DockOverlayHintDelay', 200, "Delay before show hint visual", title="Hint delay (ms)", proxy=ParamSpinBox(0, 1000, 100)),
+ ParamInt('DockOverlayAnimationDuration', 200, "Auto hide animation duration, 0 to disable",
+ title="Animation duration (ms)", proxy=ParamSpinBox(0, 5000, 100)),
+ ParamInt('DockOverlayAnimationCurve', 7, "Auto hide animation curve type", title="Animation curve type", proxy=ParamAnimationCurve()),
+ ParamBool('DockOverlayHidePropertyViewScrollBar', False, "Hide property view scroll bar in dock overlay", title="Hide property view scroll bar"),
+ ParamInt('DockOverlayMinimumSize', 30, on_change=True,
+ doc="Minimum overlay dock widget width/height",
+ title="Minimum dock widget size"),
+]
+
+def declare():
+ cog.out(f'''
+{auto_comment()}
+#include
+''')
+
+ params_utils.declare_begin(sys.modules[__name__])
+ cog.out(f'''
+ {auto_comment()}
+ static const std::vector AnimationCurveTypes;
+''')
+ params_utils.declare_end(sys.modules[__name__])
+
+def define():
+ params_utils.define(sys.modules[__name__])
+ cog.out(f'''
+{auto_comment()}
+const std::vector OverlayParams::AnimationCurveTypes = {{''')
+ for item in AnimationCurveTypes:
+ cog.out(f'''
+ QStringLiteral("{item}"),''')
+ cog.out(f'''
+}};
+''')
+
+
+params_utils.init_params(Params, NameSpace, ClassName, ParamPath)
diff --git a/src/Gui/OverlayWidgets.cpp b/src/Gui/OverlayWidgets.cpp
new file mode 100644
index 0000000000..9144cc0b63
--- /dev/null
+++ b/src/Gui/OverlayWidgets.cpp
@@ -0,0 +1,2487 @@
+/****************************************************************************
+ * Copyright (c) 2020 Zheng Lei (realthunder) *
+ * *
+ * 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_
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+# include
+#endif
+
+#include
+#include
+
+#include
+#include
+
+#include "OverlayWidgets.h"
+
+#include
+#include
+#include
+#include "Application.h"
+#include "BitmapFactory.h"
+#include "Clipping.h"
+#include "ComboView.h"
+#include "Command.h"
+#include "Control.h"
+#include "MainWindow.h"
+#include "MDIView.h"
+#include "NaviCube.h"
+#include "OverlayManager.h"
+#include "OverlayParams.h"
+#include "TaskView/TaskView.h"
+#include "Tree.h"
+#include "TreeParams.h"
+#include "propertyeditor/PropertyEditor.h"
+
+FC_LOG_LEVEL_INIT("Dock", true, true);
+
+using namespace Gui;
+
+OverlayDragFrame *OverlayTabWidget::_DragFrame;
+QDockWidget *OverlayTabWidget::_DragFloating;
+QWidget *OverlayTabWidget::_Dragging;
+OverlayTabWidget *OverlayTabWidget::_LeftOverlay;
+OverlayTabWidget *OverlayTabWidget::_RightOverlay;
+OverlayTabWidget *OverlayTabWidget::_TopOverlay;
+OverlayTabWidget *OverlayTabWidget::_BottomOverlay;
+
+static inline int widgetMinSize(const QWidget *widget, bool margin=false)
+{
+ return widget->fontMetrics().ascent()
+ + widget->fontMetrics().descent() + (margin?4:0);
+}
+
+// -----------------------------------------------------------
+
+OverlayProxyWidget::OverlayProxyWidget(OverlayTabWidget *tabOverlay)
+ :QWidget(tabOverlay->parentWidget()), owner(tabOverlay), _hintColor(QColor(50,50,50,150))
+{
+ dockArea = owner->getDockArea();
+ timer.setSingleShot(true);
+ QObject::connect(&timer, &QTimer::timeout, this, &OverlayProxyWidget::onTimer);
+ setAttribute(Qt::WA_TransparentForMouseEvents, true);
+}
+
+bool OverlayProxyWidget::isActivated() const
+{
+ return drawLine && isVisible();
+}
+
+OverlayProxyWidget::HitTest OverlayProxyWidget::hitTest(const QPoint &globalPt, bool delay)
+{
+ if (!isVisible() || !owner->count())
+ return HitTest::HitNone;
+
+ auto pt = mapFromGlobal(globalPt);
+
+ QTabBar *tabbar = owner->tabBar();
+ if (tabbar->isVisible() && tabbar->tabAt(pt)>=0) {
+ ToolTip::showText(globalPt, QObject::tr("Press ESC to hide hint"), this);
+ return HitTest::HitOuter;
+ }
+
+ HitTest hit = HitTest::HitNone;
+ QRect rect = this->getRect();
+ QSize s = this->size();
+ int hintSize = OverlayParams::getDockOverlayHintTriggerSize();
+ // if (owner->getState() == OverlayTabWidget::State::HintHidden)
+ // hintSize *= 2;
+ switch(dockArea) {
+ case Qt::LeftDockWidgetArea:
+ if (pt.y() >= 0 && pt.y() <= s.height() && pt.x() > 0 && pt.x() < hintSize)
+ hit = HitTest::HitOuter;
+ break;
+ case Qt::RightDockWidgetArea:
+ if (pt.y() >= 0 && pt.y() <= s.height() && pt.x() < s.width() && pt.x() > -hintSize)
+ hit = HitTest::HitOuter;
+ break;
+ case Qt::TopDockWidgetArea:
+ if (pt.x() >= 0 && pt.x() <= s.width() && pt.y() > 0 && pt.y() < hintSize)
+ hit = HitTest::HitOuter;
+ break;
+ case Qt::BottomDockWidgetArea:
+ if (pt.x() >= 0 && pt.x() <= s.width() && pt.y() < s.height() && pt.y() > -hintSize)
+ hit = HitTest::HitOuter;
+ break;
+ }
+ if (rect.contains(pt)) {
+ hit = HitTest::HitInner;
+ ToolTip::showText(globalPt, QObject::tr("Press ESC to hide hint"), this);
+ } else if (drawLine)
+ ToolTip::hideText();
+
+ if (owner->getState() == OverlayTabWidget::State::HintHidden) {
+ if (hit == HitTest::HitNone)
+ owner->setState(OverlayTabWidget::State::Normal);
+ else {
+ hit = HitTest::HitNone;
+ ToolTip::hideText();
+ }
+ }
+ if (hit != HitTest::HitNone) {
+ if (drawLine)
+ timer.stop();
+ else if (delay) {
+ if (!timer.isActive())
+ timer.start(OverlayParams::getDockOverlayHintDelay());
+ return hit;
+ } else {
+ timer.stop();
+ owner->setState(OverlayTabWidget::State::Hint);
+ drawLine = true;
+ update();
+ }
+ if(owner->getState() != OverlayTabWidget::State::Hidden
+ && hit == HitTest::HitOuter
+ && OverlayParams::getDockOverlayActivateOnHover()) {
+ if (owner->isVisible() && owner->tabBar()->isVisible()) {
+ QSize size = owner->tabBar()->size();
+ QPoint pt = owner->tabBar()->mapToGlobal(
+ QPoint(size.width(), size.height()));
+ QPoint pos = QCursor::pos();
+ switch(this->dockArea) {
+ case Qt::LeftDockWidgetArea:
+ case Qt::RightDockWidgetArea:
+ if (pos.y() < pt.y())
+ return HitTest::HitNone;
+ break;
+ case Qt::TopDockWidgetArea:
+ case Qt::BottomDockWidgetArea:
+ if (pos.x() < pt.x())
+ return HitTest::HitNone;
+ break;
+ default:
+ break;
+ }
+ }
+ owner->setState(OverlayTabWidget::State::Showing);
+ }
+
+ } else if (!drawLine) {
+ timer.stop();
+ } else if (delay) {
+ if (!timer.isActive())
+ timer.start(OverlayParams::getDockOverlayHintDelay());
+ } else {
+ timer.stop();
+ owner->setState(OverlayTabWidget::State::Normal);
+ drawLine = false;
+ ToolTip::hideText();
+ update();
+ }
+ return hit;
+}
+
+void OverlayProxyWidget::onTimer()
+{
+ hitTest(QCursor::pos(), false);
+}
+
+void OverlayProxyWidget::enterEvent(QEvent *)
+{
+ if(!owner->count())
+ return;
+
+ if (!drawLine) {
+ if (!timer.isActive())
+ timer.start(OverlayParams::getDockOverlayHintDelay());
+ }
+}
+
+void OverlayProxyWidget::hideEvent(QHideEvent *)
+{
+ drawLine = false;
+}
+
+void OverlayProxyWidget::onMousePress()
+{
+ if(!owner->count())
+ return;
+
+ if (owner->getState() == OverlayTabWidget::State::HintHidden)
+ return;
+
+ owner->setState(OverlayTabWidget::State::Showing);
+}
+
+QBrush OverlayProxyWidget::hintColor() const
+{
+ return _hintColor;
+}
+
+void OverlayProxyWidget::setHintColor(const QBrush &brush)
+{
+ _hintColor = brush;
+}
+
+QRect OverlayProxyWidget::getRect() const
+{
+ QRect rect = this->rect();
+ if (owner->isVisible() && owner->tabBar()->isVisible()) {
+ QSize size = owner->tabBar()->size();
+ QPoint pt = owner->tabBar()->mapToGlobal(
+ QPoint(size.width(), size.height()));
+ pt = this->mapFromGlobal(pt);
+ switch(this->dockArea) {
+ case Qt::LeftDockWidgetArea:
+ case Qt::RightDockWidgetArea:
+ rect.setTop(pt.y());
+ break;
+ case Qt::TopDockWidgetArea:
+ case Qt::BottomDockWidgetArea:
+ rect.setLeft(pt.x());
+ break;
+ default:
+ break;
+ }
+ }
+ switch(this->dockArea) {
+ case Qt::LeftDockWidgetArea:
+ if (int offset = OverlayParams::getDockOverlayHintLeftOffset())
+ rect.moveTop(std::max(rect.top()+offset, rect.bottom()-10));
+ if (int length = OverlayParams::getDockOverlayHintLeftLength())
+ rect.setHeight(std::min(length, rect.height()));
+ break;
+ case Qt::RightDockWidgetArea:
+ if (int offset = OverlayParams::getDockOverlayHintRightOffset())
+ rect.moveTop(std::max(rect.top()+offset, rect.bottom()-10));
+ if (int length = OverlayParams::getDockOverlayHintRightLength())
+ rect.setHeight(std::min(length, rect.height()));
+ break;
+ case Qt::TopDockWidgetArea:
+ if (int offset = OverlayParams::getDockOverlayHintTopOffset())
+ rect.moveLeft(std::max(rect.left()+offset, rect.right()-10));
+ if (int length = OverlayParams::getDockOverlayHintTopLength())
+ rect.setWidth(std::min(length, rect.width()));
+ break;
+ case Qt::BottomDockWidgetArea:
+ if (int offset = OverlayParams::getDockOverlayHintBottomOffset())
+ rect.moveLeft(std::max(rect.left()+offset, rect.right()-10));
+ if (int length = OverlayParams::getDockOverlayHintBottomLength())
+ rect.setWidth(std::min(length, rect.width()));
+ break;
+ default:
+ break;
+ }
+ return rect;
+}
+
+void OverlayProxyWidget::paintEvent(QPaintEvent *)
+{
+ if(!drawLine)
+ return;
+ QPainter painter(this);
+ painter.setOpacity(_hintColor.color().alphaF());
+ painter.setPen(Qt::transparent);
+ painter.setBrush(_hintColor);
+
+ QRect rect = this->getRect();
+ painter.drawRect(rect);
+}
+
+OverlayToolButton::OverlayToolButton(QWidget *parent)
+ :QToolButton(parent)
+{
+ setCursor(Qt::ArrowCursor);
+}
+
+// --------------------------------------------------------------------
+
+OverlayTabWidget::OverlayTabWidget(QWidget *parent, Qt::DockWidgetArea pos)
+ :QTabWidget(parent), dockArea(pos)
+{
+ // This is necessary to capture any focus lost from switching the tab,
+ // otherwise the lost focus will leak to the parent, i.e. MdiArea, which may
+ // cause unexpected Mdi sub window switching.
+ // setFocusPolicy(Qt::StrongFocus);
+
+ _imageScale = 0.0;
+
+ splitter = new OverlaySplitter(this);
+
+ _graphicsEffect = new OverlayGraphicsEffect(splitter);
+ splitter->setGraphicsEffect(_graphicsEffect);
+
+ _graphicsEffectTab = new OverlayGraphicsEffect(this);
+ _graphicsEffectTab->setEnabled(false);
+ tabBar()->setGraphicsEffect(_graphicsEffectTab);
+
+ Command *cmdHide = nullptr;
+ switch(pos) {
+ case Qt::LeftDockWidgetArea:
+ _LeftOverlay = this;
+ setTabPosition(QTabWidget::West);
+ splitter->setOrientation(Qt::Vertical);
+ cmdHide = Application::Instance->commandManager().getCommandByName("Std_DockOverlayToggleLeft");
+ break;
+ case Qt::RightDockWidgetArea:
+ _RightOverlay = this;
+ setTabPosition(QTabWidget::East);
+ splitter->setOrientation(Qt::Vertical);
+ cmdHide = Application::Instance->commandManager().getCommandByName("Std_DockOverlayToggleRight");
+ break;
+ case Qt::TopDockWidgetArea:
+ _TopOverlay = this;
+ setTabPosition(QTabWidget::North);
+ splitter->setOrientation(Qt::Horizontal);
+ cmdHide = Application::Instance->commandManager().getCommandByName("Std_DockOverlayToggleTop");
+ break;
+ case Qt::BottomDockWidgetArea:
+ _BottomOverlay = this;
+ setTabPosition(QTabWidget::South);
+ splitter->setOrientation(Qt::Horizontal);
+ cmdHide = Application::Instance->commandManager().getCommandByName("Std_DockOverlayToggleBottom");
+ break;
+ default:
+ break;
+ }
+
+ proxyWidget = new OverlayProxyWidget(this);
+ proxyWidget->hide();
+ _setOverlayMode(proxyWidget,OverlayOption::Enable);
+
+ setOverlayMode(true);
+ hide();
+
+ actTransparent.setCheckable(true);
+ actTransparent.setData(QStringLiteral("OBTN Transparent"));
+ actTransparent.setParent(this);
+ addAction(&actTransparent);
+
+ actAutoHide.setData(QStringLiteral("OBTN AutoHide"));
+
+ actEditHide.setData(QStringLiteral("OBTN EditHide"));
+
+ actEditShow.setData(QStringLiteral("OBTN EditShow"));
+
+ actTaskShow.setData(QStringLiteral("OBTN TaskShow"));
+
+ actNoAutoMode.setData(QStringLiteral("OBTN NoAutoMode"));
+
+ actAutoMode.setData(QStringLiteral("OBTN AutoMode"));
+ actAutoMode.setParent(this);
+ autoModeMenu.hide();
+ autoModeMenu.setToolTipsVisible(true);
+ autoModeMenu.addAction(&actNoAutoMode);
+ autoModeMenu.addAction(&actAutoHide);
+ autoModeMenu.addAction(&actEditShow);
+ autoModeMenu.addAction(&actEditHide);
+ autoModeMenu.addAction(&actTaskShow);
+ addAction(&actAutoMode);
+
+ actOverlay.setData(QStringLiteral("OBTN Overlay"));
+ actOverlay.setParent(this);
+ addAction(&actOverlay);
+
+ if (cmdHide)
+ cmdHide->addTo(this);
+
+ retranslate();
+ refreshIcons();
+
+ connect(tabBar(), &QTabBar::tabBarClicked, this, &OverlayTabWidget::onCurrentChanged);
+ connect(tabBar(), &QTabBar::tabMoved, this, &OverlayTabWidget::onTabMoved);
+ tabBar()->installEventFilter(this);
+
+ timer.setSingleShot(true);
+ connect(&timer, &QTimer::timeout, this, &OverlayTabWidget::setupLayout);
+
+ repaintTimer.setSingleShot(true);
+ connect(&repaintTimer, &QTimer::timeout, this, &OverlayTabWidget::onRepaint);
+
+ _animator = new QPropertyAnimation(this, "animation", this);
+ _animator->setStartValue(0.0);
+ _animator->setEndValue(1.0);
+ connect(_animator, &QAbstractAnimation::stateChanged,
+ this, &OverlayTabWidget::onAnimationStateChanged);
+}
+
+void OverlayTabWidget::refreshIcons()
+{
+ actOverlay.setIcon(BitmapFactory().pixmap("qss:overlay/overlay.svg"));
+ actNoAutoMode.setIcon(BitmapFactory().pixmap("qss:overlay/mode.svg"));
+ actTaskShow.setIcon(BitmapFactory().pixmap("qss:overlay/taskshow.svg"));
+ actEditShow.setIcon(BitmapFactory().pixmap("qss:overlay/editshow.svg"));
+ actEditHide.setIcon(BitmapFactory().pixmap("qss:overlay/edithide.svg"));
+ actTransparent.setIcon(BitmapFactory().pixmap("qss:overlay/transparent.svg"));
+ QPixmap pxAutoHide = BitmapFactory().pixmap("qss:overlay/autohide.svg");
+ switch(dockArea) {
+ case Qt::LeftDockWidgetArea:
+ actAutoHide.setIcon(pxAutoHide);
+ break;
+ case Qt::RightDockWidgetArea:
+ actAutoHide.setIcon(pxAutoHide.transformed(QTransform().scale(-1,1)));
+ break;
+ case Qt::TopDockWidgetArea:
+ actAutoHide.setIcon(pxAutoHide.transformed(QTransform().rotate(90)));
+ break;
+ case Qt::BottomDockWidgetArea:
+ actAutoHide.setIcon(pxAutoHide.transformed(QTransform().rotate(-90)));
+ break;
+ default:
+ break;
+ }
+ syncAutoMode();
+}
+
+void OverlayTabWidget::onAnimationStateChanged()
+{
+ if (_animator->state() != QAbstractAnimation::Running) {
+ setAnimation(0);
+ if (_animator->startValue().toReal() == 0.0) {
+ hide();
+ OverlayManager::instance()->refresh();
+ }
+ if (_state == State::Showing)
+ setState(State::Normal);
+ }
+}
+
+void OverlayTabWidget::setAnimation(qreal t)
+{
+ if (t != _animation) {
+ _animation = t;
+ setupLayout();
+ }
+}
+
+void OverlayTabWidget::startShow()
+{
+ if (isVisible() || _state > State::Normal)
+ return;
+ int duration = OverlayParams::getDockOverlayAnimationDuration();
+ bool setmode = _state != State::Showing;
+ if (duration) {
+ _animator->setStartValue(1.0);
+ _animator->setEndValue(0.0);
+ _animator->setDuration(duration);
+ _animator->setEasingCurve((QEasingCurve::Type)OverlayParams::getDockOverlayAnimationCurve());
+ _animator->start();
+ }
+ else if (_state == State::Showing)
+ setState(State::Normal);
+ proxyWidget->hide();
+ show();
+ raise();
+ if (setmode)
+ setOverlayMode(overlaid);
+}
+
+QWidget *OverlayTabWidget::createTitleButton(QAction *action, int size)
+{
+ auto button = new OverlayToolButton(nullptr);
+ button->setObjectName(action->data().toString());
+ button->setDefaultAction(action);
+ button->setAutoRaise(true);
+ button->setContentsMargins(0,0,0,0);
+ button->setFixedSize(size,size);
+ return button;
+}
+
+void OverlayTabWidget::startHide()
+{
+ if (!isVisible()
+ || _state > State::Normal
+ || (_animator->state() == QAbstractAnimation::Running
+ && _animator->startValue().toReal() == 0.0))
+ return;
+ int duration = OverlayParams::getDockOverlayAnimationDuration();
+ if (!duration)
+ hide();
+ else {
+ _animator->setStartValue(0.0);
+ _animator->setEndValue(1.0);
+ _animator->setDuration(duration);
+ _animator->setEasingCurve((QEasingCurve::Type)OverlayParams::getDockOverlayAnimationCurve());
+ _animator->start();
+ }
+}
+
+bool OverlayTabWidget::event(QEvent *ev)
+{
+ switch(ev->type()) {
+ case QEvent::MouseButtonRelease:
+ if(mouseGrabber() == this) {
+ releaseMouse();
+ ev->accept();
+ return true;
+ }
+ break;
+ case QEvent::MouseMove:
+ case QEvent::ContextMenu:
+ if(QApplication::mouseButtons() == Qt::NoButton && mouseGrabber() == this) {
+ releaseMouse();
+ ev->accept();
+ return true;
+ }
+ break;
+ case QEvent::MouseButtonPress:
+ ev->accept();
+ return true;
+ default:
+ break;
+ }
+ return QTabWidget::event(ev);
+}
+
+int OverlayTabWidget::testAlpha(const QPoint &_pos, int radiusScale)
+{
+ if (!count() || (!isOverlaid() && !isTransparent()) || !isVisible())
+ return -1;
+
+ if (tabBar()->isVisible() && tabBar()->tabAt(tabBar()->mapFromGlobal(_pos))>=0)
+ return -1;
+
+ if (titleBar->isVisible() && titleBar->rect().contains(titleBar->mapFromGlobal(_pos)))
+ return -1;
+
+ if (!splitter->isVisible())
+ return 0;
+
+ auto pos = splitter->mapFromGlobal(_pos);
+ QSize size = splitter->size();
+ if (pos.x() < 0 || pos.y() < 0
+ || pos.x() >= size.width()
+ || pos.y() >= size.height())
+ {
+ if (this->rect().contains(this->mapFromGlobal(_pos)))
+ return 0;
+ return -1;
+ }
+
+ if (_image.isNull()) {
+ auto pixmap = splitter->grab();
+ _imageScale = pixmap.devicePixelRatio();
+ _image = pixmap.toImage();
+ }
+
+ int res = qAlpha(_image.pixel(pos*_imageScale));
+ int radius = OverlayParams::getDockOverlayAlphaRadius() * radiusScale;
+ if (res || radius<=0 )
+ return res;
+
+ radius *= _imageScale;
+ for (int i=-radius; i= size.width()
+ || pos.y()+j >= size.height())
+ continue;
+ res = qAlpha(_image.pixel(pos*_imageScale + QPoint(i,j)));
+ if (res)
+ return res;
+ }
+ }
+ return 0;
+}
+
+void OverlayTabWidget::paintEvent(QPaintEvent *ev)
+{
+ Base::StateLocker guard(repainting);
+ repaintTimer.stop();
+ if (!_image.isNull())
+ _image = QImage();
+ QTabWidget::paintEvent(ev);
+}
+
+void OverlayTabWidget::onRepaint()
+{
+ Base::StateLocker guard(repainting);
+ repaintTimer.stop();
+ if (!_image.isNull())
+ _image = QImage();
+ splitter->repaint();
+}
+
+void OverlayTabWidget::scheduleRepaint()
+{
+ if(!repainting
+ && isVisible()
+ && _graphicsEffect)
+ {
+ repaintTimer.start(100);
+ }
+}
+
+QColor OverlayTabWidget::effectColor() const
+{
+ return _graphicsEffect->color();
+}
+
+void OverlayTabWidget::setEffectColor(const QColor &color)
+{
+ _graphicsEffect->setColor(color);
+ _graphicsEffectTab->setColor(color);
+}
+
+int OverlayTabWidget::effectWidth() const
+{
+ return _graphicsEffect->size().width();
+}
+
+void OverlayTabWidget::setEffectWidth(int s)
+{
+ auto size = _graphicsEffect->size();
+ size.setWidth(s);
+ _graphicsEffect->setSize(size);
+ _graphicsEffectTab->setSize(size);
+}
+
+int OverlayTabWidget::effectHeight() const
+{
+ return _graphicsEffect->size().height();
+}
+
+void OverlayTabWidget::setEffectHeight(int s)
+{
+ auto size = _graphicsEffect->size();
+ size.setHeight(s);
+ _graphicsEffect->setSize(size);
+ _graphicsEffectTab->setSize(size);
+}
+
+qreal OverlayTabWidget::effectOffsetX() const
+{
+ return _graphicsEffect->offset().x();
+}
+
+void OverlayTabWidget::setEffectOffsetX(qreal d)
+{
+ auto offset = _graphicsEffect->offset();
+ offset.setX(d);
+ _graphicsEffect->setOffset(offset);
+ _graphicsEffectTab->setOffset(offset);
+}
+
+qreal OverlayTabWidget::effectOffsetY() const
+{
+ return _graphicsEffect->offset().y();
+}
+
+void OverlayTabWidget::setEffectOffsetY(qreal d)
+{
+ auto offset = _graphicsEffect->offset();
+ offset.setY(d);
+ _graphicsEffect->setOffset(offset);
+ _graphicsEffectTab->setOffset(offset);
+}
+
+qreal OverlayTabWidget::effectBlurRadius() const
+{
+ return _graphicsEffect->blurRadius();
+}
+
+void OverlayTabWidget::setEffectBlurRadius(qreal r)
+{
+ _graphicsEffect->setBlurRadius(r);
+ _graphicsEffectTab->setBlurRadius(r);
+}
+
+bool OverlayTabWidget::effectEnabled() const
+{
+ return _effectEnabled;
+}
+
+void OverlayTabWidget::setEffectEnabled(bool enable)
+{
+ _effectEnabled = enable;
+}
+
+bool OverlayTabWidget::eventFilter(QObject *o, QEvent *ev)
+{
+ if(ev->type() == QEvent::Resize && o == tabBar()) {
+ if (_state <= State::Normal)
+ timer.start(10);
+ }
+ return QTabWidget::eventFilter(o, ev);
+}
+
+void OverlayTabWidget::restore(ParameterGrp::handle handle)
+{
+ if (!handle) {
+ hGrp = handle;
+ return;
+ }
+ if (!parentWidget())
+ return;
+ std::string widgets = handle->GetASCII("Widgets","");
+ for(auto &name : QString::fromUtf8(widgets.c_str()).split(QLatin1Char(','))) {
+ if(name.isEmpty())
+ continue;
+ OverlayManager::instance()->registerDockWidget(name, this);
+ auto dock = getMainWindow()->findChild(name);
+ if(dock)
+ addWidget(dock, dock->windowTitle());
+ }
+ int width = handle->GetInt("Width", 0);
+ int height = handle->GetInt("Height", 0);
+ int offset1 = handle->GetInt("Offset1", 0);
+ int offset2 = handle->GetInt("Offset3", 0);
+ setOffset(QSize(offset1,offset2));
+ setSizeDelta(handle->GetInt("Offset2", 0));
+ if(width && height) {
+ QRect rect(0, 0, width, height);
+ switch(dockArea) {
+ case Qt::RightDockWidgetArea:
+ rect.moveRight(parentWidget()->size().width());
+ break;
+ case Qt::BottomDockWidgetArea:
+ rect.moveBottom(parentWidget()->size().height());
+ break;
+ default:
+ break;
+ }
+ setRect(rect);
+ }
+ if (handle->GetBool("AutoHide", false))
+ setAutoMode(AutoMode::AutoHide);
+ else if (handle->GetBool("EditHide", false))
+ setAutoMode(AutoMode::EditHide);
+ else if (handle->GetBool("EditShow", false))
+ setAutoMode(AutoMode::EditShow);
+ else if (handle->GetBool("TaskShow", false))
+ setAutoMode(AutoMode::TaskShow);
+ else
+ setAutoMode(AutoMode::NoAutoMode);
+
+ setTransparent(handle->GetBool("Transparent", false));
+
+ _sizemap.clear();
+ std::string savedSizes = handle->GetASCII("Sizes","");
+ QList sizes;
+ int idx = 0;
+ for(auto &size : QString::fromUtf8(savedSizes.c_str()).split(QLatin1Char(','))) {
+ sizes.append(size.toInt());
+ _sizemap[dockWidget(idx++)] = sizes.back();
+ }
+
+ FC_LOG("restore " << objectName().toUtf8().constData() << " " << savedSizes);
+
+ getSplitter()->setSizes(sizes);
+ hGrp = handle;
+}
+
+void OverlayTabWidget::saveTabs()
+{
+ if(!hGrp)
+ return;
+
+ std::ostringstream os, os2;
+ _sizemap.clear();
+ auto sizes = splitter->sizes();
+ bool first = true;
+ for(int i=0,c=splitter->count(); iobjectName().size()) {
+ os << dock->objectName().toUtf8().constData() << ",";
+ if (first)
+ first = false;
+ else
+ os2 << ",";
+ os2 << sizes[i];
+ }
+ _sizemap[dock] = sizes[i];
+ }
+ Base::StateLocker lock(_saving);
+ hGrp->SetASCII("Widgets", os.str().c_str());
+ hGrp->SetASCII("Sizes", os2.str().c_str());
+ FC_LOG("save " << objectName().toUtf8().constData() << " " << os2.str());
+}
+
+void OverlayTabWidget::onTabMoved(int from, int to)
+{
+ QWidget *w = splitter->widget(from);
+ splitter->insertWidget(to,w);
+ saveTabs();
+}
+
+void OverlayTabWidget::setTitleBar(QWidget *w)
+{
+ titleBar = w;
+}
+
+void OverlayTabWidget::changeEvent(QEvent *e)
+{
+ QTabWidget::changeEvent(e);
+ if (e->type() == QEvent::LanguageChange)
+ retranslate();
+}
+
+void OverlayTabWidget::retranslate()
+{
+ actTransparent.setToolTip(tr("Toggle transparent mode"));
+ actNoAutoMode.setText(tr("None"));
+ actNoAutoMode.setToolTip(tr("Turn off auto hide/show"));
+ actAutoHide.setText(tr("Auto hide"));
+ actAutoHide.setToolTip(tr("Auto hide docked widgets on leave"));
+ actEditHide.setText(tr("Hide on edit"));
+ actEditHide.setToolTip(tr("Auto hide docked widgets on editing"));
+ actEditShow.setText(tr("Show on edit"));
+ actEditShow.setToolTip(tr("Auto show docked widgets on editing"));
+ actTaskShow.setText(tr("Auto task"));
+ actTaskShow.setToolTip(tr("Auto show task view for any current task, and hide the view when there is no task."));
+ actOverlay.setToolTip(tr("Toggle overlay"));
+ syncAutoMode();
+}
+
+void OverlayTabWidget::syncAutoMode()
+{
+ QAction *action = nullptr;
+ switch(autoMode) {
+ case AutoMode::AutoHide:
+ action = &actAutoHide;
+ break;
+ case AutoMode::EditShow:
+ action = &actEditShow;
+ break;
+ case AutoMode::TaskShow:
+ action = &actTaskShow;
+ break;
+ case AutoMode::EditHide:
+ action = &actEditHide;
+ break;
+ default:
+ action = &actNoAutoMode;
+ break;
+ }
+ actAutoMode.setIcon(action->icon());
+ if (action == &actNoAutoMode)
+ actAutoMode.setToolTip(tr("Select auto show/hide mode"));
+ else
+ actAutoMode.setToolTip(action->toolTip());
+}
+
+void OverlayTabWidget::onAction(QAction *action)
+{
+ if (action == &actAutoMode) {
+ action = autoModeMenu.exec(QCursor::pos());
+ if (action == &actNoAutoMode)
+ setAutoMode(AutoMode::NoAutoMode);
+ else if (action == &actAutoHide)
+ setAutoMode(AutoMode::AutoHide);
+ else if (action == &actEditShow)
+ setAutoMode(AutoMode::EditShow);
+ else if (action == &actTaskShow)
+ setAutoMode(AutoMode::TaskShow);
+ else if (action == &actEditHide)
+ setAutoMode(AutoMode::EditHide);
+ return;
+ }
+ else if(action == &actOverlay) {
+ OverlayManager::instance()->setOverlayMode(OverlayManager::OverlayMode::ToggleActive);
+ return;
+ } else if(action == &actTransparent) {
+ if(hGrp) {
+ Base::StateLocker lock(_saving);
+ hGrp->SetBool("Transparent", actTransparent.isChecked());
+ }
+ }
+ OverlayManager::instance()->refresh(this);
+}
+
+void OverlayTabWidget::setState(State state)
+{
+ if (_state == state)
+ return;
+ switch(state) {
+ case State::Normal:
+ if (_state == State::Hidden) {
+ // Only unhide through State::Showing, not State::Normal
+ return;
+ }
+ else if (_state == State::Showing) {
+ _state = state;
+ return;
+ }
+ // fall through
+ case State::Showing:
+ _state = state;
+ hide();
+ if (dockArea == Qt::RightDockWidgetArea)
+ setTabPosition(East);
+ else if (dockArea == Qt::BottomDockWidgetArea)
+ setTabPosition(South);
+ if (this->count() == 1)
+ tabBar()->hide();
+ _graphicsEffectTab->setEnabled(false);
+ titleBar->show();
+ splitter->show();
+ if (state == State::Showing)
+ OverlayManager::instance()->refresh(this);
+ break;
+ case State::Hint:
+ if (_state == State::HintHidden || _state == State::Hidden)
+ break;
+ _state = state;
+ if (this->count() && OverlayParams::getDockOverlayHintTabBar()) {
+ tabBar()->setToolTip(proxyWidget->toolTip());
+ tabBar()->show();
+ titleBar->hide();
+ splitter->hide();
+ _graphicsEffectTab->setEnabled(true);
+ show();
+ raise();
+ proxyWidget->raise();
+ if (dockArea == Qt::RightDockWidgetArea)
+ setTabPosition(West);
+ else if (dockArea == Qt::BottomDockWidgetArea)
+ setTabPosition(North);
+ OverlayManager::instance()->refresh(this);
+ }
+ break;
+ case State::HintHidden:
+ if (_state != State::Hidden)
+ _state = state;
+ proxyWidget->hide();
+ hide();
+ _graphicsEffectTab->setEnabled(true);
+ break;
+ case State::Hidden:
+ startHide();
+ _state = state;
+ break;
+ default:
+ break;
+ }
+}
+
+bool OverlayTabWidget::checkAutoHide() const
+{
+ if(autoMode == AutoMode::AutoHide)
+ return true;
+
+ if(OverlayParams::getDockOverlayAutoView()) {
+ auto view = getMainWindow()->activeWindow();
+ if (!view) return true;
+ if(!view->onHasMsg("CanPan")
+ && view->parentWidget()
+ && view->parentWidget()->isMaximized())
+ return true;
+ }
+
+ if(autoMode == AutoMode::EditShow) {
+ return !Application::Instance->editDocument()
+ && (!Control().taskPanel() || Control().taskPanel()->isEmpty(false));
+ }
+
+ if(autoMode == AutoMode::EditHide && Application::Instance->editDocument())
+ return true;
+
+ return false;
+}
+
+void OverlayTabWidget::leaveEvent(QEvent*)
+{
+ if (titleBar && QWidget::mouseGrabber() == titleBar)
+ return;
+ OverlayManager::instance()->refresh();
+}
+
+void OverlayTabWidget::enterEvent(QEvent*)
+{
+ revealTime = QTime();
+ OverlayManager::instance()->refresh();
+}
+
+void OverlayTabWidget::setRevealTime(const QTime &time)
+{
+ revealTime = time;
+}
+
+void OverlayTabWidget::_setOverlayMode(QWidget *widget, OverlayOption option)
+{
+ if(!widget)
+ return;
+
+#if QT_VERSION>QT_VERSION_CHECK(5,12,2) && QT_VERSION < QT_VERSION_CHECK(5,12,6)
+ // Work around Qt bug https://bugreports.qt.io/browse/QTBUG-77006
+ widget->setStyleSheet(OverlayManager::instance()->getStyleSheet());
+#endif
+
+ if (qobject_cast(widget)) {
+ auto parent = widget->parentWidget();
+ if (parent) {
+ parent = parent->parentWidget();
+ if (qobject_cast(parent)) {
+ auto scrollArea = static_cast(parent);
+ if (scrollArea->verticalScrollBar() == widget) {
+ if (!OverlayParams::getDockOverlayHidePropertyViewScrollBar()
+ || option == OverlayOption::Disable)
+ widget->setStyleSheet(QString());
+ else {
+ static QString _style = QStringLiteral("*{width:0}");
+ widget->setStyleSheet(_style);
+ }
+ }
+ }
+ auto treeView = qobject_cast(parent);
+ if (treeView) {
+ auto scrollArea = static_cast(parent);
+ if (scrollArea->verticalScrollBar() == widget) {
+ if (!TreeParams::getHideScrollBar() || option == OverlayOption::Disable)
+ widget->setStyleSheet(QString());
+ else {
+ static QString _style = QStringLiteral("*{width:0}");
+ widget->setStyleSheet(_style);
+ }
+ }
+ }
+
+ if (treeView) {
+ auto header = treeView->header();
+ if (!TreeParams::getHideHeaderView() || option==OverlayOption::Disable)
+ header->setStyleSheet(QString());
+ else {
+ static QString _style = QStringLiteral(
+ "QHeaderView:section {"
+ "height: 0px;"
+ "background-color: transparent;"
+ "padding: 0px;"
+ "border: transparent;}");
+ header->setStyleSheet(_style);
+ }
+ }
+ }
+ }
+
+ auto tabbar = qobject_cast(widget);
+ if(tabbar) {
+ if(!tabbar->autoHide() || tabbar->count()>1) {
+ if(!OverlayManager::instance()->getHideTab())
+ tabbar->setVisible(true);
+ else
+ tabbar->setVisible(option == OverlayOption::Disable
+ || (option == OverlayOption::ShowTab && tabbar->count()>1));
+ return;
+ }
+ }
+
+ if (!qobject_cast(widget)
+ || !qobject_cast(widget->parentWidget())) {
+ if(option != OverlayOption::Disable) {
+ widget->setWindowFlags(widget->windowFlags() | Qt::FramelessWindowHint);
+ } else {
+ widget->setWindowFlags(widget->windowFlags() & ~Qt::FramelessWindowHint);
+ }
+ widget->setAttribute(Qt::WA_NoSystemBackground, option != OverlayOption::Disable);
+ widget->setAttribute(Qt::WA_TranslucentBackground, option != OverlayOption::Disable);
+ }
+}
+
+void OverlayTabWidget::setOverlayMode(QWidget *widget, OverlayOption option)
+{
+ if(!widget || (qobject_cast(widget)
+ && !qobject_cast(widget))
+ || qobject_cast(widget))
+ return;
+
+ if(widget != tabBar()) {
+ if(OverlayParams::getDockOverlayAutoMouseThrough()
+ && option == OverlayOption::ShowTab) {
+ widget->setMouseTracking(true);
+ }
+ }
+
+ _setOverlayMode(widget, option);
+
+ if(qobject_cast(widget)) {
+ // do not set child QAbstractItemView of QComboBox, otherwise the drop down box
+ // won't be shown
+ return;
+ }
+ for(auto child : widget->children())
+ setOverlayMode(qobject_cast(child), option);
+}
+
+void OverlayTabWidget::setTransparent(bool enable)
+{
+ if(actTransparent.isChecked() == enable)
+ return;
+ if(hGrp) {
+ Base::StateLocker lock(_saving);
+ hGrp->SetBool("Transparent", enable);
+ }
+ actTransparent.setChecked(enable);
+ OverlayManager::instance()->refresh(this);
+}
+
+bool OverlayTabWidget::isTransparent() const
+{
+ if (!actTransparent.isChecked())
+ return false;
+ if(OverlayParams::getDockOverlayAutoView()) {
+ auto view = getMainWindow()->activeWindow();
+ if (!view) return false;
+ if(!view->onHasMsg("CanPan")
+ && view->parentWidget()
+ && view->parentWidget()->isMaximized())
+ return false;
+ }
+ return true;
+}
+
+bool OverlayTabWidget::isOverlaid(QueryOption option) const
+{
+ if (option != QueryOption::QueryOverlay
+ && currentTransparent != isTransparent())
+ return option == QueryOption::TransparencyChanged;
+ return overlaid;
+}
+
+void OverlayTabWidget::setAutoMode(AutoMode mode)
+{
+ if (autoMode == mode)
+ return;
+ autoMode = mode;
+
+ if (hGrp) {
+ bool autohide = false, editshow = false, edithide = false, taskshow = false;
+ switch (mode) {
+ case AutoMode::AutoHide:
+ autohide = true;
+ break;
+ case AutoMode::EditShow:
+ editshow = true;
+ break;
+ case AutoMode::EditHide:
+ edithide = true;
+ break;
+ case AutoMode::TaskShow:
+ taskshow = true;
+ break;
+ default:
+ break;
+ }
+ Base::StateLocker lock(_saving);
+ hGrp->SetBool("AutoHide", autohide);
+ hGrp->SetBool("EditShow", editshow);
+ hGrp->SetBool("EditHide", edithide);
+ hGrp->SetBool("TaskShow", taskshow);
+ }
+ syncAutoMode();
+ OverlayManager::instance()->refresh(this);
+}
+
+QDockWidget *OverlayTabWidget::currentDockWidget() const
+{
+ int index = -1;
+ for(int size : splitter->sizes()) {
+ ++index;
+ if(size>0)
+ return dockWidget(index);
+ }
+ return dockWidget(currentIndex());
+}
+
+QDockWidget *OverlayTabWidget::dockWidget(int index) const
+{
+ if(index < 0 || index >= splitter->count())
+ return nullptr;
+ return qobject_cast(splitter->widget(index));
+}
+
+void OverlayTabWidget::updateSplitterHandles()
+{
+ if (overlaid || _state > State::Normal)
+ return;
+ for (int i=0, c=splitter->count(); i(splitter->handle(i));
+ if (handle)
+ handle->showTitle(true);
+ }
+}
+
+bool OverlayTabWidget::onEscape()
+{
+ if (getState() == OverlayTabWidget::State::Hint
+ || getState() == OverlayTabWidget::State::Hidden) {
+ setState(OverlayTabWidget::State::HintHidden);
+ return true;
+ }
+ if (!isVisible())
+ return false;
+ if (titleBar->isVisible() && titleBar->underMouse()) {
+ titleBar->hide();
+ return true;
+ }
+ for (int i=0, c=splitter->count(); i(splitter->handle(i));
+ if (handle->isVisible() && handle->underMouse()) {
+ handle->showTitle(false);
+ return true;
+ }
+ }
+ return false;
+}
+
+void OverlayTabWidget::setOverlayMode(bool enable)
+{
+ overlaid = enable;
+
+ if(!isVisible() || !count())
+ return;
+
+ touched = false;
+
+ if (_state <= State::Normal) {
+ titleBar->setVisible(!enable || OverlayManager::instance()->isMouseTransparent());
+ for (int i=0, c=splitter->count(); i(splitter->handle(i));
+ if (handle)
+ handle->showTitle(!enable);
+ }
+ }
+
+ QString stylesheet;
+ stylesheet = OverlayManager::instance()->getStyleSheet();
+ currentTransparent = isTransparent();
+
+ OverlayOption option;
+ if(!enable && isTransparent()) {
+ option = OverlayOption::ShowTab;
+ } else if (enable
+ && !isTransparent()
+ && (autoMode == AutoMode::EditShow || autoMode == AutoMode::AutoHide)) {
+ option = OverlayOption::Disable;
+ } else {
+ option = enable?OverlayOption::Enable:OverlayOption::Disable;
+ }
+
+ proxyWidget->setStyleSheet(stylesheet);
+ this->setStyleSheet(stylesheet);
+ setOverlayMode(this, option);
+
+ _graphicsEffect->setEnabled(effectEnabled() && (enable || isTransparent()));
+
+ if (_state == State::Hint && OverlayParams::getDockOverlayHintTabBar()) {
+ tabBar()->setToolTip(proxyWidget->toolTip());
+ tabBar()->show();
+ } else if (OverlayParams::getDockOverlayHideTabBar() || count()==1) {
+ tabBar()->hide();
+ } else {
+ tabBar()->setToolTip(QString());
+ tabBar()->setVisible(!enable || !OverlayManager::instance()->getHideTab());
+ }
+
+ setRect(rectOverlay);
+}
+
+const QRect &OverlayTabWidget::getRect()
+{
+ return rectOverlay;
+}
+
+bool OverlayTabWidget::getAutoHideRect(QRect &rect) const
+{
+ rect = rectOverlay;
+ int hintWidth = OverlayParams::getDockOverlayHintSize();
+ switch(dockArea) {
+ case Qt::LeftDockWidgetArea:
+ case Qt::RightDockWidgetArea:
+ if (_TopOverlay->isVisible() && _TopOverlay->_state <= State::Normal)
+ rect.setTop(std::max(rect.top(), _TopOverlay->rectOverlay.bottom()));
+ if (dockArea == Qt::RightDockWidgetArea)
+ rect.setLeft(rect.left() + std::max(rect.width()-hintWidth,0));
+ else
+ rect.setRight(rect.right() - std::max(rect.width()-hintWidth,0));
+ break;
+ case Qt::TopDockWidgetArea:
+ case Qt::BottomDockWidgetArea:
+ if (_LeftOverlay->isVisible() && _LeftOverlay->_state <= State::Normal)
+ rect.setLeft(std::max(rect.left(),_LeftOverlay->rectOverlay.right()));
+ if (dockArea == Qt::TopDockWidgetArea)
+ rect.setBottom(rect.bottom() - std::max(rect.height()-hintWidth,0));
+ else {
+ rect.setTop(rect.top() + std::max(rect.height()-hintWidth,0));
+ if (_RightOverlay->isVisible() && _RightOverlay->_state <= State::Normal) {
+ QPoint offset = getMainWindow()->getMdiArea()->pos();
+ rect.setRight(std::min(rect.right(), _RightOverlay->x()-offset.x()));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return _state != State::Showing && overlaid && checkAutoHide();
+}
+
+void OverlayTabWidget::setOffset(const QSize &ofs)
+{
+ if(offset != ofs) {
+ offset = ofs;
+ if(hGrp) {
+ Base::StateLocker lock(_saving);
+ hGrp->SetInt("Offset1", ofs.width());
+ hGrp->SetInt("Offset3", ofs.height());
+ }
+ }
+}
+
+void OverlayTabWidget::setSizeDelta(int delta)
+{
+ if(sizeDelta != delta) {
+ if(hGrp) {
+ Base::StateLocker lock(_saving);
+ hGrp->SetInt("Offset2", delta);
+ }
+ sizeDelta = delta;
+ }
+}
+
+void OverlayTabWidget::setRect(QRect rect)
+{
+ if(busy || !parentWidget() || !getMainWindow() || !getMainWindow()->getMdiArea())
+ return;
+
+ if (rect.width() == 0)
+ rect.setWidth(OverlayParams::getDockOverlayMinimumSize()*3);
+ if (rect.height() == 0)
+ rect.setHeight(OverlayParams::getDockOverlayMinimumSize()*3);
+
+ switch(dockArea) {
+ case Qt::LeftDockWidgetArea:
+ rect.moveLeft(0);
+ if (rect.width() < OverlayParams::getDockOverlayMinimumSize())
+ rect.setWidth(OverlayParams::getDockOverlayMinimumSize());
+ break;
+ case Qt::RightDockWidgetArea:
+ if (rect.width() < OverlayParams::getDockOverlayMinimumSize())
+ rect.setLeft(rect.right()-OverlayParams::getDockOverlayMinimumSize());
+ break;
+ case Qt::TopDockWidgetArea:
+ rect.moveTop(0);
+ if (rect.height() < OverlayParams::getDockOverlayMinimumSize())
+ rect.setHeight(OverlayParams::getDockOverlayMinimumSize());
+ break;
+ case Qt::BottomDockWidgetArea:
+ if (rect.height() < OverlayParams::getDockOverlayMinimumSize())
+ rect.setTop(rect.bottom()-OverlayParams::getDockOverlayMinimumSize());
+ break;
+ default:
+ break;
+ }
+
+ if(hGrp && rect.size() != rectOverlay.size()) {
+ Base::StateLocker lock(_saving);
+ hGrp->SetInt("Width", rect.width());
+ hGrp->SetInt("Height", rect.height());
+ }
+ rectOverlay = rect;
+
+ QPoint offset = getMainWindow()->getMdiArea()->pos();
+
+ if(getAutoHideRect(rect) || _state == State::Hint || _state == State::Hidden) {
+ QRect rectHint = rect;
+ if (_state != State::Hint && _state != State::Hidden)
+ startHide();
+ else if (count() && OverlayParams::getDockOverlayHintTabBar()) {
+ switch(dockArea) {
+ case Qt::LeftDockWidgetArea:
+ case Qt::RightDockWidgetArea:
+ if (dockArea == Qt::LeftDockWidgetArea)
+ rect.setWidth(tabBar()->width());
+ else
+ rect.setLeft(rect.left() + rect.width() - tabBar()->width());
+ rect.setHeight(std::max(rect.height(),
+ tabBar()->y() + tabBar()->sizeHint().height() + 5));
+ break;
+ case Qt::BottomDockWidgetArea:
+ case Qt::TopDockWidgetArea:
+ if (dockArea == Qt::TopDockWidgetArea)
+ rect.setHeight(tabBar()->height());
+ else
+ rect.setTop(rect.top() + rect.height() - tabBar()->height());
+ rect.setWidth(std::max(rect.width(),
+ tabBar()->x() + tabBar()->sizeHint().width() + 5));
+ break;
+ default:
+ break;
+ }
+
+ setGeometry(rect.translated(offset));
+ }
+ proxyWidget->setGeometry(rectHint.translated(offset));
+ if (count()) {
+ proxyWidget->show();
+ proxyWidget->raise();
+ } else
+ proxyWidget->hide();
+
+ } else {
+ setGeometry(rectOverlay.translated(offset));
+
+ for(int i=0, count=splitter->count(); iwidget(i)->show();
+
+ if(!isVisible() && count()) {
+ proxyWidget->hide();
+ startShow();
+ }
+ }
+}
+
+void OverlayTabWidget::addWidget(QDockWidget *dock, const QString &title)
+{
+ if (!getMainWindow() || !getMainWindow()->getMdiArea())
+ return;
+
+ OverlayManager::instance()->registerDockWidget(dock->objectName(), this);
+
+ OverlayManager::setFocusView();
+ getMainWindow()->removeDockWidget(dock);
+
+ auto titleWidget = dock->titleBarWidget();
+ if(titleWidget && titleWidget->objectName()==QStringLiteral("OverlayTitle")) {
+ // replace the title bar with an invisible widget to hide it. The
+ // OverlayTabWidget uses its own title bar for all docks.
+ auto w = new QWidget();
+ w->setObjectName(QStringLiteral("OverlayTitle"));
+ dock->setTitleBarWidget(w);
+ w->hide();
+ titleWidget->deleteLater();
+ }
+
+ dock->show();
+ splitter->addWidget(dock);
+ auto dummyWidget = new QWidget(this);
+ addTab(dummyWidget, title);
+ connect(dock, &QObject::destroyed, dummyWidget, &QObject::deleteLater);
+
+ dock->setFeatures(dock->features() & ~QDockWidget::DockWidgetFloatable);
+ if(count() == 1) {
+ QRect rect = dock->geometry();
+ QSize sizeMain = getMainWindow()->getMdiArea()->size();
+ switch(dockArea) {
+ case Qt::LeftDockWidgetArea:
+ case Qt::RightDockWidgetArea:
+ if (rect.width() > sizeMain.width()/3)
+ rect.setWidth(sizeMain.width()/3);
+ break;
+ case Qt::TopDockWidgetArea:
+ case Qt::BottomDockWidgetArea:
+ if (rect.height() > sizeMain.height()/3)
+ rect.setHeight(sizeMain.height()/3);
+ break;
+ default:
+ break;
+ }
+ setRect(rect);
+ }
+
+ saveTabs();
+}
+
+int OverlayTabWidget::dockWidgetIndex(QDockWidget *dock) const
+{
+ return splitter->indexOf(dock);
+}
+
+void OverlayTabWidget::removeWidget(QDockWidget *dock, QDockWidget *lastDock)
+{
+ int index = dockWidgetIndex(dock);
+ if(index < 0)
+ return;
+
+ OverlayManager::instance()->unregisterDockWidget(dock->objectName(), this);
+
+ OverlayManager::setFocusView();
+ dock->show();
+ if(lastDock)
+ getMainWindow()->tabifyDockWidget(lastDock, dock);
+ else
+ getMainWindow()->addDockWidget(dockArea, dock);
+
+ auto w = this->widget(index);
+ removeTab(index);
+ w->deleteLater();
+
+ if(!count())
+ hide();
+
+ w = dock->titleBarWidget();
+ if(w && w->objectName() == QStringLiteral("OverlayTitle")) {
+ dock->setTitleBarWidget(nullptr);
+ w->deleteLater();
+ }
+ OverlayManager::instance()->setupTitleBar(dock);
+
+ dock->setFeatures(dock->features() | QDockWidget::DockWidgetFloatable);
+
+ setOverlayMode(dock, OverlayOption::Disable);
+
+ saveTabs();
+}
+
+void OverlayTabWidget::resizeEvent(QResizeEvent *ev)
+{
+ QTabWidget::resizeEvent(ev);
+ if (_state <= State::Normal)
+ timer.start(10);
+}
+
+void OverlayTabWidget::setupLayout()
+{
+ if (_state > State::Normal)
+ return;
+
+ if(count() == 1)
+ tabSize = 0;
+ else {
+ int tsize;
+ if(dockArea==Qt::LeftDockWidgetArea || dockArea==Qt::RightDockWidgetArea)
+ tsize = tabBar()->width();
+ else
+ tsize = tabBar()->height();
+ tabSize = tsize;
+ }
+ int titleBarSize = widgetMinSize(this, true);
+ QRect rect, rectTitle;
+ switch(tabPosition()) {
+ case West:
+ rectTitle = QRect(tabSize, 0, this->width()-tabSize, titleBarSize);
+ rect = QRect(rectTitle.left(), rectTitle.bottom(),
+ rectTitle.width(), this->height()-rectTitle.height());
+ break;
+ case East:
+ rectTitle = QRect(0, 0, this->width()-tabSize, titleBarSize);
+ rect = QRect(rectTitle.left(), rectTitle.bottom(),
+ rectTitle.width(), this->height()-rectTitle.height());
+ break;
+ case North:
+ rectTitle = QRect(0, tabSize, titleBarSize, this->height()-tabSize);
+ rect = QRect(rectTitle.right(), rectTitle.top(),
+ this->width()-rectTitle.width(), rectTitle.height());
+ break;
+ case South:
+ rectTitle = QRect(0, 0, titleBarSize, this->height()-tabSize);
+ rect = QRect(rectTitle.right(), rectTitle.top(),
+ this->width()-rectTitle.width(), rectTitle.height());
+ break;
+ }
+ if (_animation != 0.0) {
+ switch(dockArea) {
+ case Qt::LeftDockWidgetArea:
+ rect.moveLeft(rect.left() - _animation * rect.width());
+ break;
+ case Qt::RightDockWidgetArea:
+ rect.moveLeft(rect.left() + _animation * rect.width());
+ break;
+ case Qt::TopDockWidgetArea:
+ rect.moveTop(rect.top() - _animation * rect.height());
+ break;
+ case Qt::BottomDockWidgetArea:
+ rect.moveTop(rect.top() + _animation * rect.height());
+ break;
+ default:
+ break;
+ }
+ }
+ splitter->setGeometry(rect);
+ titleBar->setGeometry(rectTitle);
+}
+
+void OverlayTabWidget::setCurrent(QDockWidget *widget)
+{
+ int index = dockWidgetIndex(widget);
+ if(index >= 0)
+ setCurrentIndex(index);
+}
+
+void OverlayTabWidget::onSplitterResize(int index)
+{
+ const auto &sizes = splitter->sizes();
+ if (index >= 0 && index < sizes.count()) {
+ if (sizes[index] == 0) {
+ if (currentIndex() == index) {
+ bool done = false;
+ for (int i=index+1; i 0) {
+ setCurrentIndex(i);
+ done = true;
+ break;
+ }
+ }
+ if (!done) {
+ for (int i=index-1; i>=0 ;--i) {
+ if (sizes[i] > 0) {
+ setCurrentIndex(i);
+ break;
+ }
+ }
+ }
+ }
+ } else
+ setCurrentIndex(index);
+ }
+
+ saveTabs();
+}
+
+void OverlayTabWidget::onCurrentChanged(int index)
+{
+ setState(State::Showing);
+
+ auto sizes = splitter->sizes();
+ int i=0;
+ int size = splitter->orientation()==Qt::Vertical ?
+ height()-tabBar()->height() : width()-tabBar()->width();
+ for(auto &s : sizes) {
+ if(i++ == index)
+ s = size;
+ else
+ s = 0;
+ }
+ splitter->setSizes(sizes);
+ onSplitterResize(index);
+ saveTabs();
+}
+
+void OverlayTabWidget::onSizeGripMove(const QPoint &p)
+{
+ if (!getMainWindow() || !getMainWindow()->getMdiArea())
+ return;
+
+ QPoint pos = mapFromGlobal(p) + this->pos();
+ QPoint offset = getMainWindow()->getMdiArea()->pos();
+ QRect rect = this->rectOverlay.translated(offset);
+
+ switch(dockArea) {
+ case Qt::LeftDockWidgetArea:
+ if (pos.x() - rect.left() < OverlayParams::getDockOverlayMinimumSize())
+ return;
+ rect.setRight(pos.x());
+ break;
+ case Qt::RightDockWidgetArea:
+ if (rect.right() - pos.x() < OverlayParams::getDockOverlayMinimumSize())
+ return;
+ rect.setLeft(pos.x());
+ break;
+ case Qt::TopDockWidgetArea:
+ if (pos.y() - rect.top() < OverlayParams::getDockOverlayMinimumSize())
+ return;
+ rect.setBottom(pos.y());
+ break;
+ default:
+ if (rect.bottom() - pos.y() < OverlayParams::getDockOverlayMinimumSize())
+ return;
+ rect.setTop(pos.y());
+ break;
+ }
+ this->setRect(rect.translated(-offset));
+ OverlayManager::instance()->refresh();
+}
+
+QLayoutItem *OverlayTabWidget::prepareTitleWidget(QWidget *widget, const QList &actions)
+{
+ bool vertical = false;
+ QBoxLayout *layout = nullptr;
+ auto tabWidget = qobject_cast(widget->parentWidget());
+ if(!tabWidget) {
+ layout = new QBoxLayout(QBoxLayout::LeftToRight, widget);
+ } else {
+ switch(tabWidget->getDockArea()) {
+ case Qt::LeftDockWidgetArea:
+ layout = new QBoxLayout(QBoxLayout::LeftToRight, widget);
+ break;
+ case Qt::RightDockWidgetArea:
+ layout = new QBoxLayout(QBoxLayout::RightToLeft, widget);
+ break;
+ case Qt::TopDockWidgetArea:
+ layout = new QBoxLayout(QBoxLayout::TopToBottom, widget);
+ vertical = true;
+ break;
+ case Qt::BottomDockWidgetArea:
+ layout = new QBoxLayout(QBoxLayout::BottomToTop, widget);
+ vertical = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ layout->addSpacing(5);
+ layout->setContentsMargins(1,1,1,1);
+ int buttonSize = widgetMinSize(widget);
+ auto spacer = new QSpacerItem(buttonSize,buttonSize,
+ vertical?QSizePolicy::Minimum:QSizePolicy::Expanding,
+ vertical?QSizePolicy::Expanding:QSizePolicy::Minimum);
+ layout->addSpacerItem(spacer);
+
+ for(auto action : actions)
+ layout->addWidget(OverlayTabWidget::createTitleButton(action, buttonSize));
+
+ if (tabWidget) {
+ auto grip = new OverlaySizeGrip(tabWidget, vertical);
+ QObject::connect(grip, &OverlaySizeGrip::dragMove,
+ tabWidget, &OverlayTabWidget::onSizeGripMove);
+ layout->addWidget(grip);
+ grip->raise();
+ }
+
+ return spacer;
+}
+
+// -----------------------------------------------------------
+
+OverlayTitleBar::OverlayTitleBar(QWidget * parent)
+ :QWidget(parent)
+{
+ setFocusPolicy(Qt::ClickFocus);
+ setMouseTracking(true);
+ setCursor(Qt::OpenHandCursor);
+}
+
+void OverlayTitleBar::setTitleItem(QLayoutItem *item)
+{
+ titleItem = item;
+}
+
+void OverlayTitleBar::paintEvent(QPaintEvent *)
+{
+ if (!titleItem)
+ return;
+
+ QDockWidget *dock = qobject_cast(parentWidget());
+ int vertical = false;
+ int flags = Qt::AlignCenter;
+ if (!dock) {
+ OverlayTabWidget *tabWidget = qobject_cast(parentWidget());
+ if (tabWidget) {
+ switch(tabWidget->getDockArea()) {
+ case Qt::TopDockWidgetArea:
+ vertical = true;
+ // fallthrough
+ case Qt::RightDockWidgetArea:
+ flags = Qt::AlignRight;
+ break;
+ case Qt::BottomDockWidgetArea:
+ vertical = true;
+ // fallthrough
+ case Qt::LeftDockWidgetArea:
+ flags = Qt::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ dock = tabWidget->dockWidget(0);
+ }
+ }
+ if (!dock)
+ return;
+
+ QPainter painter(this);
+ if (qobject_cast(parentWidget()))
+ painter.fillRect(this->rect(), painter.background());
+
+ QRect r = titleItem->geometry();
+ if (vertical) {
+ r = r.transposed();
+ painter.translate(r.left(), r.top() + r.width());
+ painter.rotate(-90);
+ painter.translate(-r.left(), -r.top());
+ }
+
+ QString title;
+ if (OverlayManager::instance()->isMouseTransparent()) {
+ if (timerId == 0)
+ timerId = startTimer(500);
+ title = blink ? tr("Mouse pass through, ESC to stop") : dock->windowTitle();
+ } else {
+ if (timerId != 0) {
+ killTimer(timerId);
+ timerId = 0;
+ }
+ title = dock->windowTitle();
+ }
+ QString text = painter.fontMetrics().elidedText(
+ title, Qt::ElideRight, r.width());
+ painter.drawText(r, flags, text);
+}
+
+void OverlayTitleBar::timerEvent(QTimerEvent *ev)
+{
+ if (timerId == ev->timerId()) {
+ update();
+ blink = !blink;
+ }
+}
+
+static inline bool
+isNear(const QPoint &a, const QPoint &b, int tol = 16)
+{
+ QPoint d = a - b;
+ return d.x()*d.x() + d.y()*d.y() < tol;
+}
+
+void OverlayTitleBar::endDrag()
+{
+ if (OverlayTabWidget::_Dragging == this) {
+ OverlayTabWidget::_Dragging = nullptr;
+ setCursor(Qt::OpenHandCursor);
+ if (OverlayTabWidget::_DragFrame)
+ OverlayTabWidget::_DragFrame->hide();
+ if (OverlayTabWidget::_DragFloating)
+ OverlayTabWidget::_DragFrame->hide();
+ }
+}
+
+void OverlayTitleBar::mouseMoveEvent(QMouseEvent *me)
+{
+ if (ignoreMouse) {
+ if (!(me->buttons() & Qt::LeftButton))
+ ignoreMouse = false;
+ else {
+ me->ignore();
+ return;
+ }
+ }
+
+ if (OverlayTabWidget::_Dragging != this && mouseMovePending && (me->buttons() & Qt::LeftButton)) {
+ if (isNear(dragOffset, me->pos()))
+ return;
+ mouseMovePending = false;
+ OverlayTabWidget::_Dragging = this;
+ }
+
+ if (OverlayTabWidget::_Dragging != this)
+ return;
+
+ if (!(me->buttons() & Qt::LeftButton)) {
+ endDrag();
+ return;
+ }
+ OverlayManager::instance()->dragDockWidget(me->globalPos(),
+ parentWidget(),
+ dragOffset,
+ dragSize);
+}
+
+void OverlayTitleBar::mousePressEvent(QMouseEvent *me)
+{
+ mouseMovePending = false;
+ QWidget *parent = parentWidget();
+ if (OverlayTabWidget::_Dragging || !parent || !getMainWindow() || me->button() != Qt::LeftButton)
+ return;
+
+ dragSize = parent->size();
+ OverlayTabWidget *tabWidget = qobject_cast(parent);
+ if (!tabWidget) {
+ if(QApplication::queryKeyboardModifiers() == Qt::ShiftModifier) {
+ ignoreMouse = true;
+ me->ignore();
+ return;
+ }
+ }
+ else {
+ for (int s : tabWidget->getSplitter()->sizes()) {
+ if (!s)
+ continue;
+ if (tabWidget == OverlayTabWidget::_TopOverlay
+ || tabWidget == OverlayTabWidget::_BottomOverlay) {
+ dragSize.setWidth(s + this->width());
+ dragSize.setHeight(tabWidget->height());
+ }
+ else {
+ dragSize.setHeight(s + this->height());
+ dragSize.setWidth(tabWidget->width());
+ }
+ }
+ }
+ ignoreMouse = false;
+ QSize mwSize = getMainWindow()->size();
+ dragSize.setWidth(std::max(OverlayParams::getDockOverlayMinimumSize(),
+ static_cast(std::min(mwSize.width()/2, dragSize.width()))));
+ dragSize.setHeight(std::max(OverlayParams::getDockOverlayMinimumSize(),
+ static_cast(std::min(mwSize.height()/2, dragSize.height()))));
+
+ dragOffset = me->pos();
+ setCursor(Qt::ClosedHandCursor);
+ mouseMovePending = true;
+}
+
+void OverlayTitleBar::mouseReleaseEvent(QMouseEvent *me)
+{
+ if (ignoreMouse) {
+ me->ignore();
+ return;
+ }
+
+ setCursor(Qt::OpenHandCursor);
+ mouseMovePending = false;
+ if (OverlayTabWidget::_Dragging != this)
+ return;
+
+ if (me->button() != Qt::LeftButton)
+ return;
+
+ OverlayTabWidget::_Dragging = nullptr;
+ OverlayManager::instance()->dragDockWidget(me->globalPos(),
+ parentWidget(),
+ dragOffset,
+ dragSize,
+ true);
+ if (OverlayTabWidget::_DragFrame)
+ OverlayTabWidget::_DragFrame->hide();
+ if (OverlayTabWidget::_DragFloating)
+ OverlayTabWidget::_DragFloating->hide();
+}
+
+void OverlayTitleBar::keyPressEvent(QKeyEvent *ke)
+{
+ if (OverlayTabWidget::_Dragging == this && ke->key() == Qt::Key_Escape)
+ endDrag();
+}
+
+
+// -----------------------------------------------------------
+
+OverlayDragFrame::OverlayDragFrame(QWidget * parent)
+ :QWidget(parent)
+{
+}
+
+void OverlayDragFrame::paintEvent(QPaintEvent *)
+{
+ QPainter painter(this);
+ painter.drawRect(0, 0, this->width()-1, this->height()-1);
+ painter.setOpacity(0.3);
+ painter.setBrush(QBrush(Qt::blue));
+ painter.drawRect(0, 0, this->width()-1, this->height()-1);
+}
+
+QSize OverlayDragFrame::sizeHint() const
+{
+ return size();
+}
+
+QSize OverlayDragFrame::minimumSizeHint() const
+{
+ return minimumSize();
+}
+
+// -----------------------------------------------------------
+
+OverlaySizeGrip::OverlaySizeGrip(QWidget * parent, bool vertical)
+ :QWidget(parent), vertical(vertical)
+{
+ if (vertical) {
+ this->setFixedHeight(6);
+ this->setMinimumWidth(widgetMinSize(this,true));
+ this->setCursor(Qt::SizeVerCursor);
+ }
+ else {
+ this->setFixedWidth(6);
+ this->setMinimumHeight(widgetMinSize(this,true));
+ this->setCursor(Qt::SizeHorCursor);
+ }
+ setMouseTracking(true);
+}
+
+void OverlaySizeGrip::paintEvent(QPaintEvent*)
+{
+ QPainter painter(this);
+ painter.setPen(Qt::transparent);
+ painter.setOpacity(0.5);
+ painter.setBrush(QBrush(Qt::black, Qt::Dense6Pattern));
+ QRect rect(this->rect());
+ painter.drawRect(rect);
+}
+
+void OverlaySizeGrip::mouseMoveEvent(QMouseEvent *me)
+{
+ if ((me->buttons() & Qt::LeftButton))
+ Q_EMIT dragMove(me->globalPos());
+}
+
+void OverlaySizeGrip::mousePressEvent(QMouseEvent *)
+{
+}
+
+void OverlaySizeGrip::mouseReleaseEvent(QMouseEvent *)
+{
+}
+
+// -----------------------------------------------------------
+
+OverlaySplitter::OverlaySplitter(QWidget *parent)
+ : QSplitter(parent)
+{
+}
+
+QSplitterHandle * OverlaySplitter::createHandle()
+{
+ auto widget = new OverlaySplitterHandle(this->orientation(), this);
+ widget->setObjectName(QStringLiteral("OverlaySplitHandle"));
+ QList actions;
+ actions.append(&widget->actFloat);
+ widget->setTitleItem(OverlayTabWidget::prepareTitleWidget(widget, actions));
+ return widget;
+}
+
+// -----------------------------------------------------------
+
+OverlaySplitterHandle::OverlaySplitterHandle(Qt::Orientation orientation, QSplitter *parent)
+ : QSplitterHandle(orientation, parent)
+{
+ setMouseTracking(true);
+ setFocusPolicy(Qt::ClickFocus);
+ retranslate();
+ refreshIcons();
+ QObject::connect(&actFloat, &QAction::triggered, this, &OverlaySplitterHandle::onAction);
+ timer.setSingleShot(true);
+ QObject::connect(&timer, &QTimer::timeout, this, &OverlaySplitterHandle::onTimer);
+}
+
+void OverlaySplitterHandle::refreshIcons()
+{
+ actFloat.setIcon(BitmapFactory().pixmap("qss:overlay/float.svg"));
+}
+
+void OverlaySplitterHandle::onTimer()
+{
+ if (isVisible() && qApp->widgetAt(QCursor::pos()) != this)
+ showTitle(false);
+}
+
+void OverlaySplitterHandle::showEvent(QShowEvent *ev)
+{
+ if (OverlayParams::getDockOverlaySplitterHandleTimeout() > 0
+ && qApp->widgetAt(QCursor::pos()) != this)
+ timer.start(OverlayParams::getDockOverlaySplitterHandleTimeout());
+ QSplitterHandle::showEvent(ev);
+}
+
+void OverlaySplitterHandle::enterEvent(QEvent *ev)
+{
+ timer.stop();
+ QSplitterHandle::enterEvent(ev);
+}
+
+void OverlaySplitterHandle::leaveEvent(QEvent *ev)
+{
+ if (OverlayParams::getDockOverlaySplitterHandleTimeout() > 0)
+ timer.start(OverlayParams::getDockOverlaySplitterHandleTimeout());
+ QSplitterHandle::leaveEvent(ev);
+}
+
+QSize OverlaySplitterHandle::sizeHint() const
+{
+ QSize size = QSplitterHandle::sizeHint();
+ int minSize = widgetMinSize(this,true);
+ if (this->orientation() == Qt::Vertical)
+ size.setHeight(std::max(minSize, size.height()));
+ else
+ size.setWidth(std::max(minSize, size.width()));
+ return size;
+}
+
+void OverlaySplitterHandle::onAction()
+{
+ auto action = qobject_cast(sender());
+ if(action == &actFloat) {
+ QDockWidget *dock = dockWidget();
+ if (dock)
+ OverlayManager::instance()->floatDockWidget(dock);
+ }
+}
+
+QDockWidget *OverlaySplitterHandle::dockWidget()
+{
+ QSplitter *parent = splitter();
+ if (!parent)
+ return nullptr;
+
+ if (parent->handle(this->idx) != this) {
+ this->idx = -1;
+ for (int i=0, c=parent->count(); ihandle(i) == this) {
+ this->idx = i;
+ break;
+ }
+ }
+ }
+ return qobject_cast(parent->widget(this->idx));
+}
+
+void OverlaySplitterHandle::retranslate()
+{
+ actFloat.setToolTip(QObject::tr("Toggle floating window"));
+}
+
+void OverlaySplitterHandle::changeEvent(QEvent *e)
+{
+ QSplitterHandle::changeEvent(e);
+ if (e->type() == QEvent::LanguageChange)
+ retranslate();
+}
+
+void OverlaySplitterHandle::setTitleItem(QLayoutItem *item)
+{
+ titleItem = item;
+}
+
+void OverlaySplitterHandle::showTitle(bool enable)
+{
+ if (_showTitle == enable)
+ return;
+ if (!enable)
+ unsetCursor();
+ else {
+ setCursor(this->orientation() == Qt::Horizontal
+ ? Qt::SizeHorCursor : Qt::SizeVerCursor);
+ if (OverlayParams::getDockOverlaySplitterHandleTimeout() > 0
+ && qApp->widgetAt(QCursor::pos()) != this)
+ timer.start(OverlayParams::getDockOverlaySplitterHandleTimeout());
+ }
+ _showTitle = enable;
+ for (auto child : findChildren(QString(), Qt::FindDirectChildrenOnly))
+ child->setVisible(enable);
+ update();
+}
+
+void OverlaySplitterHandle::paintEvent(QPaintEvent *e)
+{
+ if (!_showTitle)
+ return;
+
+ if (!titleItem) {
+ QSplitterHandle::paintEvent(e);
+ return;
+ }
+
+ int flags = Qt::AlignCenter;
+ auto tabWidget = qobject_cast(
+ splitter() ? splitter()->parentWidget() : nullptr);
+
+ if (tabWidget) {
+ switch(tabWidget->getDockArea()) {
+ case Qt::TopDockWidgetArea:
+ case Qt::RightDockWidgetArea:
+ flags = Qt::AlignRight;
+ break;
+ case Qt::BottomDockWidgetArea:
+ case Qt::LeftDockWidgetArea:
+ flags = Qt::AlignLeft;
+ break;
+ default:
+ break;
+ }
+ }
+
+ QDockWidget *dock = dockWidget();
+ if (!dock) {
+ QSplitterHandle::paintEvent(e);
+ return;
+ }
+
+ QPainter painter(this);
+ painter.fillRect(this->rect(), painter.background());
+
+ QRect r = titleItem->geometry();
+ if (this->orientation() != Qt::Vertical) {
+ r = r.transposed();
+ painter.translate(r.left(), r.top() + r.width());
+ painter.rotate(-90);
+ painter.translate(-r.left(), -r.top());
+ }
+ QString text = painter.fontMetrics().elidedText(
+ dock->windowTitle(), Qt::ElideRight, r.width());
+
+ painter.drawText(r, flags, text);
+}
+
+void OverlaySplitterHandle::endDrag()
+{
+ auto tabWidget = qobject_cast(splitter()->parentWidget());
+ if (tabWidget) {
+ dockWidget();
+ tabWidget->onSplitterResize(this->idx);
+ }
+ OverlayTabWidget::_Dragging = nullptr;
+ setCursor(this->orientation() == Qt::Horizontal
+ ? Qt::SizeHorCursor : Qt::SizeVerCursor);
+ if (OverlayTabWidget::_DragFrame)
+ OverlayTabWidget::_DragFrame->hide();
+ if (OverlayTabWidget::_DragFloating)
+ OverlayTabWidget::_DragFloating->hide();
+}
+
+void OverlaySplitterHandle::keyPressEvent(QKeyEvent *ke)
+{
+ if (OverlayTabWidget::_Dragging == this && ke->key() == Qt::Key_Escape)
+ endDrag();
+}
+
+void OverlaySplitterHandle::mouseMoveEvent(QMouseEvent *me)
+{
+ if (OverlayTabWidget::_Dragging != this)
+ return;
+
+ if (!(me->buttons() & Qt::LeftButton)) {
+ endDrag();
+ return;
+ }
+
+ if (dragging == 1) {
+ OverlayTabWidget *overlay = qobject_cast(
+ splitter()->parentWidget());
+ QPoint pos = me->pos();
+ if (overlay) {
+ switch(overlay->getDockArea()) {
+ case Qt::LeftDockWidgetArea:
+ case Qt::RightDockWidgetArea:
+ if (pos.x() < 0 || pos.x() > overlay->width())
+ dragging = 2;
+ break;
+ case Qt::TopDockWidgetArea:
+ case Qt::BottomDockWidgetArea:
+ if (pos.y() < 0 || pos.y() > overlay->height())
+ dragging = 2;
+ break;
+ default:
+ break;
+ }
+ }
+ if (dragging == 1) {
+ QPoint offset = parentWidget()->mapFromGlobal(me->globalPos()) - dragOffset;
+ moveSplitter(this->orientation() == Qt::Horizontal ? offset.x() : offset.y());
+ return;
+ }
+ setCursor(Qt::ClosedHandCursor);
+ }
+
+ OverlayManager::instance()->dragDockWidget(me->globalPos(),
+ dockWidget(),
+ dragOffset,
+ dragSize);
+}
+
+void OverlaySplitterHandle::mousePressEvent(QMouseEvent *me)
+{
+ if (OverlayTabWidget::_Dragging || !getMainWindow() || me->button() != Qt::LeftButton)
+ return;
+
+ OverlayTabWidget::_Dragging = this;
+ dragging = 1;
+ dragOffset = me->pos();
+ auto dock = dockWidget();
+ if (dock) {
+ dragSize = dock->size();
+ dock->show();
+ } else
+ dragSize = QSize();
+
+ QSize mwSize = getMainWindow()->size();
+ dragSize.setWidth(std::max(OverlayParams::getDockOverlayMinimumSize(),
+ static_cast(std::min(mwSize.width()/2, dragSize.width()))));
+ dragSize.setHeight(std::max(OverlayParams::getDockOverlayMinimumSize(),
+ static_cast(std::min(mwSize.height()/2, dragSize.height()))));
+
+}
+
+void OverlaySplitterHandle::mouseReleaseEvent(QMouseEvent *me)
+{
+ if (OverlayTabWidget::_Dragging != this || me->button() != Qt::LeftButton)
+ return;
+
+ if (dragging == 1) {
+ endDrag();
+ return;
+ }
+ endDrag();
+ OverlayManager::instance()->dragDockWidget(me->globalPos(),
+ dockWidget(),
+ dragOffset,
+ dragSize,
+ true);
+ // Warning! the handle itself maybe deleted after return from
+ // dragDockWidget().
+}
+
+// -----------------------------------------------------------
+
+OverlayGraphicsEffect::OverlayGraphicsEffect(QObject *parent) :
+ QGraphicsEffect(parent),
+ _enabled(false),
+ _size(1,1),
+ _blurRadius(2.0f),
+ _color(0, 0, 0, 80)
+{
+}
+
+QT_BEGIN_NAMESPACE
+ extern Q_WIDGETS_EXPORT void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0 );
+QT_END_NAMESPACE
+
+void OverlayGraphicsEffect::draw(QPainter* painter)
+{
+ // if nothing to show outside the item, just draw source
+ if (!_enabled || _blurRadius + _size.height() <= 0 || _blurRadius + _size.width() <= 0) {
+ drawSource(painter);
+ return;
+ }
+
+ PixmapPadMode mode = QGraphicsEffect::PadToEffectiveBoundingRect;
+ QPoint offset;
+ QPixmap px = sourcePixmap(Qt::DeviceCoordinates, &offset, mode);
+
+ // return if no source
+ if (px.isNull())
+ return;
+
+#if 0
+ if (FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
+ static int count;
+ getMainWindow()->showMessage(
+ QStringLiteral("dock overlay redraw %1").arg(count++));
+ }
+#endif
+
+ QTransform restoreTransform = painter->worldTransform();
+ painter->setWorldTransform(QTransform());
+
+ // Calculate size for the background image
+ QImage tmp(px.size(), QImage::Format_ARGB32_Premultiplied);
+ tmp.setDevicePixelRatio(px.devicePixelRatioF());
+ tmp.fill(0);
+ QPainter tmpPainter(&tmp);
+ QPainterPath clip;
+ tmpPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ if(_size.width() == 0 && _size.height() == 0)
+ tmpPainter.drawPixmap(QPoint(0, 0), px);
+ else {
+ // exclude splitter handles
+ auto splitter = qobject_cast(parent());
+ if (splitter) {
+ int i = -1;
+ for (int size : splitter->sizes()) {
+ ++i;
+ if (!size)
+ continue;
+ QWidget *w = splitter->widget(i);
+ if (w->findChild())
+ continue;
+ QRect rect = w->geometry();
+ if (splitter->orientation() == Qt::Vertical)
+ clip.addRect(rect.x(), rect.y()+4,
+ rect.width(), rect.height()-4);
+ else
+ clip.addRect(rect.x()+4, rect.y(),
+ rect.width()-4, rect.height());
+ }
+ if (clip.isEmpty()) {
+ drawSource(painter);
+ return;
+ }
+ tmpPainter.setClipPath(clip);
+ }
+
+ for (int x=-_size.width();x<=_size.width();++x) {
+ for (int y=-_size.height();y<=_size.height();++y) {
+ if (x || y) {
+ tmpPainter.drawPixmap(QPoint(x, y), px);
+ tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceOver);
+ }
+ }
+ }
+ }
+ tmpPainter.end();
+
+ // blur the alpha channel
+ QImage blurred(tmp.size(), QImage::Format_ARGB32_Premultiplied);
+ blurred.setDevicePixelRatio(px.devicePixelRatioF());
+ blurred.fill(0);
+ QPainter blurPainter(&blurred);
+ qt_blurImage(&blurPainter, tmp, blurRadius(), false, true);
+ blurPainter.end();
+
+ tmp = blurred;
+
+ // blacken the image...
+ tmpPainter.begin(&tmp);
+ tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
+ tmpPainter.fillRect(tmp.rect(), color());
+ tmpPainter.end();
+
+ // draw the blurred shadow...
+ painter->drawImage(QPointF(offset.x()+_offset.x(), offset.y()+_offset.y()), tmp);
+
+ // draw the actual pixmap...
+ painter->drawPixmap(offset, px, QRectF());
+
+#if 0
+ QWidget *focus = qApp->focusWidget();
+ if (focus) {
+ QWidget *widget = qobject_cast(this->parent());
+ if (auto *edit = qobject_cast(focus)) {
+ if (!edit->isReadOnly() && edit->isEnabled()) {
+ for(auto w=edit->parentWidget(); w; w=w->parentWidget()) {
+ if (w == widget) {
+ QRect r = edit->cursorRect();
+ QRect rect(edit->viewport()->mapTo(widget, r.topLeft()),
+ edit->viewport()->mapTo(widget, r.bottomRight()));
+ // painter->fillRect(rect, edit->textColor());
+ // painter->fillRect(rect, edit->currentCharFormat().foreground());
+ painter->fillRect(rect.translated(offset), Qt::white);
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ // restore world transform
+ painter->setWorldTransform(restoreTransform);
+}
+
+QRectF OverlayGraphicsEffect::boundingRectFor(const QRectF& rect) const
+{
+ if (!_enabled)
+ return rect;
+ return rect.united(rect.adjusted(-_blurRadius - _size.width() + _offset.x(),
+ -_blurRadius - _size.height()+ _offset.y(),
+ _blurRadius + _size.width() + _offset.x(),
+ _blurRadius + _size.height() + _offset.y()));
+}
+
+#include "moc_OverlayWidgets.cpp"
diff --git a/src/Gui/OverlayWidgets.h b/src/Gui/OverlayWidgets.h
new file mode 100644
index 0000000000..9f71ced9c3
--- /dev/null
+++ b/src/Gui/OverlayWidgets.h
@@ -0,0 +1,630 @@
+/****************************************************************************
+ * Copyright (c) 2020 Zheng Lei (realthunder) *
+ * *
+ * 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 FC_OVERLAYWIDGETS_H
+#define FC_OVERLAYWIDGETS_H
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "OverlayManager.h"
+
+class QPropertyAnimation;
+class QLayoutItem;
+
+namespace Gui {
+
+class OverlayTabWidget;
+class OverlayTitleBar;
+class OverlaySplitterHandle;
+class OverlaySizeGrip;
+class OverlayProxyWidget;
+class OverlayGraphicsEffect;
+class OverlayDragFrame;
+
+/// Tab widget to contain dock widgets in overlay mode
+class OverlayTabWidget: public QTabWidget
+{
+ Q_OBJECT
+
+ /** @name Graphics effect properties for customization through stylesheet */
+ //@{
+ Q_PROPERTY(QColor effectColor READ effectColor WRITE setEffectColor) // clazy:exclude=qproperty-without-notify
+ Q_PROPERTY(int effectWidth READ effectWidth WRITE setEffectWidth) // clazy:exclude=qproperty-without-notify
+ Q_PROPERTY(int effectHeight READ effectHeight WRITE setEffectHeight) // clazy:exclude=qproperty-without-notify
+ Q_PROPERTY(qreal effectOffsetX READ effectOffsetX WRITE setEffectOffsetX) // clazy:exclude=qproperty-without-notify
+ Q_PROPERTY(qreal effectOffsetY READ effectOffsetY WRITE setEffectOffsetY) // clazy:exclude=qproperty-without-notify
+ Q_PROPERTY(qreal effectBlurRadius READ effectBlurRadius WRITE setEffectBlurRadius) // clazy:exclude=qproperty-without-notify
+ Q_PROPERTY(bool enableEffect READ effectEnabled WRITE setEffectEnabled) // clazy:exclude=qproperty-without-notify
+ Q_PROPERTY(qreal animation READ animation WRITE setAnimation) // clazy:exclude=qproperty-without-notify
+ //@}
+
+public:
+ /** Constructor
+ * @param parent: parent widget
+ * @param pos: docking position
+ */
+ OverlayTabWidget(QWidget *parent, Qt::DockWidgetArea pos);
+
+ /// Enable/disable overlay mode for this tab widget
+ void setOverlayMode(bool enable);
+
+ /// Update splitter handle according to overlay status
+ void updateSplitterHandles();
+
+ /** Add a dock widget
+ * @param widget: dock widget to be added
+ * @param title: title for the dock widget
+ */
+ void addWidget(QDockWidget *widget, const QString &title);
+
+ /** Remove a dock widget
+ * @param widget: dock widget to be removed
+ * @param last: optional non overlaid widget. If given, then the removed
+ * dock widget will be tabified together with this one.
+ */
+ void removeWidget(QDockWidget *widget, QDockWidget *last=nullptr);
+
+ /** Set the current dock widget
+ * @param widget: an overlay dock widget
+ *
+ * All other dock widget in the same tab widget will be collapsed, and the
+ * give widget will take the whole space. This is actually handled inside
+ * onCurrentChanged().
+ */
+ void setCurrent(QDockWidget *widget);
+
+ /** Handle ESC key press
+ *
+ * If the this overlay tab widget is hidden and its hint/tabs are visible,
+ * pressing ESC will hide the hint and tabs.
+ *
+ * If this overlay tab widget is visible and the current mouse cursor is on
+ * top of the tab widget title bar or any of its split handler, then
+ * pressing ESC will hide the title bar and split handler.
+ */
+ bool onEscape();
+
+ /// Enable/disable transparent background mode
+ void setTransparent(bool enable);
+
+ /// Check if transparent background mode is active
+ bool isTransparent() const;
+
+ /// Auto mode to show or hide the tab widget
+ enum class AutoMode {
+ /// No auto show or hide
+ NoAutoMode,
+ /// Auto hide tab widget on lost of focus
+ AutoHide,
+ /// Auto show tab widget on any new editing task
+ EditShow,
+ /// Auto hide tab widget on any new editing task
+ EditHide,
+ /// Auto show on any task panel e.g. suggestive task panel in PartDesign
+ TaskShow,
+ };
+ /// Set auto mode to show or hide the tab widget
+ void setAutoMode(AutoMode mode);
+ /// Get current auto mode
+ AutoMode getAutoMode() const { return autoMode; }
+
+ /// Touch the tab widget to trigger saving of settings
+ void touch() {touched = true;}
+ /// Check if the tab widget settings need to be saved
+ bool isTouched() const {return touched;}
+
+ /// Set geometry of this tab widget
+ void setRect(QRect rect);
+
+ /// Get the geometry of this tab widget
+ const QRect &getRect();
+
+ /// Overlay query option
+ enum class QueryOption {
+ /// Report the current overlay status
+ QueryOverlay,
+ /// Report true if transparency status has been changed
+ TransparencyChanged,
+ /// Report true if transparency status has not been changed
+ TransparencyNotChanged,
+ };
+ /// Query overlay status
+ bool isOverlaid(QueryOption option=QueryOption::QueryOverlay) const;
+ /** Check if needs to auto hide this tab widget
+ *
+ * Besides when auto hide mode is activated by user, the tab widget will
+ * also auto hide if the current view does not have panning capability
+ * (queried through MdiView::hasMsg("CanPan")). The user can explicitly
+ * disable this auto hide if no pan by setting user parameter
+ * View/DockOverlayAutoView, or preference option Display -> UI -> Auto
+ * hide in non 3D view.
+ */
+ bool checkAutoHide() const;
+ /** Obtain geometry of auto hiding tab widget
+ * @param rect: output geometry of the tab widget
+ * @return Return true if the tab widget should be auto hiding
+ */
+ bool getAutoHideRect(QRect &rect) const;
+ /// Handler of various actions exposed as buttons on title bar
+ void onAction(QAction *);
+ /// Sync relevant actions status with the current auto mode
+ void syncAutoMode();
+
+ /** Set tab widget position offset
+ * @param ofs: the offset size. Width is the x offset for top and bottom
+ * docking tab widget, and y offset for left and right ones. Height is the y
+ * offset for top and bottom, and x offset for left and right ones.
+ */
+ void setOffset(const QSize &ofs);
+ /// Get the tab widget position offset
+ const QSize &getOffset() const {return offset;}
+
+ /** Set tab widget size delta
+ * @param delta: the size delta. For left and right widget, the delta is
+ * added to the height of the tab widget. For top and bottom widget, it is
+ * added to the width.
+ */
+ void setSizeDelta(int delta);
+ /// Get the tab widget size delta
+ int getSizeDelta() const {return sizeDelta;}
+
+ /// Obtain the proxy widget
+ OverlayProxyWidget *getProxyWidget() {return proxyWidget;}
+
+ /// Obtain the current dock widget
+ QDockWidget *currentDockWidget() const;
+ /// Obtain the dock widget by index
+ QDockWidget *dockWidget(int index) const;
+ /// Obtain the index of a given dock widget
+ int dockWidgetIndex(QDockWidget *) const;
+
+ /// Set the title bar for this tab widget
+ void setTitleBar(QWidget *);
+
+ /// Get the splitter
+ QSplitter *getSplitter() const {return splitter;}
+ /// Get the title bar
+ QWidget *getTitleBar() const {return titleBar;}
+
+ /// Get the docking position of this tab widget
+ Qt::DockWidgetArea getDockArea() const {return dockArea;}
+
+ /// Get delay time for animated reveal
+ const QTime &getRevealTime() const {return revealTime;}
+ /// Set delay time for animated reveal
+ void setRevealTime(const QTime &time);
+
+ /// Restore state
+ void restore(ParameterGrp::handle handle);
+ /// Save tab orders and positions
+ void saveTabs();
+
+ /** @name Graphics effect properties setters and getters */
+ //@{
+ QColor effectColor() const;
+ void setEffectColor(const QColor&);
+ int effectWidth() const;
+ void setEffectWidth(int);
+ int effectHeight() const;
+ void setEffectHeight(int);
+ qreal effectOffsetX() const;
+ void setEffectOffsetX(qreal);
+ qreal effectOffsetY() const;
+ void setEffectOffsetY(qreal);
+ qreal effectBlurRadius() const;
+ void setEffectBlurRadius(qreal);
+ bool effectEnabled() const;
+ void setEffectEnabled(bool);
+ qreal animation() const {return _animation;}
+ void setAnimation(qreal);
+ //@}
+
+ /// Schedule for repaint
+ void scheduleRepaint();
+
+ /** Return the pixel alpha value at the give position
+ * @param pos: position
+ * @param radiusScale: scale of the radius to check for alpha.
+ *
+ * @return Returns the largest alpha value of a circular area of 'pos' as
+ * center and radius as defined by user parameter
+ * View/DockOverlayAlphaRadius. May return -1 if out side of the widget, or
+ * zero if transparent.
+ */
+ int testAlpha(const QPoint &pos, int radiusScale);
+
+ /// Start animated showing
+ void startShow();
+ /// Start animated hiding
+ void startHide();
+
+ /// Internal state of the tab widget
+ enum class State {
+ /// The tab widget is showing
+ Showing,
+ /// Normal visible state
+ Normal,
+ /// Visual hint is visible
+ Hint,
+ /// Hint is hidden by user after pressing ESC
+ HintHidden,
+ /// The tab widget is explicitly hidden by user
+ Hidden,
+ };
+ /// Set state of the tab widget
+ void setState(State);
+ /// Get the state of the widget
+ State getState() const {return _state;}
+
+ /// Handle splitter resize
+ void onSplitterResize(int index);
+
+ /// Check if the tab widget is saving its state
+ bool isSaving() const {return _saving;}
+
+ /// Helper function to create title bar for a dock widget
+ static QWidget *createTitleButton(QAction *action, int size);
+ /// Helper function to prepare a widget as a title widget
+ static QLayoutItem *prepareTitleWidget(QWidget *widget, const QList &actions);
+
+protected:
+ void leaveEvent(QEvent*);
+ void enterEvent(QEvent*);
+ void changeEvent(QEvent*);
+ void resizeEvent(QResizeEvent*);
+ void paintEvent(QPaintEvent *);
+ bool event(QEvent *ev);
+ bool eventFilter(QObject *, QEvent *ev);
+
+ void retranslate();
+ void refreshIcons();
+
+ /// Overlay mode options
+ enum class OverlayOption {
+ /// Enable overlay
+ Enable,
+ /// Disable overlay
+ Disable,
+ /// Enable overlay and show tab bar
+ ShowTab,
+ };
+ /// Toggle overlay mode for a given widget
+ void setOverlayMode(QWidget *widget, OverlayOption option);
+ /// Helper function to set overlay mode for a give widget
+ static void _setOverlayMode(QWidget *widget, OverlayOption option);
+
+protected:
+ void onCurrentChanged(int index);
+ void onTabMoved(int from, int to);
+ void onRepaint();
+ void onAnimationStateChanged();
+ void setupLayout();
+ void onSizeGripMove(const QPoint &);
+
+private:
+ friend class OverlayProxyWidget;
+ friend class OverlayTitleBar;
+ friend class OverlayManager;
+ friend class OverlayManager::Private;
+ friend class OverlaySplitterHandle;
+ friend class OverlaySizeGrip;
+
+ QSize offset;
+ int sizeDelta = 0;
+ QRect rectOverlay;
+ OverlayProxyWidget *proxyWidget;
+ QSplitter *splitter = nullptr;
+ QWidget *titleBar = nullptr;
+ QAction actNoAutoMode;
+ QAction actAutoHide;
+ QAction actEditHide;
+ QAction actEditShow;
+ QAction actTaskShow;
+ QAction actAutoMode;
+ QMenu autoModeMenu;
+ QAction actTransparent;
+ QAction actIncrease;
+ QAction actDecrease;
+ QAction actOverlay;
+ QTimer timer;
+ QTimer repaintTimer;
+ AutoMode autoMode = AutoMode::NoAutoMode;
+ bool repainting = false;
+ bool overlaid = false;
+ bool currentTransparent = false;
+ bool touched = false;
+ bool busy = false;
+ Qt::DockWidgetArea dockArea;
+ int tabSize = 0;
+ QTime revealTime;
+ ParameterGrp::handle hGrp;
+
+ OverlayGraphicsEffect *_graphicsEffect = nullptr;
+ OverlayGraphicsEffect *_graphicsEffectTab = nullptr;
+ bool _effectEnabled = false;
+
+ QImage _image;
+ qreal _imageScale;
+
+ qreal _animation = 0;
+ QPropertyAnimation *_animator = nullptr;
+
+ State _state = State::Normal;
+
+ std::map _sizemap;
+ bool _saving = false;
+
+ static OverlayDragFrame *_DragFrame;
+ static QDockWidget *_DragFloating;
+ static QWidget *_Dragging;
+ static OverlayTabWidget *_LeftOverlay;
+ static OverlayTabWidget *_RightOverlay;
+ static OverlayTabWidget *_TopOverlay;
+ static OverlayTabWidget *_BottomOverlay;
+};
+
+/// A translucent frame as a visual indicator when dragging a dock widget
+class OverlayDragFrame: public QWidget
+{
+ Q_OBJECT
+public:
+ OverlayDragFrame(QWidget * parent);
+ QSize sizeHint() const;
+ QSize minimumSizeHint() const;
+
+protected:
+ void paintEvent(QPaintEvent*);
+};
+
+/// Title bar for OverlayTabWidget
+class OverlayTitleBar: public QWidget
+{
+ Q_OBJECT
+public:
+ OverlayTitleBar(QWidget * parent);
+ void setTitleItem(QLayoutItem *);
+ void endDrag();
+
+protected:
+ void mouseMoveEvent(QMouseEvent *);
+ void mousePressEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ void paintEvent(QPaintEvent*);
+ void keyPressEvent(QKeyEvent *ke);
+ void timerEvent(QTimerEvent *);
+
+private:
+ QPoint dragOffset;
+ QSize dragSize;
+ QLayoutItem *titleItem = nullptr;
+ QColor textcolor;
+ int timerId = 0;
+ bool blink = false;
+ bool mouseMovePending = false;
+ bool ignoreMouse = false;
+};
+
+/// Size grip for title bar and split handler of OverlayTabWidget
+class OverlaySizeGrip: public QWidget
+{
+ Q_OBJECT
+public:
+ OverlaySizeGrip(QWidget *parent, bool vertical);
+
+Q_SIGNALS:
+ void dragMove(const QPoint &globalPos);
+
+protected:
+ void paintEvent(QPaintEvent*);
+ void mouseMoveEvent(QMouseEvent *);
+ void mousePressEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+ const QPixmap &pixmap() const;
+
+private:
+ bool vertical;
+};
+
+/// Splitter for OverlayTabWidget
+class OverlaySplitter : public QSplitter
+{
+ Q_OBJECT
+public:
+ OverlaySplitter(QWidget *parent);
+ void retranslate();
+
+protected:
+ virtual QSplitterHandle *createHandle();
+};
+
+
+/// Splitter handle for dragging the splitter
+class OverlaySplitterHandle : public QSplitterHandle
+{
+ Q_OBJECT
+public:
+ friend class OverlaySplitter;
+
+ OverlaySplitterHandle(Qt::Orientation, QSplitter *parent);
+ void setTitleItem(QLayoutItem *);
+ void retranslate();
+ void refreshIcons();
+ QDockWidget * dockWidget();
+
+ void showTitle(bool enable);
+ bool isShowing() const { return _showTitle; }
+ void endDrag();
+
+protected:
+ virtual void showEvent(QShowEvent *);
+ virtual void enterEvent(QEvent *);
+ virtual void leaveEvent(QEvent *);
+ virtual void paintEvent(QPaintEvent*);
+ virtual void changeEvent(QEvent*);
+ virtual void mouseMoveEvent(QMouseEvent *);
+ virtual void mousePressEvent(QMouseEvent *);
+ virtual void mouseReleaseEvent(QMouseEvent *);
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual QSize sizeHint() const;
+
+protected:
+ void onAction();
+ void onTimer();
+
+private:
+ QLayoutItem * titleItem = nullptr;
+ int idx = -1;
+ QAction actFloat;
+ bool _showTitle = true;
+ int dragging = 0;
+ QPoint dragOffset;
+ QSize dragSize;
+ QTimer timer;
+};
+
+
+/// Tool button for the title bar of the OverlayTabWidget
+class OverlayToolButton: public QToolButton
+{
+ Q_OBJECT
+public:
+ OverlayToolButton(QWidget *parent);
+};
+
+/** Class for handling visual hint for bringing back hidden overlay dock widget
+ *
+ * The proxy widget is transparent except a customizable rectangle area with a
+ * selectable color shown as the visual hint. The hint is normally hidden, and
+ * is shown only if the mouse hovers within the widget. When the hint area is
+ * clicked, it will bring back hidden overlay dock panel. Note that the proxy
+ * widget itself is mouse transparent as well, meaning that it will not receive
+ * any mouse event. It is handled in the OverlayManager event filter.
+ */
+class OverlayProxyWidget: public QWidget
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QBrush hintColor READ hintColor WRITE setHintColor) // clazy:exclude=qproperty-without-notify
+
+public:
+ OverlayProxyWidget(OverlayTabWidget *);
+
+ OverlayTabWidget *getOwner() const {return owner;}
+
+ /// For representing hit region
+ enum class HitTest {
+ /// Not hitting
+ HitNone = 0,
+ /// Hitting the proxy widget size but not within the visible hint area.
+ HitOuter = 1,
+ /// Hitting the visible hint area.
+ HitInner = 2,
+ };
+ /** Mouse cursor hit test
+ * @param pos: cursor position
+ * @param delay: Whether to delay showing hint on mouse hit
+ */
+ HitTest hitTest(const QPoint &pos, bool delay=true);
+
+ /// Check if the visual hint is showing
+ bool isActivated() const;
+
+ QBrush hintColor() const;
+ void setHintColor(const QBrush &);
+
+ QRect getRect() const;
+
+ void onMousePress();
+
+protected:
+ void enterEvent(QEvent*);
+ void hideEvent(QHideEvent*);
+ void paintEvent(QPaintEvent*);
+
+protected:
+ void onTimer();
+
+private:
+ OverlayTabWidget* owner;
+ int drawLine = false;
+ int dockArea;
+ QTimer timer;
+ QBrush _hintColor;
+};
+
+/** Graphic effects for drawing shadow and outline of text on transparent background
+ *
+ * Modified from https://stackoverflow.com/a/23752747
+ */
+class OverlayGraphicsEffect: public QGraphicsEffect
+{
+ Q_OBJECT
+public:
+ OverlayGraphicsEffect(QObject *parent);
+
+ virtual void draw(QPainter* painter);
+ virtual QRectF boundingRectFor(const QRectF& rect) const;
+
+ inline void setSize(const QSize &size)
+ { if(_size!=size){_size = size; updateBoundingRect(); } }
+
+ inline QSize size() const { return _size; }
+
+ inline void setOffset(const QPointF &offset)
+ { if(_offset!=offset) {_offset = offset; updateBoundingRect(); } }
+
+ inline QPointF offset() const { return _offset; }
+
+ inline void setBlurRadius(qreal blurRadius)
+ { if(_blurRadius!=blurRadius) {_blurRadius = blurRadius; updateBoundingRect();} }
+
+ inline qreal blurRadius() const { return _blurRadius; }
+
+ inline void setColor(const QColor& color) { _color = color; }
+ inline QColor color() const { return _color; }
+
+ inline bool enabled() const {return _enabled;}
+ inline void setEnabled(bool enabled)
+ { if(_enabled!=enabled) {_enabled = enabled; updateBoundingRect();} }
+
+private:
+ bool _enabled;
+ QSize _size;
+ qreal _blurRadius;
+ QColor _color;
+ QPointF _offset;
+};
+
+} // namespace Gui
+
+#endif // FC_OVERLAYWIDGETS_H
diff --git a/src/Gui/Stylesheets/CMakeLists.txt b/src/Gui/Stylesheets/CMakeLists.txt
index 07eed65c12..6e5de676a7 100644
--- a/src/Gui/Stylesheets/CMakeLists.txt
+++ b/src/Gui/Stylesheets/CMakeLists.txt
@@ -10,6 +10,22 @@ SET(Stylesheets_Files
"Light-modern.qss"
)
+SET(Overlay_Stylesheets_Files
+ "overlay/Dark.qss"
+ "overlay/Light.qss"
+ "overlay/Dark-Outline.qss"
+ "overlay/Light-Outline.qss"
+ "overlay/close.svg"
+ "overlay/overlay.svg"
+ "overlay/float.svg"
+ "overlay/autohide.svg"
+ "overlay/editshow.svg"
+ "overlay/taskshow.svg"
+ "overlay/edithide.svg"
+ "overlay/mode.svg"
+ "overlay/transparent.svg"
+)
+
# Find all the image files
FILE(GLOB Images_Files RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/images_dark-light/*.svg")
@@ -17,11 +33,13 @@ FILE(GLOB Images_Files RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
SOURCE_GROUP("images_dark-light" FILES ${Images_Files})
ADD_CUSTOM_TARGET(Stylesheets_data ALL
- SOURCES ${Stylesheets_Files} ${Images_Files}
+ SOURCES ${Stylesheets_Files} ${Images_Files} ${Overlay_Stylesheets_Files}
)
fc_copy_sources(Stylesheets_data "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_DATADIR}/Gui/Stylesheets"
- ${Stylesheets_Files} ${Images_Files})
+ ${Stylesheets_Files}
+ ${Images_Files}
+ ${Overlay_Stylesheets_Files})
INSTALL(
FILES
@@ -29,6 +47,12 @@ INSTALL(
DESTINATION
${CMAKE_INSTALL_DATADIR}/Gui/Stylesheets
)
+INSTALL(
+ FILES
+ ${Overlay_Stylesheets_Files}
+ DESTINATION
+ ${CMAKE_INSTALL_DATADIR}/Gui/Stylesheets/overlay
+)
INSTALL(
FILES
${Images_Files}
diff --git a/src/Gui/Stylesheets/overlay/Dark-Outline.qss b/src/Gui/Stylesheets/overlay/Dark-Outline.qss
new file mode 100644
index 0000000000..ad962b7bea
--- /dev/null
+++ b/src/Gui/Stylesheets/overlay/Dark-Outline.qss
@@ -0,0 +1,190 @@
+* {
+ color: #f0f0f0;
+ alternate-background-color: rgba(50,50,50,120);
+}
+
+QComboBox,
+QComboBox:editable,
+QComboBox:!editable,
+QLineEdit,
+QTextEdit,
+QPlainTextEdit,
+QAbstractSpinBox,
+QDateEdit,
+QDateTimeEdit,
+Gui--PropertyEditor--PropertyEditor QLabel {
+ background : #6e6e6e;
+}
+Gui--PropertyEditor--PropertyEditor {
+ gridline-color: #20a0a0a0;
+}
+
+QComboBox:disabled,
+QAbstractSpinBox:disabled,
+QLineEdit:disabled,
+QTextEdit:disabled,
+QPlainTextEdit:disabled,
+QTimeEdit:disabled,
+QDateEdit:disabled,
+QDateTimeEdit:disabled {
+ color: darkgray;
+}
+
+QTabWidget::pane {
+ background-color: transparent;
+ border: transparent;
+}
+
+QTabBar {
+ border : none;
+}
+
+QTabBar::tab {
+ color: rgb(180,180,180);
+ background-color: rgba(100,100,100,10);
+ padding: 5px;
+}
+
+QTabBar::tab:selected {
+ color: rgb(250,250,250);
+ background-color: rgba(100,100,100,50);
+}
+
+QTabBar::tab:hover {
+ color: rgb(250,250,250);
+ background-color: rgba(150,150,150,150);
+}
+
+/* The OverlayTabWidget is named as OverlayLeft, OverlayRight, OverlayTop, OverlayBottom.
+To customize for each overlay docking site, use the following selector
+
+Gui--OverlayTabWidget#OverlayLeft {}
+*/
+
+Gui--OverlayTabWidget {
+ qproperty-effectColor: rgba(50, 50, 50, 200);
+ qproperty-effectBlurRadius: 2.0;
+ qproperty-effectOffsetX: 0.0;
+ qproperty-effectOffsetY: 0.0;
+ qproperty-effectWidth: 1;
+ qproperty-effectHeight: 1;
+ qproperty-enableEffect: 1;
+}
+
+Gui--OverlayTabWidget::tab-bar:top,
+Gui--OverlayTabWidget::tab-bar:bottom {
+ left: 10px;
+ alignment: left;
+}
+
+Gui--OverlayTabWidget::tab-bar:left,
+Gui--OverlayTabWidget::tab-bar:right {
+ top: 10px;
+ alignment: top;
+}
+
+Gui--OverlayTabWidget::pane {
+ background-color: transparent;
+}
+
+QHeaderView { background:transparent }
+QHeaderView::section {
+ color: rgb(200,200,200);
+ background-color: rgba(50,50,50,10);
+ padding: 2px;
+ border: 1px solid rgb(150,150,150);
+}
+
+QToolTip {
+ background-color: rgba(100,100,100,180);
+ border: 1px solid darkgray;
+ border-radius:2px;
+}
+
+Gui--OverlayProxyWidget {
+ qproperty-hintColor: rgba(50, 50, 50, 0.6);
+}
+
+Gui--OverlayToolButton {
+ background: transparent;
+ padding: 0px;
+ border: none;
+}
+
+Gui--OverlayToolButton::hover {
+ background: rgba(150,150,150,200);
+}
+
+Gui--OverlayToolButton::focus {
+ background: rgba(150,150,150,155);
+}
+
+Gui--OverlayToolButton::pressed {
+ background: rgba(50,50,50,80);
+ border: 1px inset darkgray;
+}
+
+Gui--OverlayToolButton::checked {
+ background: rgba(50,50,50,80);
+ border: 1px inset darkgray;
+}
+
+Gui--OverlayToolButton::checked:hover {
+ background: rgba(150,150,150,200);
+ border: 1px inset darkgray;
+}
+
+QTreeView,
+QListView,
+QTableView {
+ background: rgb(100,100,100);
+ border: transparent;
+ selection-background-color: rgba(94, 144, 250, 0.7);
+}
+
+QListView::item:selected,
+QTreeView::item:selected {
+ background-color: rgba(94, 144, 250, 0.7);
+}
+
+Gui--PropertyEditor--PropertyEditor {
+ qproperty-groupTextColor: rgb(50, 50, 50);
+ qproperty-groupBackground: rgba(140, 140, 140, 0.6);
+ qproperty-itemBackground: rgba(0, 0, 0, 0.01);
+}
+
+Gui--CallTipsList::item {
+ background-color: rgba(100, 100, 100, 200);
+}
+
+Gui--CallTipsList::item::selected {
+ background-color: rgb(94, 144, 250);
+}
+
+/* Use the following selector to customize title bar for each side */
+/*
+Gui--OverlayTabWidget#OverlayBottom Gui--OverlayTitleBar,
+Gui--OverlayTabWidget#OverlayBottom QSplitter Gui--OverlaySplitterHandle {
+ background-color: qlineargradient(
+ spread:pad, x1:0, y1:1, x2:0, y2:0,
+ stop:0 #80202020, stop:1 #00202020);
+}
+*/
+
+Gui--OverlayTitleBar,
+Gui--OverlaySplitterHandle {
+ background-color: rgba(80, 80, 80, 150)
+}
+
+QScrollArea#ClippingScrollArea,
+QWidget#ClippingScrollAreaContents {
+ background-color: #808c8c8c;
+}
+
+QSint--ActionGroup QFrame[class="content"] {
+ background-color: #a08c8c8c; /* Task Panel background color */
+}
+
+QSint--ActionGroup QFrame[class="content"] > QWidget {
+ background-color: #808c8c8c; /* Task Panel background color */
+}
diff --git a/src/Gui/Stylesheets/overlay/Dark-off.qss b/src/Gui/Stylesheets/overlay/Dark-off.qss
new file mode 100644
index 0000000000..a11272af5b
--- /dev/null
+++ b/src/Gui/Stylesheets/overlay/Dark-off.qss
@@ -0,0 +1,34 @@
+Gui--OverlayToolButton {
+ background: transparent;
+ padding: 0px;
+ border: none;
+}
+
+Gui--OverlayToolButton::hover {
+ background: rgba(150,150,150,200);
+}
+
+Gui--OverlayToolButton::focus {
+ background: rgba(150,150,150,155);
+}
+
+Gui--OverlayToolButton::pressed {
+ background: rgba(50,50,50,80);
+ border: 1px inset palette(dark);
+}
+
+Gui--OverlayToolButton::checked {
+ background: rgba(50,50,50,80);
+ border: 1px inset palette(dark);
+}
+
+Gui--OverlayToolButton::checked:hover {
+ background: rgba(150,150,150,200);
+ border: 1px inset palette(dark);
+}
+
+Gui--OverlayTitleBar,
+Gui--OverlaySplitterHandle {
+ background-color: rgba(80, 80, 80, 150)
+}
+
diff --git a/src/Gui/Stylesheets/overlay/Dark.qss b/src/Gui/Stylesheets/overlay/Dark.qss
new file mode 100644
index 0000000000..3e74e12b36
--- /dev/null
+++ b/src/Gui/Stylesheets/overlay/Dark.qss
@@ -0,0 +1,158 @@
+* {
+ color: #f0f0f0;
+ alternate-background-color: rgba(50,50,50,120);
+}
+
+QComboBox,
+QComboBox:editable,
+QComboBox:!editable,
+QLineEdit,
+QTextEdit,
+QPlainTextEdit,
+QAbstractSpinBox,
+QDateEdit,
+QDateTimeEdit,
+Gui--PropertyEditor--PropertyEditor QLabel {
+ background : #6e6e6e;
+}
+
+QComboBox:disabled,
+QAbstractSpinBox:disabled,
+QLineEdit:disabled,
+QTextEdit:disabled,
+QPlainTextEdit:disabled,
+QTimeEdit:disabled,
+QDateEdit:disabled,
+QDateTimeEdit:disabled {
+ color: darkgray;
+}
+
+QTabWidget::pane {
+ background-color: transparent;
+ border: transparent;
+}
+
+Gui--OverlayTabWidget {
+ qproperty-enableEffect: 0;
+}
+
+Gui--OverlayTabWidget::pane {
+ background-color: rgba(100,100,100,150)
+}
+
+QTabBar {
+ border : none;
+}
+
+QTabBar::tab {
+ color: #f0f0f0;
+ background-color: rgba(100,100,100,50);
+ padding: 5px;
+}
+
+QTabBar::tab:selected {
+ background-color: rgba(100,100,100,150);
+}
+
+QTabBar::tab:hover {
+ background-color: rgba(150,150,150,150);
+}
+
+QHeaderView { background:transparent }
+QHeaderView::section {
+ color: rgb(200,200,200);
+ background-color: rgba(50,50,50,50);
+ padding: 2px;
+ border: 1px solid rgb(100,100,100);
+}
+
+QToolTip {
+ background-color: rgba(100,100,100,180);
+ border: 1px solid darkgray;
+ border-radius:2px;
+}
+
+Gui--OverlayToolButton {
+ background: transparent;
+ padding: 0px;
+ border: none;
+}
+
+Gui--OverlayToolButton::hover {
+ background: rgba(150,150,150,200);
+}
+
+Gui--OverlayToolButton::focus {
+ background: rgba(150,150,150,155);
+}
+
+Gui--OverlayToolButton::pressed {
+ background: rgba(50,50,50,80);
+ border: 1px inset darkgray;
+}
+
+Gui--OverlayToolButton::checked {
+ background: rgba(50,50,50,80);
+ border: 1px inset darkgray;
+}
+
+Gui--OverlayToolButton::checked:hover {
+ background: rgba(150,150,150,200);
+ border: 1px inset darkgray;
+}
+
+QTreeView,
+QListView,
+QTableView {
+ background: rgb(100,100,100);
+ selection-background-color: rgba(94, 144, 250, 0.7);
+ border: transparent;
+}
+
+QListView::item:selected,
+QTreeView::item:selected {
+ background-color: rgba(94, 144, 250, 0.7);
+}
+
+Gui--PropertyEditor--PropertyEditor {
+ qproperty-groupTextColor: rgb(50, 50, 50);
+ qproperty-groupBackground: rgba(140, 140, 140, 0.7);
+ qproperty-itemBackground: rgba(0, 0, 0, 0.01);
+}
+
+Gui--CallTipsList::item {
+ background-color: rgba(100, 100, 100, 200);
+}
+
+Gui--CallTipsList::item::selected {
+ background-color: rgb(94, 144, 250);
+}
+
+/* Use the following selector to customize title bar for each side */
+/*
+Gui--OverlayTabWidget#OverlayBottom Gui--OverlayTitleBar,
+Gui--OverlayTabWidget#OverlayBottom QSplitter Gui--OverlaySplitterHandle {
+ background-color: qlineargradient(
+ spread:pad, x1:0, y1:1, x2:0, y2:0,
+ stop:0 #80202020, stop:1 #00202020);
+}
+*/
+
+Gui--OverlayTitleBar,
+Gui--OverlaySplitterHandle {
+ background-color: rgba(80, 80, 80, 150)
+}
+
+QScrollArea#ClippingScrollArea,
+QWidget#ClippingScrollAreaContents {
+ background-color: #808c8c8c;
+}
+
+QSint--ActionGroup QFrame[class="content"] {
+ background-color: #808c8c8c; /* Task Panel background color */
+}
+
+QSint--ActionGroup QFrame[class="content"] > QWidget {
+ background-color: #808c8c8c; /* Task Panel background color */
+}
+
diff --git a/src/Gui/Stylesheets/overlay/Light-Outline.qss b/src/Gui/Stylesheets/overlay/Light-Outline.qss
new file mode 100644
index 0000000000..b3c76bbfd3
--- /dev/null
+++ b/src/Gui/Stylesheets/overlay/Light-Outline.qss
@@ -0,0 +1,183 @@
+* {
+ color: #202020;
+ alternate-background-color: rgba(250,250,250,120);
+}
+
+QComboBox,
+QComboBox:editable,
+QComboBox:!editable,
+QLineEdit,
+QTextEdit,
+QPlainTextEdit,
+QAbstractSpinBox,
+QDateEdit,
+QDateTimeEdit,
+Gui--PropertyEditor--PropertyEditor QLabel {
+ background-color: #e0e0e0;
+}
+
+QComboBox:disabled,
+QAbstractSpinBox:disabled,
+QLineEdit:disabled,
+QTextEdit:disabled,
+QPlainTextEdit:disabled,
+QTimeEdit:disabled,
+QDateEdit:disabled,
+QDateTimeEdit:disabled {
+ color: gray;
+}
+
+QTabWidget::pane {
+ background-color: transparent;
+ border: transparent;
+}
+
+QTabBar {
+ border : none;
+}
+
+QTabBar::tab {
+ color: #202020;
+ background-color: rgba(100,100,100,50);
+ padding: 5px;
+}
+
+QTabBar::tab:selected {
+ background-color: rgba(250,250,250,80);
+}
+
+QTabBar::tab:hover {
+ background-color: rgba(250,250,250,200);
+}
+
+/* The OverlayTabWidget is named as OverlayLeft, OverlayRight, OverlayTop, OverlayBottom.
+To customize for each overlay docking site, use the following selector
+
+Gui--OverlayTabWidget#OverlayLeft {}
+*/
+
+Gui--OverlayTabWidget {
+ qproperty-effectColor: rgba(200, 200, 200, 100);
+ qproperty-effectBlurRadius: 2.0;
+ qproperty-effectOffsetX: 0.0;
+ qproperty-effectOffsetY: 0.0;
+ qproperty-effectWidth: 1;
+ qproperty-effectHeight: 1;
+ qproperty-enableEffect: 1;
+}
+
+Gui--OverlayTabWidget::pane {
+ background-color: transparent
+}
+
+Gui--OverlayTabWidget::tab-bar:top,
+Gui--OverlayTabWidget::tab-bar:bottom {
+ left: 10px;
+ alignment: left;
+}
+
+Gui--OverlayTabWidget::tab-bar:left,
+Gui--OverlayTabWidget::tab-bar:right {
+ top: 10px;
+ alignment: top;
+}
+
+QHeaderView { background:transparent }
+QHeaderView::section {
+ color: rgb(80, 80, 80);
+ background-color: rgba(128,128,128,50);
+ border: 1px solid rgb(100,100,100);
+ padding: 2px;
+}
+
+QToolTip {
+ background-color: rgba(250,250,250,180);
+ border: 1px solid rgb(80,80,80);
+ border-radius:2px;
+}
+
+Gui--OverlayProxyWidget {
+ qproperty-hintColor: rgba(250, 250, 250, 0.6);
+}
+
+Gui--OverlayToolButton {
+ background: transparent;
+ padding: 0px;
+ border: none;
+}
+
+Gui--OverlayToolButton::hover {
+ background: rgba(250,250,250,200);
+}
+
+Gui--OverlayToolButton::focus {
+ background: rgba(250,250,250,255);
+}
+
+Gui--OverlayToolButton::pressed,
+Gui--OverlayToolButton::checked {
+ background: rgba(150,150,150,80);
+ border: 1px inset #f5f5f5;
+}
+
+Gui--OverlayToolButton::checked:hover {
+ background: rgba(150,150,150,200);
+ border: 1px inset #f5f5f5;
+}
+
+QTreeView,
+QListView,
+QTableView {
+ background: rgb(250,250,250);
+ selection-background-color: rgba(94, 144, 250, 0.7);
+ border: transparent;
+}
+
+QListView::item:selected,
+QTreeView::item:selected {
+ background-color: rgba(94, 144, 250, 0.7);
+}
+
+/* Property Editor QTreeView (FreeCAD custom widget) */
+Gui--PropertyEditor--PropertyEditor {
+ gridline-color: #20d2d2de;
+ qproperty-groupTextColor: rgb(100, 100, 100);
+ qproperty-groupBackground: rgba(180, 180, 180, 0.7);
+ qproperty-itemBackground: rgba(0, 0, 0, 0.01);
+}
+
+Gui--CallTipsList::item {
+ background-color: rgba(200, 200, 200, 200);
+}
+
+Gui--CallTipsList::item::selected {
+ background-color: rgba(94, 144, 250);
+}
+
+/* Use the following selector to customize title bar for each side */
+/*
+Gui--OverlayTabWidget#OverlayBottom Gui--OverlayTitleBar,
+Gui--OverlayTabWidget#OverlayBottom QSplitter Gui--OverlaySplitterHandle {
+ background-color: qlineargradient(
+ spread:pad, x1:0, y1:1, x2:0, y2:0,
+ stop:0 #80202020, stop:1 #00202020);
+}
+*/
+
+Gui--OverlayTitleBar,
+Gui--OverlaySplitterHandle {
+ background-color: rgba(200, 200, 200, 150)
+}
+
+QScrollArea#ClippingScrollArea,
+QWidget#ClippingScrollAreaContents {
+ background-color: #80e6e6e6;
+}
+
+QSint--ActionGroup QFrame[class="content"] {
+ background-color: #a0e6e6e6; /* Task Panel background color */
+}
+
+QSint--ActionGroup QFrame[class="content"] > QWidget {
+ background-color: #80e6e6e6; /* Task Panel background color */
+}
diff --git a/src/Gui/Stylesheets/overlay/Light-off.qss b/src/Gui/Stylesheets/overlay/Light-off.qss
new file mode 100644
index 0000000000..0c5ec79e65
--- /dev/null
+++ b/src/Gui/Stylesheets/overlay/Light-off.qss
@@ -0,0 +1,33 @@
+Gui--OverlayToolButton {
+ background: transparent;
+ padding: 0px;
+ border: none;
+}
+
+Gui--OverlayToolButton::hover {
+ background: rgba(150,150,150,200);
+}
+
+Gui--OverlayToolButton::focus {
+ background: rgba(150,150,150,155);
+}
+
+Gui--OverlayToolButton::pressed {
+ background: rgba(50,50,50,80);
+ border: 1px inset palette(dark);
+}
+
+Gui--OverlayToolButton::checked {
+ background: rgba(50,50,50,80);
+ border: 1px inset palette(dark);
+}
+
+Gui--OverlayToolButton::checked:hover {
+ background: rgba(150,150,150,200);
+ border: 1px inset palette(dark);
+}
+
+Gui--OverlayTitleBar,
+Gui--OverlaySplitterHandle {
+ background-color: rgba(200, 200, 200, 150)
+}
diff --git a/src/Gui/Stylesheets/overlay/Light.qss b/src/Gui/Stylesheets/overlay/Light.qss
new file mode 100644
index 0000000000..6ee020ac01
--- /dev/null
+++ b/src/Gui/Stylesheets/overlay/Light.qss
@@ -0,0 +1,155 @@
+* {
+ color: #202020;
+ alternate-background-color: rgba(250,250,250,120);
+}
+
+QComboBox,
+QComboBox:editable,
+QComboBox:!editable,
+QLineEdit,
+QTextEdit,
+QPlainTextEdit,
+QAbstractSpinBox,
+QDateEdit,
+QDateTimeEdit,
+Gui--PropertyEditor--PropertyEditor QLabel {
+ background-color: #e0e0e0;
+}
+
+QComboBox:disabled,
+QAbstractSpinBox:disabled,
+QLineEdit:disabled,
+QTextEdit:disabled,
+QPlainTextEdit:disabled,
+QTimeEdit:disabled,
+QDateEdit:disabled,
+QDateTimeEdit:disabled {
+ color: gray;
+}
+
+QTabWidget::pane {
+ background-color: transparent;
+ border: transparent;
+}
+
+Gui--OverlayTabWidget {
+ qproperty-enableEffect: 0;
+}
+
+Gui--OverlayTabWidget::pane {
+ background-color: rgba(255,255,255,80)
+}
+
+QTabBar {
+ border : none;
+}
+
+QTabBar::tab {
+ color: #202020;
+ background-color: rgba(100,100,100,50);
+ padding: 5px;
+}
+
+QTabBar::tab:selected {
+ background-color: rgba(250,250,250,80);
+}
+
+QTabBar::tab:hover {
+ background-color: rgba(250,250,250,200);
+}
+
+QHeaderView { background:transparent }
+QHeaderView::section {
+ color: rgb(80, 80, 80);
+ background-color: rgba(128,128,128,50);
+ border: 1px solid darkgray;
+ padding: 2px;
+}
+
+QToolTip {
+ background-color: rgba(250,250,250,180);
+ border: 1px solid rgb(80,80,80);
+ border-radius:2px;
+}
+
+Gui--OverlayToolButton {
+ background: transparent;
+ padding: 0px;
+ border: none;
+}
+
+Gui--OverlayToolButton::hover {
+ background: rgba(250,250,250,200);
+}
+
+Gui--OverlayToolButton::focus {
+ background: rgba(250,250,250,255);
+}
+
+Gui--OverlayToolButton::pressed,
+Gui--OverlayToolButton::checked {
+ background: rgba(150,150,150,80);
+ border: 1px inset #f5f5f5;
+}
+
+Gui--OverlayToolButton::checked:hover {
+ background: rgba(150,150,150,200);
+ border: 1px inset #f5f5f5;
+}
+
+QTreeView,
+QListView,
+QTableView {
+ background: rgb(250,250,250);
+ selection-background-color: rgba(94, 144, 250, 0.7);
+ border: transparent;
+}
+
+QListView::item:selected,
+QTreeView::item:selected {
+ background-color: rgba(94, 144, 250, 0.7);
+}
+
+/* Property Editor QTreeView (FreeCAD custom widget) */
+Gui--PropertyEditor--PropertyEditor {
+ /* gridline-color: #6e6e6e; */
+ qproperty-groupTextColor: rgb(100, 100, 100);
+ qproperty-groupBackground: rgba(180, 180, 180, 0.7);
+ qproperty-itemBackground: rgba(0, 0, 0, 0.01);
+}
+
+Gui--CallTipsList::item {
+ background-color: rgba(200, 200, 200, 200);
+}
+
+Gui--CallTipsList::item::selected {
+ background-color: rgba(94, 144, 250);
+}
+
+/* Use the following selector to customize title bar for each side */
+/*
+Gui--OverlayTabWidget#OverlayBottom Gui--OverlayTitleBar,
+Gui--OverlayTabWidget#OverlayBottom QSplitter Gui--OverlaySplitterHandle {
+ background-color: qlineargradient(
+ spread:pad, x1:0, y1:1, x2:0, y2:0,
+ stop:0 #80202020, stop:1 #00202020);
+}
+*/
+
+Gui--OverlayTitleBar,
+Gui--OverlaySplitterHandle {
+ background-color: rgba(200, 200, 200, 150)
+}
+
+QScrollArea#ClippingScrollArea,
+QWidget#ClippingScrollAreaContents {
+ background-color: #80e6e6e6
+}
+
+QSint--ActionGroup QFrame[class="content"] {
+ background-color: #80e6e6e6; /* Task Panel background color */
+}
+
+QSint--ActionGroup QFrame[class="content"] > QWidget {
+ background-color: #80e6e6e6; /* Task Panel background color */
+}
diff --git a/src/Gui/Stylesheets/overlay/autohide.svg b/src/Gui/Stylesheets/overlay/autohide.svg
new file mode 100644
index 0000000000..978084bd13
--- /dev/null
+++ b/src/Gui/Stylesheets/overlay/autohide.svg
@@ -0,0 +1,86 @@
+
+