Gui: add support for transparent overlay docking widget

This commit is contained in:
Zheng, Lei
2022-11-24 07:57:35 +08:00
committed by Yorik van Havre
parent 1dd0a9afaa
commit ba6b2a4375
46 changed files with 9997 additions and 240 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -23,6 +23,7 @@
#ifndef GUI_DOCKWND_COMBOVIEW_H
#define GUI_DOCKWND_COMBOVIEW_H
#include <Base/Parameter.h>
#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.

View File

@@ -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())

View File

@@ -25,15 +25,23 @@
#ifndef _PreComp_
# include <array>
# include <QAction>
# include <QApplication>
# include <QDockWidget>
# include <QMap>
# include <QMouseEvent>
# include <QPointer>
# include <QTimer>
#endif
#include <boost/algorithm/string/predicate.hpp>
#include <App/Application.h>
#include <Base/Console.h>
#include <Base/Tools.h>
#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<DockWindowItem>::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<DockWindowItem>::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<DockWindowItem>& 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<QDockWidget*>(o);
if (!widget || !widget->isFloating()) {
if (overridden) {
overridden = false;
QApplication::restoreOverrideCursor();
}
return false;
}
if (static_cast<QMouseEvent*>(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<QDockWidget*> _dockedWindows;
QMap<QString, QPointer<QWidget> > _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<QDockWidget*>(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<QDockWidget*>(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<QDockWidget*>::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<QDockWidget*>::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<QDockWidget*>::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<QDockWidget*>::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<QString, QPointer<QWidget> >::Iterator it = d->_dockWindows.find(QLatin1String(name));
QMap<QString, QPointer<QWidget> >::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<QString, QPointer<QWidget> >::Iterator it = d->_dockWindows.find(QLatin1String(name));
QMap<QString, QPointer<QWidget> >::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<QString, QPointer<QWidget> >::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<QDockWidget*> docked = d->_dockedWindows;
const QList<DockWindowItem>& 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<QString, QPointer<QWidget> >::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<DockWindowItem>& dockItems = d->_dockWindowItems.dockWidgets();
for (QList<DockWindowItem>::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<DockWindowItem>::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);
}

View File

@@ -26,7 +26,6 @@
#include <QObject>
#include <FCGlobal.h>
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

View File

@@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="32"
height="32"
viewBox="0 0 32 32"
id="svg2"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="cursor-through.svg">
<defs
id="defs4">
<linearGradient
gradientTransform="matrix(1.9992772,0,0,1.9992772,-0.23550294,-1052.047)"
inkscape:collect="always"
xlink:href="#linearGradient4136"
id="linearGradient4146"
x1="3.2922609"
y1="1048.2958"
x2="7.3351092"
y2="1045.6942"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
id="linearGradient4136">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop4138" />
<stop
style="stop-color:#000000;stop-opacity:0"
offset="1"
id="stop4140" />
</linearGradient>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.919596"
inkscape:cx="2.4698679"
inkscape:cy="4.0737083"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
units="px"
inkscape:window-width="1301"
inkscape:window-height="744"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-1020.3622)">
<path
style="fill:url(#linearGradient4146);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 9.9393899,1030.4959 6e-7,18.5201 4.2134615,-4.1523 2.912554,6.4989 3.001123,-1.6055 -3.18829,-6.9637 5.402014,-0.2053 z"
id="path4134"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccc" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -255,6 +255,7 @@
<file>folder.svg</file>
<file>document-python.svg</file>
<file>document-package.svg</file>
<file>cursor-through.svg</file>
<file>Std_Alignment.svg</file>
<file>Std_DuplicateSelection.svg</file>
<file>Std_UserEditModeDefault.svg</file>

View File

@@ -31,6 +31,7 @@
# include <QCloseEvent>
# include <QContextMenuEvent>
# include <QDesktopServices>
# include <QDesktopWidget>
# include <QDockWidget>
# include <QFontMetrics>
# include <QKeySequence>
@@ -58,6 +59,8 @@
# include <QtPlatformHeaders/QWindowsWindowFunctions>
#endif
#include <boost/algorithm/string/predicate.hpp>
#include <App/Application.h>
#include <App/Document.h>
#include <App/DocumentObject.h>
@@ -68,6 +71,7 @@
#include <Base/FileInfo.h>
#include <Base/Interpreter.h>
#include <Base/Stream.h>
#include <Base/Tools.h>
#include <Base/UnitsApi.h>
#include <DAGView/DAGView.h>
#include <TaskView/TaskView.h>
@@ -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<MDIView> activeView;
QSignalMapper* windowMapper;
@@ -254,6 +261,13 @@ struct MainWindowP
int currentStatusType = 100;
int actionUpdateDelay = 0;
QMap<QString, QPointer<UrlHandler> > 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<class T>
static inline void _updateDockWidget(const char *name,
bool enabled,
bool show,
Qt::DockWidgetArea pos,
T callback)
{
std::string hiddenDockWindows;
const std::map<std::string,std::string>& 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<ComboView*>(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<int>(rect.left(), std::min<int>(rect.left()+rect.width()/2, pos.x()));
y = std::max<int>(rect.top(), std::min<int>(rect.top()+rect.height()/2, pos.y()));
w = std::min<int>(rect.width(), size.width());
h = std::min<int>(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()

View File

@@ -105,6 +105,10 @@ public:
* Returns a list of all MDI windows in the worpspace.
*/
QList<QWidget*> 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);

View File

@@ -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);
}

View File

@@ -68,6 +68,7 @@ public:
// Label order: front, top, right, rear, bottom, left
void setNaviCubeLabels(const std::vector<std::string>& labels);
static void setNaviCubeCommands(const std::vector<std::string>& cmd);
static int getNaviCubeSize();
private:
NaviCubeImplementation* m_NaviCubeImplementation;

2052
src/Gui/OverlayManager.cpp Normal file

File diff suppressed because it is too large Load Diff

190
src/Gui/OverlayManager.h Normal file
View File

@@ -0,0 +1,190 @@
/****************************************************************************
* Copyright (c) 2022 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
* *
* 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 <QObject>
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

1151
src/Gui/OverlayParams.cpp Normal file

File diff suppressed because it is too large Load Diff

422
src/Gui/OverlayParams.h Normal file
View File

@@ -0,0 +1,422 @@
/****************************************************************************
* Copyright (c) 2022 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
* *
* 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 <QString>
// Auto generated code (Tools/params_utils.py:72)
#include <Base/Parameter.h>
// 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:on<parameter_name>Changed()
* @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<QString> AnimationCurveTypes;
// Auto generated code (Tools/params_utils.py:150)
}; // class OverlayParams
} // namespace Gui
//[[[end]]]
#endif // GUI_OVERLAY_PARAMS_H

182
src/Gui/OverlayParams.py Normal file
View File

@@ -0,0 +1,182 @@
# -*- coding: utf-8 -*-
# ***************************************************************************
# * Copyright (c) 2022 Zheng Lei (realthunder) <realthunder.dev@gmail.com>*
# * *
# * 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 <QString>
''')
params_utils.declare_begin(sys.modules[__name__])
cog.out(f'''
{auto_comment()}
static const std::vector<QString> AnimationCurveTypes;
''')
params_utils.declare_end(sys.modules[__name__])
def define():
params_utils.define(sys.modules[__name__])
cog.out(f'''
{auto_comment()}
const std::vector<QString> OverlayParams::AnimationCurveTypes = {{''')
for item in AnimationCurveTypes:
cog.out(f'''
QStringLiteral("{item}"),''')
cog.out(f'''
}};
''')
params_utils.init_params(Params, NameSpace, ClassName, ParamPath)

2487
src/Gui/OverlayWidgets.cpp Normal file

File diff suppressed because it is too large Load Diff

630
src/Gui/OverlayWidgets.h Normal file
View File

@@ -0,0 +1,630 @@
/****************************************************************************
* Copyright (c) 2020 Zheng Lei (realthunder) <realthunder.dev@gmail.com> *
* *
* 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 <QTabWidget>
#include <QTimer>
#include <QTime>
#include <QAction>
#include <QToolButton>
#include <QGraphicsEffect>
#include <QImage>
#include <QDockWidget>
#include <QSplitter>
#include <QMenu>
#include <Base/Parameter.h>
#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<QAction*> &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<QDockWidget *, int> _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

View File

@@ -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}

View File

@@ -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 */
}

View File

@@ -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)
}

