Improved transparent docking

This commit is contained in:
Uwe Kindler 2019-11-28 09:09:36 +01:00
parent 07f9c6d016
commit 2fe542c3ef
4 changed files with 82 additions and 32 deletions

View File

@ -322,7 +322,9 @@ CMainWindow::CMainWindow(QWidget *parent) :
// uncomment the following line if you wand a fixed tab width that does // uncomment the following line if you wand a fixed tab width that does
// not change if the visibility of the close button changes // not change if the visibility of the close button changes
CDockManager::setConfigFlag(CDockManager::OpaqueUndocking, false); //CDockManager::setConfigFlag(CDockManager::OpaqueUndocking, false);
//CDockManager::setConfigFlag(CDockManager::DragPreviewIsDynamic, false);
CDockManager::setConfigFlags(CDockManager::NonOpaqueWithWindowFrame);
// Now create the dock manager and its content // Now create the dock manager and its content
d->DockManager = new CDockManager(this); d->DockManager = new CDockManager(this);

View File

@ -152,12 +152,24 @@ public:
TabCloseButtonIsToolButton = 0x0040,//! If enabled the tab close buttons will be QToolButtons instead of QPushButtons - disabled by default TabCloseButtonIsToolButton = 0x0040,//! If enabled the tab close buttons will be QToolButtons instead of QPushButtons - disabled by default
AllTabsHaveCloseButton = 0x0080, //!< if this flag is set, then all tabs that are closable show a close button AllTabsHaveCloseButton = 0x0080, //!< if this flag is set, then all tabs that are closable show a close button
RetainTabSizeWhenCloseButtonHidden = 0x0100, //!< if this flag is set, the space for the close button is reserved even if the close button is not visible RetainTabSizeWhenCloseButtonHidden = 0x0100, //!< if this flag is set, the space for the close button is reserved even if the close button is not visible
OpaqueUndocking = 0x0200, OpaqueUndocking = 0x0200,///< If enabled, the widgets are immediately undocked into floating widgets, if disabled, only a draw preview is undocked and the real undocking is deferred until the mouse is released
DragPreviewIsDynamic = 0x0400,///< If opaque undocking is disabled, this flag defines the behavior of the drag preview window, if this flag is enabled, the preview will be adjusted dynamically to the drop area
DragPreviewShowsContentPixmap = 0x0800,///< If opaque undocking is disabled, the created drag preview window shows a copy of the content of the dock widget / dock are that is dragged
DragPreviewHasWindowFrame = 0x1000,///< If opaque undocking is disabled, then this flag configures if the drag preview is frameless or looks like a real window
DefaultConfig = ActiveTabHasCloseButton DefaultConfig = ActiveTabHasCloseButton
| DockAreaHasCloseButton | DockAreaHasCloseButton
| OpaqueSplitterResize | OpaqueSplitterResize
| XmlCompressionEnabled | XmlCompressionEnabled
| OpaqueUndocking, ///< the default configuration | OpaqueUndocking, ///< the default configuration
DefaultNonOpaqueConfig = ActiveTabHasCloseButton
| DockAreaHasCloseButton
| XmlCompressionEnabled
| DragPreviewShowsContentPixmap, ///< the default configuration for non opaque operations
NonOpaqueWithWindowFrame = ActiveTabHasCloseButton
| DockAreaHasCloseButton
| XmlCompressionEnabled
| DragPreviewShowsContentPixmap
| DragPreviewHasWindowFrame ///< the default configuration for non opaque operations that show a real window with frame
}; };
Q_DECLARE_FLAGS(ConfigFlags, eConfigFlag) Q_DECLARE_FLAGS(ConfigFlags, eConfigFlag)

View File

