23static const int s_invalidTabIndex = -2;
24static const int s_autoHideAreaWidth = 32;
25static const int s_autoHideAreaMouseZone = 8;
27class DockOverlayPrivate
37 DockOverlay::OverlayMode m_mode = DockOverlay::PanelOverlayMode;
40 QPointer<QWidget> m_targetWidget;
41 bool m_dropPreviewEnabled =
true;
43 int m_tabIndex = s_invalidTabIndex;
44 DockOverlayCross *m_cross;
47DockOverlayPrivate::DockOverlayPrivate()
53 auto container = qobject_cast<DockContainer *>(m_targetWidget.data());
54 auto sideBar = container->autoHideSideBar(area);
55 if (!sideBar || !sideBar->isVisibleTo(container)) {
56 return s_autoHideAreaWidth;
58 return (sideBar->orientation() == Qt::Horizontal) ? sideBar->height() : sideBar->width();
64 auto container = qobject_cast<DockContainer *>(m_targetWidget.data());
65 auto sideBar = container->autoHideSideBar(area);
66 if (!sideBar || !sideBar->isVisibleTo(container)) {
67 return s_autoHideAreaMouseZone;
69 return (sideBar->orientation() == Qt::Horizontal) ? sideBar->height() : sideBar->width();
83 setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
85 setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
88 setWindowTitle(
"DockOverlay");
89 setAttribute(Qt::WA_NoSystemBackground);
90 setAttribute(Qt::WA_TranslucentBackground);
92 d->m_cross->setVisible(
false);
104 if (areas == d->m_allowedAreas) {
107 d->m_allowedAreas = areas;
114 auto areasOld = d->m_allowedAreas;
115 d->m_allowedAreas.setFlag(area, enable);
116 if (areasOld != d->m_allowedAreas) {
124 return d->m_allowedAreas;
130 d->m_tabIndex = s_invalidTabIndex;
131 if (!d->m_targetWidget) {
140 auto cursorPos = QCursor::pos();
141 auto panel = qobject_cast<DockPanel *>(d->m_targetWidget.data());
144 const QPoint pos = mapFromGlobal(QCursor::pos());
160 auto container = qobject_cast<DockContainer *>(d->m_targetWidget.data());
161 auto sideBar = container->autoHideSideBar(sideBarArea);
162 if (sideBar->isVisible()) {
163 d->m_tabIndex = sideBar->tabInsertIndexAt(sideBar->mapFromGlobal(cursorPos));
172 panel->titleBarGeometry().contains(panel->mapFromGlobal(cursorPos))) {
173 auto tabBar = panel->titleBar()->tabBar();
174 d->m_tabIndex = tabBar->tabInsertIndexAt(tabBar->mapFromGlobal(cursorPos));
193 return d->m_tabIndex;
199 if (isHidden() || !d->m_dropPreviewEnabled) {
209 if (d->m_targetWidget == target) {
212 if (da != d->m_lastLocation) {
214 d->m_lastLocation = da;
219 d->m_targetWidget = target;
224 resize(target->size());
225 QPoint TopLeft = target->mapToGlobal(target->rect().topLeft());
228 d->m_cross->updatePosition();
229 d->m_cross->updateOverlayIcons();
238 d->m_targetWidget.clear();
240 d->m_dropAreaRect = QRect();
246 d->m_dropPreviewEnabled = enable;
253 return d->m_dropAreaRect;
259 bool result = Super::event(e);
260 if (e->type() == QEvent::Polish) {
261 d->m_cross->setupOverlayCross(d->m_mode);
272 if (!d->m_dropPreviewEnabled) {
273 d->m_dropAreaRect = QRect();
283 r.setHeight(r.height() / factor);
286 r.setX(r.width() * (1 - 1 / factor));
289 r.setY(r.height() * (1 - 1 / factor));
292 r.setWidth(r.width() / factor);
313 QPainter painter(
this);
314 QColor color = palette().color(QPalette::Active, QPalette::Highlight);
315 QPen pen = painter.pen();
316 pen.setColor(color.darker(120));
317 pen.setStyle(Qt::SolidLine);
319 pen.setCosmetic(
true);
321 color = color.lighter(130);
323 painter.setBrush(color);
324 painter.drawRect(r.adjusted(0, 0, -1, -1));
326 d->m_dropAreaRect = r;
344class DockOverlayCrossPrivate
349 DockOverlayCrossPrivate();
358 qreal dropIndicatiorWidth(QLabel *l)
const;
361 void updateDropIndicatorIcon(QWidget *DropIndicatorWidget);
362 QPixmap createHighDpiDropIndicatorPixmap(
const QSizeF &size,
Qx::DockWidgetArea dockWidgetArea,
366 QGridLayout *m_gridLayout;
368 QHash<Qx::DockWidgetArea, QWidget *> m_dropIndicatorWidgets;
370 bool m_updateRequired =
false;
371 double m_lastDevicePixelRatio = 0.1;
374DockOverlayCrossPrivate::DockOverlayCrossPrivate()
378void DockOverlayCrossPrivate::init()
380 Q_Q(DockOverlayCross);
382 m_gridLayout =
new QGridLayout();
383 m_gridLayout->setSpacing(0);
384 q->setLayout(m_gridLayout);
391 return (
int)Qt::AlignHCenter | Qt::AlignBottom;
393 return (
int)Qt::AlignLeft | Qt::AlignVCenter;
395 return (
int)Qt::AlignHCenter | Qt::AlignTop;
397 return (
int)Qt::AlignRight | Qt::AlignVCenter;
399 return (
int)Qt::AlignCenter;
401 return Qt::AlignCenter;
442 Q_Q(DockOverlayCross);
443 QPalette pal = q->palette();
444 switch (colorIndex) {
446 return pal.color(QPalette::Active, QPalette::Highlight);
448 return pal.color(QPalette::Active, QPalette::Base);
450 QColor Color = pal.color(QPalette::Active, QPalette::Highlight);
456 return pal.color(QPalette::Active, QPalette::Base);
458 return QColor(0, 0, 0, 64);
468 QColor color = m_iconColors[colorIndex];
469 if (!color.isValid()) {
470 color = defaultIconColor(colorIndex);
471 m_iconColors[colorIndex] = color;
476qreal DockOverlayCrossPrivate::dropIndicatiorWidth(QLabel *l)
const
482 return static_cast<qreal
>(l->fontMetrics().height()) * 3.f;
486QWidget *DockOverlayCrossPrivate::createDropIndicatorWidget(
Qx::DockWidgetArea dockWidgetArea,
489 QLabel *l =
new QLabel();
490 l->setObjectName(
"DockWidgetAreaLabel");
492 qreal metric = dropIndicatiorWidth(l);
493 QSizeF size(metric, metric);
497 size.setHeight(size.height() / 2);
499 size.setWidth(size.width() / 2);
503 l->setPixmap(createHighDpiDropIndicatorPixmap(size, dockWidgetArea, mode));
504 l->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
505 l->setAttribute(Qt::WA_TranslucentBackground);
506 l->setProperty(
"dockWidgetArea", dockWidgetArea);
510void DockOverlayCrossPrivate::updateDropIndicatorIcon(QWidget *dropIndicatorWidget)
512 QLabel *l = qobject_cast<QLabel *>(dropIndicatorWidget);
513 const qreal metric = dropIndicatiorWidth(l);
514 const QSizeF size(metric, metric);
516 int area = l->property(
"dockWidgetArea").toInt();
517 l->setPixmap(createHighDpiDropIndicatorPixmap(size, (
Qx::DockWidgetArea)area, m_mode));
520QPixmap DockOverlayCrossPrivate::createHighDpiDropIndicatorPixmap(
const QSizeF &size,
Qx::DockWidgetArea dockWidgetArea,
523 Q_Q(DockOverlayCross);
527 if (overlayColor.alpha() == 255) {
528 overlayColor.setAlpha(64);
531#if QT_VERSION >= 0x050600
532 double devicePixelRatio = q->window()->devicePixelRatioF();
534 double devicePixelRatio = q->window()->devicePixelRatio();
536 QSizeF pixmapSize = size * devicePixelRatio;
537 QPixmap pm(pixmapSize.toSize());
538 pm.fill(QColor(0, 0, 0, 0));
542 QRectF shadowRect(pm.rect());
544 baseRect.setSize(shadowRect.size() * 0.7);
545 baseRect.moveCenter(shadowRect.center());
549 if (shadowColor.alpha() == 255) {
550 shadowColor.setAlpha(64);
552 p.fillRect(shadowRect, shadowColor);
559 switch (dockWidgetArea) {
561 areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f);
562 nonAreaRect = QRectF(baseRect.x(), shadowRect.height() * .5f, baseRect.width(), baseRect.height() * .5f);
563 areaLine = QLineF(areaRect.bottomLeft(), areaRect.bottomRight());
566 areaRect = QRectF(shadowRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height());
567 nonAreaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height());
568 areaLine = QLineF(areaRect.topLeft(), areaRect.bottomLeft());
571 areaRect = QRectF(baseRect.x(), shadowRect.height() * .5f, baseRect.width(), baseRect.height() * .5f);
572 nonAreaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f);
573 areaLine = QLineF(areaRect.topLeft(), areaRect.topRight());
576 areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height());
577 nonAreaRect = QRectF(shadowRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height());
578 areaLine = QLineF(areaRect.topRight(), areaRect.bottomRight());
584 QSizeF baseSize = baseRect.size();
585 bool isOuterContainerArea =
588 if (isOuterContainerArea) {
592 p.fillRect(baseRect, backgroundColor);
594 if (areaRect.isValid()) {
596 pen.setColor(borderColor);
597 p.setBrush(overlayColor);
599 p.drawRect(areaRect);
603 pen.setColor(borderColor);
604 pen.setStyle(Qt::DashLine);
606 p.drawLine(areaLine);
613 pen.setColor(borderColor);
615 p.setBrush(Qt::NoBrush);
617 p.drawRect(baseRect);
620 p.setBrush(borderColor);
621 QRectF frameRect(baseRect.topLeft(), QSizeF(baseRect.width(), baseSize.height() / 10));
622 p.drawRect(frameRect);
626 if (isOuterContainerArea) {
628 arrowRect.setSize(baseSize);
629 arrowRect.setWidth(arrowRect.width() / 4.6);
630 arrowRect.setHeight(arrowRect.height() / 2);
631 arrowRect.moveCenter(QPointF(0, 0));
633 arrow << arrowRect.topLeft() << QPointF(arrowRect.right(), arrowRect.center().y()) << arrowRect.bottomLeft();
636 p.setRenderHint(QPainter::Antialiasing,
true);
637 p.translate(nonAreaRect.center().x(), nonAreaRect.center().y());
639 switch (dockWidgetArea) {
655 p.drawPolygon(arrow);
658 pm.setDevicePixelRatio(devicePixelRatio);
663 : QWidget(overlay->parentWidget())
667 d->m_dockOverlay = overlay;
670 setWindowFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
672 setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
674 setWindowTitle(
"DockOverlayCross");
675 setAttribute(Qt::WA_TranslucentBackground);
686 return d->m_iconColors[colorIndex];
692 d->m_iconColors[colorIndex] = color;
693 d->m_updateRequired =
true;
704 const QPoint pos = mapFromGlobal(QCursor::pos());
705 QHashIterator<Qx::DockWidgetArea, QWidget *> i(d->m_dropIndicatorWidgets);
706 while (i.hasNext()) {
708 if (d->m_dockOverlay->allowedAreas().testFlag(i.key()) && i.value() && i.value()->isVisible() &&
709 i.value()->geometry().contains(pos)) {
721 QHash<Qx::DockWidgetArea, QWidget *> areaWidgets;
728#if QT_VERSION >= 0x050600
729 d->m_lastDevicePixelRatio = devicePixelRatioF();
731 d->m_lastDevicePixelRatio = devicePixelRatio();
734 d->m_updateRequired =
false;
740 if (windowHandle()->devicePixelRatio() == d->m_lastDevicePixelRatio) {
744 for (
auto Widget : d->m_dropIndicatorWidgets) {
745 d->updateDropIndicatorIcon(Widget);
747#if QT_VERSION >= 0x050600
748 d->m_lastDevicePixelRatio = devicePixelRatioF();
750 d->m_lastDevicePixelRatio = devicePixelRatio();
757 QList<Qx::DockWidgetArea> allAreas;
760 const Qx::DockWidgetAreas allowedAreas = d->m_dockOverlay->allowedAreas();
763 for (
int i = 0; i < allAreas.count(); ++i) {
764 QPoint p = d->areaGridPosition(allAreas.at(i));
765 QLayoutItem *item = d->m_gridLayout->itemAtPosition(p.x(), p.y());
766 QWidget *w =
nullptr;
767 if (item && (w = item->widget()) !=
nullptr) {
768 w->setVisible(allowedAreas.testFlag(allAreas.at(i)));
776 resize(d->m_dockOverlay->size());
777 QPoint topLeft = d->m_dockOverlay->pos();
778 QPoint offest((this->width() - d->m_dockOverlay->width()) / 2, (this->height() - d->m_dockOverlay->height()) / 2);
779 QPoint crossTopLeft = topLeft - offest;
804#if (QT_VERSION < QT_VERSION_CHECK(5, 14, 0))
805 auto skipEmptyParts = QString::SkipEmptyParts;
807 auto skipEmptyParts = Qt::SkipEmptyParts;
809 auto colorList = colors.split(
' ', skipEmptyParts);
810 for (
const auto &colorListEntry : colorList) {
811 auto componentColor = colorListEntry.split(
'=', skipEmptyParts);
812 int component = ColorCompenentStringMap.value(componentColor[0], -1);
816 d->m_iconColors[component] = QColor(componentColor[1]);
819 d->m_updateRequired =
true;
831 QMutableHashIterator<Qx::DockWidgetArea, QWidget *> i(d->m_dropIndicatorWidgets);
832 while (i.hasNext()) {
834 QWidget *widget = i.value();
835 d->m_gridLayout->removeWidget(widget);
841 d->m_dropIndicatorWidgets = widgets;
842 QHashIterator<Qx::DockWidgetArea, QWidget *> i2(d->m_dropIndicatorWidgets);
843 while (i2.hasNext()) {
846 QWidget *widget = i2.value();
847 QPoint p = d->areaGridPosition(area);
848 d->m_gridLayout->addWidget(widget, p.x(), p.y(), (Qt::Alignment)areaAlignment(area));
852 d->m_gridLayout->setContentsMargins(0, 0, 0, 0);
853 d->m_gridLayout->setRowStretch(0, 1);
854 d->m_gridLayout->setRowStretch(1, 0);
855 d->m_gridLayout->setRowStretch(2, 0);
856 d->m_gridLayout->setRowStretch(3, 0);
857 d->m_gridLayout->setRowStretch(4, 1);
859 d->m_gridLayout->setColumnStretch(0, 1);
860 d->m_gridLayout->setColumnStretch(1, 0);
861 d->m_gridLayout->setColumnStretch(2, 0);
862 d->m_gridLayout->setColumnStretch(3, 0);
863 d->m_gridLayout->setColumnStretch(4, 1);
865 d->m_gridLayout->setContentsMargins(4, 4, 4, 4);
866 d->m_gridLayout->setRowStretch(0, 0);
867 d->m_gridLayout->setRowStretch(1, 1);
868 d->m_gridLayout->setRowStretch(2, 1);
869 d->m_gridLayout->setRowStretch(3, 1);
870 d->m_gridLayout->setRowStretch(4, 0);
872 d->m_gridLayout->setColumnStretch(0, 0);
873 d->m_gridLayout->setColumnStretch(1, 1);
874 d->m_gridLayout->setColumnStretch(2, 1);
875 d->m_gridLayout->setColumnStretch(3, 1);
876 d->m_gridLayout->setColumnStretch(4, 0);
885 if (d->m_updateRequired) {
static AutoHideFlags autoHideConfigFlags()
DockOverlayCross shows a cross with 5 different drop area possibilities.
void setIconColor(IconColor colorIndex, const QColor &color)
void setupOverlayCross(DockOverlay::OverlayMode mode)
DockOverlayCross(DockOverlay *overlay)
void updateOverlayIcons()
@ WindowBackgroundColor
the background color of the small window in the icon
@ ShadowColor
the color of the shadow rectangle that is painted below the icons
@ FrameColor
the color of the frame of the small window icon
@ OverlayColor
the color that shows the overlay (the dock side) in the icon
@ ArrowColor
the arrow that points into the direction
virtual ~DockOverlayCross()
void setAreaWidgets(const QHash< Qx::DockWidgetArea, QWidget * > &widgets)
void setIconColors(const QString &colors)
A string with all icon colors to set.
virtual void showEvent(QShowEvent *e) override
QString iconColors() const
Qx::DockWidgetArea cursorLocation() const
Returns the dock widget area depending on the current cursor location.
DockOverlay paints a translucent rectangle over another widget.
virtual void showEvent(QShowEvent *e) override
QRect dropOverlayRect() const
int tabIndexUnderCursor() const
If the drop area is the CenterDockWidgetArea or a sidebar area, then this function returns the index ...
Qx::DockWidgetArea dropAreaUnderCursor()
void setAllowedArea(Qx::DockWidgetArea area, bool enable)
Qx::DockWidgetAreas allowedAreas() const
virtual bool event(QEvent *e) override
Qx::DockWidgetArea showOverlay(QWidget *target)
Qx::DockWidgetArea visibleDropAreaUnderCursor()
virtual void paintEvent(QPaintEvent *e) override
void setAllowedAreas(Qx::DockWidgetAreas areas)
virtual void hideEvent(QHideEvent *e) override
void enableDropPreview(bool enable)
bool isHorizontalSideBarArea(Qx::DockSideBarArea area)
Qx::DockSideBarArea toSideBarArea(Qx::DockWidgetArea area)
bool isSideBarArea(Qx::DockWidgetArea area)
#define QX_INIT_PRIVATE(Class)
#define QX_DECLARE_PUBLIC(Class)
#define QX_FINI_PRIVATE()
#define QX_DOCK_END_NAMESPACE
#define QX_DOCK_BEGIN_NAMESPACE