View File

@@ -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 */
}

View File

@@ -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 */
}

View File

@@ -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)
}

View File

@@ -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 */
}

View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="12"
height="12"
id="svg2"
version="1.1"
viewBox="0 0 12 12"
inkscape:version="0.91 r13725"
sodipodi:docname="autohide.svg">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1301"
inkscape:window-height="744"
id="namedview8"
showgrid="true"
inkscape:zoom="22.627417"
inkscape:cx="4.6041743"
inkscape:cy="2.6400142"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg2">
<inkscape:grid
type="xygrid"
id="grid4136"
spacingx="0.5"
spacingy="0.5"
empspacing="2"
units="px" />
</sodipodi:namedview>
<defs
id="defs4" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:creator>
<cc:Agent>
<dc:title>Pablo Gil</dc:title>
</cc:Agent>
</dc:creator>
<dc:subject>
<rdf:Bag>
<rdf:li>SVG</rdf:li>
<rdf:li>template</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
</rdf:RDF>
</metadata>
<path
id="path5607"
d="m 5,1.5 5.501761,0.00796 L 10.5,10.5 5,10.5"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:0.50196078"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
<path
id="path5609"
d="m 8.5,6 -5,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:0.50196078"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
id="path5611"
d="m 4.4999599,4 -3,2 3,2"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.50196078" />
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 2.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 2.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 12 12"
version="1.1"
id="svg2"
height="12"
width="12">
<defs
id="defs4" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Pablo Gil</dc:title>
</cc:Agent>
</dc:creator>
<dc:subject>
<rdf:Bag>
<rdf:li>SVG</rdf:li>
<rdf:li>template</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
</rdf:RDF>
</metadata>
<g
transform="translate(-1074.0663,-344.59799)"
id="layer1">
<rect
y="349.09799"
x="1075.5664"
height="6.0000062"
width="6.0000587"
id="rect4200"
style="opacity:1;fill:none;fill-opacity:0.50196078;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:63;stroke-opacity:0.50196078" />
<path
id="rect4200-1"
d="m 1078.5663,348.09799 0,-2 6,0 0,6 -2,0"
style="opacity:1;fill:none;fill-opacity:0.50196078;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:63;stroke-opacity:0.50196078" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="12"
height="12"
id="svg2"
version="1.1"
viewBox="0 0 12 12"
inkscape:version="0.91 r13725"
sodipodi:docname="overlay.svg">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1301"
inkscape:window-height="744"
id="namedview7252"
showgrid="true"
inkscape:zoom="39.333334"
inkscape:cx="5.677245"
inkscape:cy="7.37444"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg2">
<inkscape:grid
type="xygrid"
id="grid7794"
units="px"
spacingx="0.5"
spacingy="0.5"
originx="0"
originy="0"
empspacing="2" />
</sodipodi:namedview>
<defs
id="defs4" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:creator>
<cc:Agent>
<dc:title>Pablo Gil</dc:title>
</cc:Agent>
</dc:creator>
<dc:subject>
<rdf:Bag>
<rdf:li>SVG</rdf:li>
<rdf:li>template</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
</rdf:RDF>
</metadata>
<path
style="opacity:1;fill:none;fill-opacity:0.50196078;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:63;stroke-opacity:0.50196078"
d="m 1.5000553,1.4999919 8.9999447,0 0,9.0000081 -8.9999447,0 z"
id="rect4200" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path4207"
d="m 2,4.5 8,0"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.50196078" />
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
id="svg6528"
height="12"
width="12"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="taskshow.svg">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1301"
inkscape:window-height="744"
id="namedview4692"
showgrid="true"
inkscape:zoom="11.313709"
inkscape:cx="-3.3929586"
inkscape:cy="-3.0838742"
inkscape:window-x="65"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="svg6528">
<inkscape:grid
type="xygrid"
id="grid5234"
units="px"
spacingx="0.5"
spacingy="0.5"
empspacing="2" />
</sodipodi:namedview>
<metadata
id="metadata6538">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs6536" />
<path
id="path7086"
d="M 3,2 1.5,2 1.4996684,10.5 10.5,10.5 10.5,2 9,2"
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196078"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<rect
style="opacity:1;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:63;stroke-opacity:0.50196078"
id="rect4137"
width="5"
height="2"
x="3.5"
y="0.5" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196078"
d="m 3,4.5 6,0"
id="path4139"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196078"
d="m 3,6.5 6,0"
id="path4139-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.50196078"
d="m 3,8.5 6,0"
id="path4139-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
width="12"
height="12"
id="svg2"
version="1.1"
viewBox="0 0 12 12">
<defs
id="defs4" />
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Pablo Gil</dc:title>
</cc:Agent>
</dc:creator>
<dc:subject>
<rdf:Bag>
<rdf:li>SVG</rdf:li>
<rdf:li>template</rdf:li>
</rdf:Bag>
</dc:subject>
</cc:Work>
</rdf:RDF>
</metadata>
<ellipse
ry="2.2648306"
rx="2.2341104"
cy="6"
cx="6"
id="path5584"
style="opacity:1;fill:#000000;fill-opacity:0.50196078;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:63;stroke-opacity:0.50196078" />
<ellipse
ry="3.7245762"
rx="4.7838984"
cy="6"
cx="6"
id="path5586"
style="opacity:1;fill:none;fill-opacity:0.50196078;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:63;stroke-opacity:0.50196078" />
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -41,6 +41,7 @@
#include "TaskView.h"
#include "TaskDialog.h"
#include "TaskEditControl.h"
#include <Gui/Control.h>
#include <Gui/QSint/actionpanel/taskgroup_p.h>
#include <Gui/QSint/actionpanel/taskheader_p.h>
@@ -299,6 +300,11 @@ TaskView::TaskView(QWidget *parent)
App::GetApplication().signalRedoDocument.connect
(std::bind(&Gui::TaskView::TaskView::slotRedoDocument, this, sp::_1));
//NOLINTEND
this->timer = new QTimer(this);
this->timer->setSingleShot(true);
QObject::connect(this->timer, &QTimer::timeout, [this](){onUpdateWatcher();});
updateWatcher();
}
TaskView::~TaskView()
@@ -310,6 +316,20 @@ TaskView::~TaskView()
Gui::Selection().Detach(this);
}
bool TaskView::isEmpty(bool includeWatcher) const
{
if (ActiveCtrl || ActiveDialog)
return false;
if (includeWatcher) {
for (auto * watcher : ActiveWatcher) {
if (watcher->shouldShow())
return false;
}
}
return true;
}
bool TaskView::event(QEvent* event)
{
// Workaround for a limitation in Qt (#0003794)
@@ -542,7 +562,10 @@ void TaskView::showDialog(TaskDialog *dlg)
ActiveDialog->open();
getMainWindow()->updateActions();
triggerMinimumSizeHint();
Q_EMIT taskUpdate();
}
void TaskView::removeDialog()
@@ -585,8 +608,23 @@ void TaskView::removeDialog()
triggerMinimumSizeHint();
}
void TaskView::updateWatcher()
void TaskView::updateWatcher(void)
{
this->timer->start(200);
}
void TaskView::onUpdateWatcher(void)
{
if (ActiveCtrl || ActiveDialog)
return;
if (ActiveWatcher.empty()) {
auto panel = Gui::Control().taskPanel();
if (panel && panel->ActiveWatcher.size())
takeTaskWatcher(panel);
}
this->timer->stop();
// In case a child of the TaskView has the focus and get hidden we have
// to make sure to set the focus on a widget that won't be hidden or
// deleted because otherwise Qt may forward the focus via focusNextPrevChild()
@@ -622,6 +660,8 @@ void TaskView::updateWatcher()
fwp->setFocus();
triggerMinimumSizeHint();
Q_EMIT taskUpdate();
}
void TaskView::addTaskWatcher(const std::vector<TaskWatcher*> &Watcher)
@@ -631,7 +671,17 @@ void TaskView::addTaskWatcher(const std::vector<TaskWatcher*> &Watcher)
delete tw;
ActiveWatcher = Watcher;
addTaskWatcher();
if (!ActiveCtrl && !ActiveDialog)
addTaskWatcher();
}
void TaskView::takeTaskWatcher(TaskView *other)
{
clearTaskWatcher();
ActiveWatcher.swap(other->ActiveWatcher);
other->clearTaskWatcher();
if (isEmpty(false))
addTaskWatcher();
}
void TaskView::clearTaskWatcher()