@ -40,6 +40,7 @@ struct FloatingOverlayPrivate
qreal WindowOpacity; qreal WindowOpacity;
bool Hidden = false; bool Hidden = false;
bool IgnoreMouseEvents = false; bool IgnoreMouseEvents = false;
QPixmap ContentPreviewPixmap;
/** /**
@ -99,7 +100,10 @@ void FloatingOverlayPrivate::updateDropOverlays(const QPoint &GlobalPos)
{ {
ContainerOverlay->hideOverlay(); ContainerOverlay->hideOverlay();
DockAreaOverlay->hideOverlay(); DockAreaOverlay->hideOverlay();
setHidden(false); if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewIsDynamic))
{
setHidden(false);
}
return; return;
} }
@ -140,7 +144,10 @@ void FloatingOverlayPrivate::updateDropOverlays(const QPoint &GlobalPos)
} }
} }
setHidden(DockDropArea != InvalidDockWidgetArea || ContainerDropArea != InvalidDockWidgetArea); if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewIsDynamic))
{
setHidden(DockDropArea != InvalidDockWidgetArea || ContainerDropArea != InvalidDockWidgetArea);
}
} }
@ -153,21 +160,37 @@ FloatingOverlayPrivate::FloatingOverlayPrivate(CFloatingOverlay *_public) :
//============================================================================ //============================================================================
CFloatingOverlay::CFloatingOverlay(QWidget* Content, QWidget* parent) : CFloatingOverlay::CFloatingOverlay(QWidget* Content, QWidget* parent) :
QFrame(parent), QWidget(parent),
d(new FloatingOverlayPrivate(this)) d(new FloatingOverlayPrivate(this))
{ {
d->Content = Content; d->Content = Content;
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewHasWindowFrame))
{
setWindowFlags(
Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
}
else
{
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground);
}
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); setWindowOpacity(0.6);
setWindowOpacity(1);
setWindowTitle("FloatingOverlay");
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground);
// We install an event filter to detect mouse release events because we // We install an event filter to detect mouse release events because we
// do not receive mouse release event if the floating widget is behind // do not receive mouse release event if the floating widget is behind
// the drop overlay cross // the drop overlay cross
qApp->installEventFilter(this); qApp->installEventFilter(this);
// Create a static image of the widget that should get undocked
// This is like some kind preview image like it is uses in drag and drop
// operations
if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewShowsContentPixmap))
{
d->ContentPreviewPixmap = QPixmap(Content->size());
Content->render(&d->ContentPreviewPixmap);
}
} }
@ -181,6 +204,7 @@ CFloatingOverlay::CFloatingOverlay(CDockWidget* Content)
d->ContentSourceArea = Content->dockAreaWidget(); d->ContentSourceArea = Content->dockAreaWidget();
d->ContenSourceContainer = Content->dockContainer(); d->ContenSourceContainer = Content->dockContainer();
} }
setWindowTitle(Content->windowTitle());
} }
@ -191,6 +215,7 @@ CFloatingOverlay::CFloatingOverlay(CDockAreaWidget* Content)
d->DockManager = Content->dockManager(); d->DockManager = Content->dockManager();
d->ContentSourceArea = Content; d->ContentSourceArea = Content;
d->ContenSourceContainer = Content->dockContainer(); d->ContenSourceContainer = Content->dockContainer();
setWindowTitle(Content->currentDockWidget()->windowTitle());
} }
@ -241,7 +266,6 @@ bool CFloatingOverlay::eventFilter(QObject *watched, QEvent *event)
if (event->type() == QEvent::MouseButtonRelease && !d->IgnoreMouseEvents) if (event->type() == QEvent::MouseButtonRelease && !d->IgnoreMouseEvents)
{ {
ADS_PRINT("FloatingWidget::eventFilter QEvent::MouseButtonRelease"); ADS_PRINT("FloatingWidget::eventFilter QEvent::MouseButtonRelease");
std::cout << "CFloatingOverlay::eventFilter QEvent::MouseButtonRelease" << std::endl;
auto DockDropArea = d->DockManager->dockAreaOverlay()->dropAreaUnderCursor(); auto DockDropArea = d->DockManager->dockAreaOverlay()->dropAreaUnderCursor();
auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor(); auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor();
@ -265,16 +289,22 @@ bool CFloatingOverlay::eventFilter(QObject *watched, QEvent *event)
} }
FloatingWidget->setGeometry(this->geometry()); FloatingWidget->setGeometry(this->geometry());
FloatingWidget->show(); FloatingWidget->show();
QApplication::processEvents(); if (!CDockManager::configFlags().testFlag(CDockManager::DragPreviewHasWindowFrame))
int FrameHeight = FloatingWidget->frameGeometry().height() - FloatingWidget->geometry().height(); {
QRect FixedGeometry = this->geometry(); QApplication::processEvents();
FixedGeometry.adjust(0, FrameHeight, 0, 0); int FrameHeight = FloatingWidget->frameGeometry().height() - FloatingWidget->geometry().height();
FloatingWidget->setGeometry(FixedGeometry); QRect FixedGeometry = this->geometry();
FixedGeometry.adjust(0, FrameHeight, 0, 0);
FloatingWidget->setGeometry(FixedGeometry);
}
} }
this->close(); this->close();
d->DockManager->containerOverlay()->hideOverlay(); d->DockManager->containerOverlay()->hideOverlay();
d->DockManager->dockAreaOverlay()->hideOverlay(); d->DockManager->dockAreaOverlay()->hideOverlay();
// Because we use the event filter, we receive multiple mouse release
// events. To prevent multiple code execution, we ignore all mouse
// events after the first mouse event
d->IgnoreMouseEvents = true; d->IgnoreMouseEvents = true;
} }
@ -286,25 +316,31 @@ bool CFloatingOverlay::eventFilter(QObject *watched, QEvent *event)
void CFloatingOverlay::paintEvent(QPaintEvent* event) void CFloatingOverlay::paintEvent(QPaintEvent* event)
{ {
Q_UNUSED(event); Q_UNUSED(event);
if (d->Hidden) if (d->Hidden)
{ {
return; return;
} }
QRect r = rect();
QPainter painter(this); QPainter painter(this);
QColor Color = palette().color(QPalette::Active, QPalette::Highlight); if (CDockManager::configFlags().testFlag(CDockManager::DragPreviewShowsContentPixmap))
QPen Pen = painter.pen(); {
Pen.setColor(Color.darker(120)); painter.drawPixmap(QPoint(0, 0), d->ContentPreviewPixmap);
Pen.setStyle(Qt::SolidLine); }
Pen.setWidth(1);
Pen.setCosmetic(true); if (!CDockManager::configFlags().testFlag(CDockManager::DragPreviewHasWindowFrame))
painter.setPen(Pen); {
Color = Color.lighter(130); QColor Color = palette().color(QPalette::Active, QPalette::Highlight);
Color.setAlpha(64); QPen Pen = painter.pen();
painter.setBrush(Color); Pen.setColor(Color.darker(120));
painter.drawRect(r.adjusted(0, 0, -1, -1)); Pen.setStyle(Qt::SolidLine);
Pen.setWidth(1);
Pen.setCosmetic(true);
painter.setPen(Pen);
Color = Color.lighter(130);
Color.setAlpha(64);
painter.setBrush(Color);
painter.drawRect(rect().adjusted(0, 0, -1, -1));
}
} }

View File

@ -10,7 +10,7 @@
//============================================================================ //============================================================================
// INCLUDES // INCLUDES
//============================================================================ //============================================================================
#include <QFrame> #include <QWidget>
#include "FloatingDockContainer.h" #include "FloatingDockContainer.h"
namespace ads namespace ads
@ -23,7 +23,7 @@ struct FloatingOverlayPrivate;
* A floating overlay is a temporary floating widget that is just used to * A floating overlay is a temporary floating widget that is just used to
* indicate the floating widget movement * indicate the floating widget movement
*/ */
class CFloatingOverlay : public QFrame, public IFloatingWidget class CFloatingOverlay : public QWidget, public IFloatingWidget
{ {
private: private:
FloatingOverlayPrivate* d; FloatingOverlayPrivate* d;
@ -40,7 +40,7 @@ protected:
CFloatingOverlay(QWidget* Content, QWidget* parent); CFloatingOverlay(QWidget* Content, QWidget* parent);
public: public:
using Super = QRubberBand; using Super = QWidget;
CFloatingOverlay(CDockWidget* Content); CFloatingOverlay(CDockWidget* Content);
CFloatingOverlay(CDockAreaWidget* Content); CFloatingOverlay(CDockAreaWidget* Content);