View File

@@ -154,17 +154,24 @@ public:
void addTaskWatcher(const std::vector<TaskWatcher*> &Watcher);
void clearTaskWatcher();
void takeTaskWatcher(TaskView *other);
bool isEmpty(bool includeWatcher = true) const;
void clearActionStyle();
void restoreActionStyle();
QSize minimumSizeHint() const override;
Q_SIGNALS:
void taskUpdate();
protected Q_SLOTS:
void accept();
void reject();
void helpRequested();
void clicked (QAbstractButton * button);
void onUpdateWatcher();
private:
void triggerMinimumSizeHint();
@@ -193,6 +200,7 @@ protected:
QSint::ActionPanel* taskPanel;
TaskDialog *ActiveDialog;
TaskEditControl *ActiveCtrl;
QTimer *timer;
Connection connectApplicationActiveDocument;
Connection connectApplicationDeleteDocument;

View File

@@ -32,6 +32,7 @@
# include <QHeaderView>
# include <QMenu>
# include <QMessageBox>
# include <QPainter>
# include <QPixmap>
# include <QThread>
# include <QTimer>
@@ -89,6 +90,7 @@ std::set<TreeWidget*> TreeWidget::Instances;
static TreeWidget* _LastSelectedTreeWidget;
const int TreeWidget::DocumentType = 1000;
const int TreeWidget::ObjectType = 1001;
static bool _DraggingActive;
static bool _DragEventFilter;
void TreeParams::onItemBackgroundChanged()
@@ -355,13 +357,95 @@ public:
// ---------------------------------------------------------------------------
TreeWidgetEditDelegate::TreeWidgetEditDelegate(QObject* parent)
namespace Gui {
/**
* TreeWidget item delegate for editing
*/
class TreeWidgetItemDelegate: public QStyledItemDelegate {
typedef QStyledItemDelegate inherited;
public:
TreeWidgetItemDelegate(QObject* parent=0);
virtual QWidget* createEditor(QWidget *parent,
const QStyleOptionViewItem &, const QModelIndex &index) const;
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
virtual void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const;
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
} // namespace Gui
TreeWidgetItemDelegate::TreeWidgetItemDelegate(QObject* parent)
: QStyledItemDelegate(parent)
{
}
QWidget* TreeWidgetEditDelegate::createEditor(
QWidget* parent, const QStyleOptionViewItem&, const QModelIndex& index) const
void TreeWidgetItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
TreeWidget * tree = static_cast<TreeWidget*>(parent());
auto style = tree->style();
// If the second column is not shown, we'll trim the color background when
// rendering as transparent overlay.
bool trimBG = TreeParams::getHideColumn();
QRect rect = opt.rect;
if (index.column() == 0) {
if (tree->testAttribute(Qt::WA_NoSystemBackground)
&& (trimBG || (opt.backgroundBrush.style() == Qt::NoBrush
&& _TreeItemBackground.style() != Qt::NoBrush)))
{
const int margin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, tree) + 1;
// 2 margin for text, 2 margin for decoration (icon)
int width = 4*margin + opt.fontMetrics.boundingRect(opt.text).width()
+ opt.decorationSize.width() + TreeParams::getItemBackgroundPadding();
if (TreeParams::getCheckBoxesSelection()) {
// another 2 margin for checkbox
width += 2*margin + style->pixelMetric(QStyle::PM_IndicatorWidth)
+ style->pixelMetric(QStyle::PM_LayoutHorizontalSpacing);
}
if (width < rect.width())
rect.setWidth(width);
if (trimBG) {
rect.setWidth(rect.width() + 5);
opt.rect = rect;
if (opt.backgroundBrush.style() == Qt::NoBrush)
painter->fillRect(rect, _TreeItemBackground);
} else if (!opt.state.testFlag(QStyle::State_Selected))
painter->fillRect(rect, _TreeItemBackground);
}
}
style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, tree);
}
void TreeWidgetItemDelegate::initStyleOption(QStyleOptionViewItem *option,
const QModelIndex &index) const
{
inherited::initStyleOption(option, index);
TreeWidget * tree = static_cast<TreeWidget*>(parent());
QTreeWidgetItem * item = tree->itemFromIndex(index);
if (!item || item->type() != TreeWidget::ObjectType)
return;
QSize size;
size = option->icon.actualSize(QSize(0xffff, 0xffff));
if (size.height())
option->decorationSize = QSize(size.width()*TreeWidget::iconSize()/size.height(),
TreeWidget::iconSize());
}
QWidget* TreeWidgetItemDelegate::createEditor(
QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const
{
auto ti = static_cast<QTreeWidgetItem*>(index.internalPointer());
if (ti->type() != TreeWidget::ObjectType || index.column() > 1)
@@ -375,14 +459,27 @@ QWidget* TreeWidgetEditDelegate::createEditor(
App::GetApplication().setActiveTransaction(str.str().c_str());
FC_LOG("create editor transaction " << App::GetApplication().getActiveTransaction());
auto le = new ExpLineEdit(parent);
le->setFrame(false);
le->setReadOnly(prop.isReadOnly());
le->bind(App::ObjectIdentifier(prop));
le->setAutoApply(true);
return le;
QLineEdit *editor;
if(TreeParams::getLabelExpression()) {
ExpLineEdit *le = new ExpLineEdit(parent);
le->setAutoApply(true);
le->setFrame(false);
le->bind(App::ObjectIdentifier(prop));
editor = le;
} else {
editor = new QLineEdit(parent);
}
editor->setReadOnly(prop.isReadOnly());
return editor;
}
QSize TreeWidgetItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QSize size = QStyledItemDelegate::sizeHint(option, index);
int spacing = std::max(0, static_cast<int>(TreeParams::getItemSpacing()));
size.setHeight(size.height() + spacing);
return size;
}
// ---------------------------------------------------------------------------
TreeWidget::TreeWidget(const char* name, QWidget* parent)
@@ -404,7 +501,7 @@ TreeWidget::TreeWidget(const char* name, QWidget* parent)
this->setDropIndicatorShown(false);
this->setDragDropMode(QTreeWidget::InternalMove);
this->setColumnCount(2);
this->setItemDelegate(new TreeWidgetEditDelegate(this));
this->setItemDelegate(new TreeWidgetItemDelegate(this));
this->showHiddenAction = new QAction(this);
this->showHiddenAction->setCheckable(true);
@@ -1170,6 +1267,47 @@ void TreeWidget::selectAllInstances(const ViewProviderDocumentObject& vpd) {
v.second->selectAllInstances(vpd);
}
static int &treeIconSize()
{
static int _treeIconSize = -1;
if (_treeIconSize < 0)
_treeIconSize = TreeParams::getIconSize();
return _treeIconSize;
}
int TreeWidget::iconHeight() const
{
return treeIconSize();
}
void TreeWidget::setIconHeight(int height)
{
if (treeIconSize() == height)
return;
treeIconSize() = height;
if (treeIconSize() <= 0)
treeIconSize() = std::max(10, iconSize());
for(auto tree : Instances)
tree->setIconSize(QSize(treeIconSize(), treeIconSize()));
}
int TreeWidget::iconSize() {
static int defaultSize;
if (defaultSize == 0) {
auto tree = instance();
if(tree)
defaultSize = tree->viewOptions().decorationSize.width();
else
defaultSize = QApplication::style()->pixelMetric(QStyle::PM_SmallIconSize);
}
if (treeIconSize() > 0)
return std::max(10, treeIconSize());
return defaultSize;
}
TreeWidget* TreeWidget::instance() {
auto res = _LastSelectedTreeWidget;
if (res && res->isVisible())
@@ -1336,6 +1474,15 @@ bool TreeWidget::eventFilter(QObject*, QEvent* ev) {
return false;
}
namespace Gui {
bool isTreeViewDragging()
{
return _DraggingActive;
}
} // namespace Gui
void TreeWidget::keyPressEvent(QKeyEvent* event)
{
if (event->matches(QKeySequence::Find)) {
@@ -1477,6 +1624,7 @@ void TreeWidget::startDragging() {
void TreeWidget::startDrag(Qt::DropActions supportedActions)
{
Base::StateLocker guard(_DraggingActive);
QTreeWidget::startDrag(supportedActions);
if (_DragEventFilter) {
_DragEventFilter = false;

View File

@@ -46,9 +46,12 @@ class ViewProviderDocumentObject;
class DocumentObjectItem;
class DocumentObjectData;
using DocumentObjectDataPtr = std::shared_ptr<DocumentObjectData>;
class TreeWidgetItemDelegate;
class DocumentItem;
GuiExport bool isTreeViewDragging();
/** Tree view that allows drag & drop of document objects.
* @author Werner Mayer
*/
@@ -66,6 +69,13 @@ public:
void selectLinkedObject(App::DocumentObject *linked);
void selectAllLinks(App::DocumentObject *obj);
void expandSelectedItems(TreeItemMode mode);
static int iconSize();
int iconHeight() const;
void setIconHeight(int height);
int itemSpacing() const;
void setItemSpacing(int);
bool eventFilter(QObject *, QEvent *ev) override;
@@ -241,6 +251,7 @@ private:
friend class DocumentItem;
friend class DocumentObjectItem;
friend class TreeParams;
friend class TreeWidgetItemDelegate;
using Connection = boost::signals2::connection;
Connection connectNewDocument;
@@ -480,19 +491,6 @@ public:
~TreeDockWidget() override;
};
/**
* TreeWidget item delegate for editing
*/
class TreeWidgetEditDelegate: public QStyledItemDelegate {
Q_OBJECT
public:
explicit TreeWidgetEditDelegate(QObject* parent=nullptr);
QWidget* createEditor(QWidget *parent,
const QStyleOptionViewItem &, const QModelIndex &index) const override;
};
}
#endif // GUI_TREE_H

View File

@@ -140,7 +140,7 @@ public:
funcs["ItemSpacing"] = &TreeParamsP::updateItemSpacing;
ItemBackground = handle->GetUnsigned("ItemBackground", 0x00000000);
funcs["ItemBackground"] = &TreeParamsP::updateItemBackground;
ItemBackgroundPadding = handle->GetInt("ItemBackgroundPadding", 10);
ItemBackgroundPadding = handle->GetInt("ItemBackgroundPadding", 0);
funcs["ItemBackgroundPadding"] = &TreeParamsP::updateItemBackgroundPadding;
HideColumn = handle->GetBool("HideColumn", true);
funcs["HideColumn"] = &TreeParamsP::updateHideColumn;
@@ -347,7 +347,7 @@ public:
}
// Auto generated code (Tools/params_utils.py:244)
static void updateItemBackgroundPadding(TreeParamsP *self) {
auto v = self->handle->GetInt("ItemBackgroundPadding", 10);
auto v = self->handle->GetInt("ItemBackgroundPadding", 0);
if (self->ItemBackgroundPadding != v) {
self->ItemBackgroundPadding = v;
TreeParams::onItemBackgroundPaddingChanged();
@@ -1174,7 +1174,7 @@ const long & TreeParams::getItemBackgroundPadding() {
// Auto generated code (Tools/params_utils.py:300)
const long & TreeParams::defaultItemBackgroundPadding() {
const static long def = 10;
const static long def = 0;
return def;
}
@@ -1403,10 +1403,9 @@ void TreeParams::onResizableColumnChanged() {
}
void TreeParams::onIconSizeChanged() {
// auto tree = TreeWidget::instance();
// Commented out temporarily while merging PR #7888
//if (tree)
//tree->setIconHeight(TreeParams::getIconSize());
auto tree = TreeWidget::instance();
if (tree)
tree->setIconHeight(TreeParams::getIconSize());
}
void TreeParams::onFontSizeChanged() {

View File

@@ -66,8 +66,8 @@ Params = [
ParamInt('FontSize', 0, on_change=True),
ParamInt('ItemSpacing', 0, on_change=True),
ParamHex('ItemBackground', 0, on_change=True, title='Item background color', proxy=ParamColor(),
doc = "Tree view item background. Only effective in overlay."),
ParamInt('ItemBackgroundPadding', 10, on_change=True, title="Item background padding", proxy=ParamSpinBox(0, 100, 1),
doc = "Tree view item background. Only effecitve in overlay."),
ParamInt('ItemBackgroundPadding', 0, on_change=True, title="Item background padding", proxy=ParamSpinBox(0, 100, 1),
doc = "Tree view item background padding."),
ParamBool('HideColumn', True, on_change=True, title="Hide extra column",
doc = "Hide extra tree view column for item description."),

View File

@@ -40,6 +40,7 @@
# include <QToolTip>
#endif
#include <Base/Console.h>
#include <Base/Tools.h>
#include <Base/Exception.h>
#include <Base/Interpreter.h>
@@ -1164,11 +1165,17 @@ void ToolTip::showText(const QPoint & pos, const QString & text, QWidget * w)
tip->displayTime.start();
}
else {
// do immediately
QToolTip::showText(pos, text, w);
hideText();
}
}
void ToolTip::hideText()
{
instance()->tooltipTimer.stop();
instance()->hidden = true;
QToolTip::hideText();
}
void ToolTip::timerEvent(QTimerEvent *e)
{
if (e->timerId() == tooltipTimer.timerId()) {
@@ -1180,25 +1187,45 @@ void ToolTip::timerEvent(QTimerEvent *e)
bool ToolTip::eventFilter(QObject* o, QEvent*e)
{
// This is a trick to circumvent that the tooltip gets hidden immediately
// after it gets visible. We just filter out all timer events to keep the
// label visible.
if (o->inherits("QLabel")) {
auto label = qobject_cast<QLabel*>(o);
// Ignore the timer events to prevent from being closed
if (label->windowFlags() & Qt::ToolTip) {
if (e->type() == QEvent::Show) {
this->hidden = false;
}
else if (e->type() == QEvent::Hide) {
removeEventFilter();
this->hidden = true;
}
else if (e->type() == QEvent::Timer &&
!this->hidden && displayTime.elapsed() < 5000) {
return true;
if (!o->isWidgetType())
return false;
switch(e->type()) {
case QEvent::MouseButtonPress:
hideText();
break;
case QEvent::KeyPress:
if (static_cast<QKeyEvent*>(e)->key() == Qt::Key_Escape)
hideText();
break;
case QEvent::Leave:
hideText();
break;
case QEvent::Timer:
case QEvent::Show:
case QEvent::Hide:
if (auto label = qobject_cast<QLabel*>(o)) {
if (label->objectName() == QStringLiteral("qtooltip_label")) {
// This is a trick to circumvent that the tooltip gets hidden immediately
// after it gets visible. We just filter out all timer events to keep the
// label visible.
// Ignore the timer events to prevent from being closed
if (e->type() == QEvent::Show) {
this->hidden = false;
}
else if (e->type() == QEvent::Hide) {
// removeEventFilter();
this->hidden = true;
}
else if (e->type() == QEvent::Timer &&
!this->hidden && displayTime.elapsed() < 5000) {
return true;
}
}
}
break;
default:
break;
}
return false;
}

View File

@@ -449,6 +449,7 @@ class GuiExport ToolTip : public QObject
{
public:
static void showText(const QPoint & pos, const QString & text, QWidget * w = nullptr);
static void hideText();
protected:
static ToolTip* instance();

View File

@@ -699,7 +699,7 @@ MenuItem* StdWorkbench::setupMenuBar() const
<< "Separator" << visu
<< "Std_ToggleNavigation"
<< "Std_SetAppearance" << "Std_RandomColor" << "Separator"
<< "Std_Workbench" << "Std_ToolBarMenu" << "Std_DockViewMenu" << "Separator"
<< "Std_Workbench" << "Std_ToolBarMenu" << "Std_DockViewMenu" << "Std_DockOverlay" << "Separator"
<< "Std_LinkSelectActions"
<< "Std_TreeViewActions"
<< "Std_ViewStatusBar";

View File

@@ -83,6 +83,8 @@ PropertyEditor::PropertyEditor(QWidget *parent)
this->background = opt.palette.dark();
this->groupColor = opt.palette.color(QPalette::BrightText);
this->_itemBackground.setColor(QColor(0,0,0,0));
this->setSelectionMode(QAbstractItemView::ExtendedSelection);
connect(this, &QTreeView::activated, this, &PropertyEditor::onItemActivated);
@@ -154,6 +156,16 @@ void PropertyEditor::setGroupTextColor(const QColor& c)
this->groupColor = c;
}
QBrush PropertyEditor::itemBackground() const
{
return this->_itemBackground;
}
void PropertyEditor::setItemBackground(const QBrush& c)
{
this->_itemBackground = c;
}
#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
QStyleOptionViewItem PropertyEditor::viewOptions() const
{

View File

@@ -64,6 +64,7 @@ class PropertyEditor : public QTreeView
Q_PROPERTY(QBrush groupBackground READ groupBackground WRITE setGroupBackground DESIGNABLE true SCRIPTABLE true) // clazy:exclude=qproperty-without-notify
Q_PROPERTY(QColor groupTextColor READ groupTextColor WRITE setGroupTextColor DESIGNABLE true SCRIPTABLE true) // clazy:exclude=qproperty-without-notify
Q_PROPERTY(QBrush itemBackground READ itemBackground WRITE setItemBackground DESIGNABLE true SCRIPTABLE true) // clazy:exclude=qproperty-without-notify
public:
PropertyEditor(QWidget *parent = nullptr);
@@ -84,6 +85,8 @@ public:
void setGroupBackground(const QBrush& c);
QColor groupTextColor() const;
void setGroupTextColor(const QColor& c);
QBrush itemBackground() const;
void setItemBackground(const QBrush& c);
bool isBinding() const { return binding; }
void openEditor(const QModelIndex &index);
@@ -135,6 +138,7 @@ private:
QColor groupColor;
QBrush background;
QBrush _itemBackground;
QPointer<QWidget> activeEditor;
QPersistentModelIndex editingIndex;