From 0bd5dc57fad4f321990b88e1fcd1a4e5449ad83c Mon Sep 17 00:00:00 2001 From: mfreiholz Date: Fri, 15 Apr 2016 12:14:50 +0200 Subject: [PATCH] Preparation for #13 - custom drop images. - DropOverlay and DropSplitArea widgets are friendly, but still separate for better customization. - Both classes are reusable, no longer create a new instance of DropSplitArea for each show call. --- .../include/ads/DropOverlay.h | 32 ++- AdvancedDockingSystem/src/DropOverlay.cpp | 270 +++++++++++------- .../src/SectionTitleWidget.cpp | 14 +- 3 files changed, 198 insertions(+), 118 deletions(-) diff --git a/AdvancedDockingSystem/include/ads/DropOverlay.h b/AdvancedDockingSystem/include/ads/DropOverlay.h index e3e929f..499bfad 100644 --- a/AdvancedDockingSystem/include/ads/DropOverlay.h +++ b/AdvancedDockingSystem/include/ads/DropOverlay.h @@ -2,8 +2,10 @@ #define DROP_OVERLAY_H #include +#include #include #include +class QGridLayout; #include "ads/API.h" @@ -15,28 +17,33 @@ class DropSplitAreas; class DropOverlay : public QFrame { Q_OBJECT + friend class DropSplitAreas; public: DropOverlay(QWidget* parent); virtual ~DropOverlay(); - void setDropAreas(DropAreas areas); - void setFullAreaDropEnabled(bool enabled) { _fullAreaDrop = enabled; } + void setAllowedAreas(DropAreas areas); + DropAreas allowedAreas() const; + DropArea cursorLocation() const; - DropArea showDropOverlay(QWidget* target, DropAreas areas = AllAreas); - void showDropOverlay(QWidget* target, const QRect& targetAreaRect, DropAreas areas = AllAreas); + DropArea showDropOverlay(QWidget* target); + void showDropOverlay(QWidget* target, const QRect& targetAreaRect); void hideDropOverlay(); protected: virtual void paintEvent(QPaintEvent *e); + virtual void showEvent(QShowEvent* e); + virtual void hideEvent(QHideEvent* e); virtual void resizeEvent(QResizeEvent* e); virtual void moveEvent(QMoveEvent* e); private: + DropAreas _allowedAreas; DropSplitAreas* _splitAreas; - bool _fullAreaDrop; + bool _fullAreaDrop; QPointer _target; QRect _targetRect; DropArea _lastLocation; @@ -48,15 +55,18 @@ class DropSplitAreas : public QWidget Q_OBJECT public: - DropSplitAreas(DropAreas areas, QWidget* parent); + DropSplitAreas(DropOverlay* overlay); + void reset(); DropArea cursorLocation() const; + void setWidgetForArea(QWidget* widget, DropArea area); + +protected: + virtual void showEvent(QShowEvent* e); private: - QWidget* _top; - QWidget* _right; - QWidget* _bottom; - QWidget* _left; - QWidget* _center; + DropOverlay* _overlay; + QHash _widgets; + QGridLayout* _grid; }; ADS_NAMESPACE_END diff --git a/AdvancedDockingSystem/src/DropOverlay.cpp b/AdvancedDockingSystem/src/DropOverlay.cpp index 92c2ed1..9d66360 100644 --- a/AdvancedDockingSystem/src/DropOverlay.cpp +++ b/AdvancedDockingSystem/src/DropOverlay.cpp @@ -26,41 +26,44 @@ static QWidget* createDropWidget(const QString& img) DropOverlay::DropOverlay(QWidget* parent) : QFrame(parent), - _splitAreas(NULL), + _allowedAreas(InvalidDropArea), + _splitAreas(new DropSplitAreas(this)), _fullAreaDrop(false), _lastLocation(InvalidDropArea) { setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); setWindowOpacity(0.2); setWindowTitle("DropOverlay"); - setVisible(false); QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom); l->setContentsMargins(0, 0, 0, 0); l->setSpacing(0); setLayout(l); + + _splitAreas->setVisible(false); + setVisible(false); } DropOverlay::~DropOverlay() { - if (_splitAreas) - { - delete _splitAreas; - _splitAreas = NULL; - } + delete _splitAreas; + _splitAreas = NULL; } -void DropOverlay::setDropAreas(DropAreas areas) +void DropOverlay::setAllowedAreas(DropAreas areas) { - if (_splitAreas) - { - delete _splitAreas; - _splitAreas = NULL; - } - _splitAreas = new DropSplitAreas(areas, parentWidget()); + if (areas == _allowedAreas) + return; + _allowedAreas = areas; + + _splitAreas->reset(); _splitAreas->move(pos()); _splitAreas->resize(size()); - _splitAreas->setVisible(false); +} + +DropAreas DropOverlay::allowedAreas() const +{ + return _allowedAreas; } DropArea DropOverlay::cursorLocation() const @@ -73,7 +76,7 @@ DropArea DropOverlay::cursorLocation() const return loc; } -DropArea DropOverlay::showDropOverlay(QWidget* target, DropAreas areas) +DropArea DropOverlay::showDropOverlay(QWidget* target) { if (_target == target) { @@ -86,54 +89,53 @@ DropArea DropOverlay::showDropOverlay(QWidget* target, DropAreas areas) } return da; } - hideDropOverlay(); - // Move directly over the "parent" widget. - setDropAreas(areas); - setFullAreaDropEnabled(false); + hideDropOverlay(); + _fullAreaDrop = false; + _target = target; + _targetRect = QRect(); + _lastLocation = InvalidDropArea; + + // Move it over the target. resize(target->size()); move(target->mapToGlobal(target->rect().topLeft())); + show(); - _splitAreas->show(); - _target = target; + return cursorLocation(); } -void DropOverlay::showDropOverlay(QWidget* target, const QRect& targetAreaRect, DropAreas areas) +void DropOverlay::showDropOverlay(QWidget* target, const QRect& targetAreaRect) { if (_target == target && _targetRect == targetAreaRect) { return; } - hideDropOverlay(); - // Create overlay and move it to the parent's areaRect -// MyOverlay = new DropOverlay(areas, parent); - setDropAreas(areas); - setFullAreaDropEnabled(true); - resize(targetAreaRect.size()); - move(target->mapToGlobal(QPoint(targetAreaRect.x(), targetAreaRect.y()))); - show(); - _splitAreas->show(); + hideDropOverlay(); + _fullAreaDrop = true; _target = target; _targetRect = targetAreaRect; + _lastLocation = InvalidDropArea; + + // Move it over the target's area. + resize(targetAreaRect.size()); + move(target->mapToGlobal(QPoint(targetAreaRect.x(), targetAreaRect.y()))); + + show(); + return; } void DropOverlay::hideDropOverlay() { hide(); - if (_splitAreas) - { - _splitAreas->hide(); - } - + _fullAreaDrop = false; #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) _target.clear(); #else _target = 0; #endif - _targetRect = QRect(); _lastLocation = InvalidDropArea; } @@ -189,70 +191,43 @@ void DropOverlay::paintEvent(QPaintEvent*) // p.fillRect(r, QBrush(QColor(0, 100, 255), Qt::Dense4Pattern)); // p.setBrush(QBrush(QColor(0, 100, 255))); -// p.drawRect(r); + // p.drawRect(r); +} + +void DropOverlay::showEvent(QShowEvent*) +{ + _splitAreas->show(); +} + +void DropOverlay::hideEvent(QHideEvent*) +{ + _splitAreas->hide(); } void DropOverlay::resizeEvent(QResizeEvent* e) { - // Keep it in center of DropOverlay - if (_splitAreas) - { - _splitAreas->resize(e->size()); - } + _splitAreas->resize(e->size()); } void DropOverlay::moveEvent(QMoveEvent* e) { - // Keep it in center of DropOverlay - if (_splitAreas) - { - _splitAreas->move(e->pos()); - } + _splitAreas->move(e->pos()); } /////////////////////////////////////////////////////////////////////// -DropSplitAreas::DropSplitAreas(DropAreas areas, QWidget* parent) : - QWidget(parent), - _top(0), - _right(0), - _bottom(0), - _left(0), - _center(0) +DropSplitAreas::DropSplitAreas(DropOverlay* overlay) : + QWidget(overlay->parentWidget()), + _overlay(overlay), + _widgets() { setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); setWindowTitle("DropSplitAreas"); setAttribute(Qt::WA_TranslucentBackground); - QGridLayout* grid = new QGridLayout(); - grid->setContentsMargins(0, 0, 0, 0); - grid->setSpacing(6); - - if (areas.testFlag(ADS_NS::TopDropArea)) - { - _top = createDropWidget(":/img/split-top.png"); - grid->addWidget(_top, 0, 1, Qt::AlignHCenter | Qt::AlignBottom); - } - if (areas.testFlag(ADS_NS::RightDropArea)) - { - _right = createDropWidget(":/img/split-right.png"); - grid->addWidget(_right, 1, 2, Qt::AlignLeft | Qt::AlignVCenter); - } - if (areas.testFlag(ADS_NS::BottomDropArea)) - { - _bottom = createDropWidget(":/img/split-bottom.png"); - grid->addWidget(_bottom, 2, 1, Qt::AlignHCenter | Qt::AlignTop); - } - if (areas.testFlag(ADS_NS::LeftDropArea)) - { - _left = createDropWidget(":/img/split-left.png"); - grid->addWidget(_left, 1, 0, Qt::AlignRight | Qt::AlignVCenter); - } - if (areas.testFlag(ADS_NS::CenterDropArea)) - { - _center = createDropWidget(":/img/dock-center.png"); - grid->addWidget(_center, 1, 1, Qt::AlignCenter); - } + _grid = new QGridLayout(); + _grid->setContentsMargins(0, 0, 0, 0); + _grid->setSpacing(6); QBoxLayout* bl1 = new QBoxLayout(QBoxLayout::TopToBottom); bl1->setContentsMargins(0, 0, 0, 0); @@ -266,36 +241,125 @@ DropSplitAreas::DropSplitAreas(DropAreas areas, QWidget* parent) : bl1->addStretch(1); bl1->addLayout(bl2); bl2->addStretch(1); - bl2->addLayout(grid, 0); + bl2->addLayout(_grid, 0); bl2->addStretch(1); bl1->addStretch(1); } +void DropSplitAreas::reset() +{ + const DropAreas areas = _overlay->allowedAreas(); + + if (areas.testFlag(ADS_NS::TopDropArea)) + setWidgetForArea(createDropWidget(":/img/split-top.png"), ADS_NS::TopDropArea); + else + setWidgetForArea(NULL, ADS_NS::TopDropArea); + + if (areas.testFlag(ADS_NS::RightDropArea)) + setWidgetForArea(createDropWidget(":/img/split-right.png"), ADS_NS::RightDropArea); + else + setWidgetForArea(NULL, ADS_NS::RightDropArea); + + if (areas.testFlag(ADS_NS::BottomDropArea)) + setWidgetForArea(createDropWidget(":/img/split-bottom.png"), ADS_NS::BottomDropArea); + else + setWidgetForArea(NULL, ADS_NS::BottomDropArea); + + if (areas.testFlag(ADS_NS::LeftDropArea)) + setWidgetForArea(createDropWidget(":/img/split-left.png"), ADS_NS::LeftDropArea); + else + setWidgetForArea(NULL, ADS_NS::LeftDropArea); + + if (areas.testFlag(ADS_NS::CenterDropArea)) + setWidgetForArea(createDropWidget(":/img/dock-center.png"), ADS_NS::CenterDropArea); + else + setWidgetForArea(NULL, ADS_NS::CenterDropArea); +} + DropArea DropSplitAreas::cursorLocation() const { - DropArea loc = InvalidDropArea; - QPoint pos = mapFromGlobal(QCursor::pos()); - if (_top && _top->geometry().contains(pos)) + const QPoint pos = mapFromGlobal(QCursor::pos()); + QHashIterator i(_widgets); + while (i.hasNext()) { - loc = TopDropArea; + i.next(); + if (_overlay->allowedAreas().testFlag(i.key()) + && i.value() + && i.value()->isVisible() + && i.value()->geometry().contains(pos)) + { + return i.key(); + } } - else if (_right && _right->geometry().contains(pos)) + return InvalidDropArea; +} + +void DropSplitAreas::setWidgetForArea(QWidget* widget, DropArea area) +{ + QWidget* oldWidget = _widgets.take(area); + if (oldWidget) { - loc = RightDropArea; + _grid->removeWidget(oldWidget); + delete oldWidget; + oldWidget = NULL; } - else if (_bottom && _bottom->geometry().contains(pos)) + if (!widget) + return; + + switch (area) { - loc = BottomDropArea; + case ADS_NS::TopDropArea: + _grid->addWidget(widget, 0, 1, Qt::AlignHCenter | Qt::AlignBottom); + break; + case ADS_NS::RightDropArea: + _grid->addWidget(widget, 1, 2, Qt::AlignLeft | Qt::AlignVCenter); + break; + case ADS_NS::BottomDropArea: + _grid->addWidget(widget, 2, 1, Qt::AlignHCenter | Qt::AlignTop); + break; + case ADS_NS::LeftDropArea: + _grid->addWidget(widget, 1, 0, Qt::AlignRight | Qt::AlignVCenter); + break; + case ADS_NS::CenterDropArea: + _grid->addWidget(widget, 1, 1, Qt::AlignCenter); + break; + default: + return; } - else if (_left && _left->geometry().contains(pos)) - { - loc = LeftDropArea; - } - else if (_center && _center->geometry().contains(pos)) - { - loc = CenterDropArea; - } - return loc; + _widgets.insert(area, widget); + _grid->invalidate(); + +// if (area == ADS_NS::TopDropArea) +// { +// _top = createDropWidget(":/img/split-top.png"); +// _grid->addWidget(_top, 0, 1, Qt::AlignHCenter | Qt::AlignBottom); +// } +// else if (area ==(ADS_NS::RightDropArea)) +// { +// _right = createDropWidget(":/img/split-right.png"); +// _grid->addWidget(_right, 1, 2, Qt::AlignLeft | Qt::AlignVCenter); +// } +// if (areas.testFlag(ADS_NS::BottomDropArea)) +// { +// _bottom = createDropWidget(":/img/split-bottom.png"); +// _grid->addWidget(_bottom, 2, 1, Qt::AlignHCenter | Qt::AlignTop); +// } +// if (areas.testFlag(ADS_NS::LeftDropArea)) +// { +// _left = createDropWidget(":/img/split-left.png"); +// _grid->addWidget(_left, 1, 0, Qt::AlignRight | Qt::AlignVCenter); +// } +// if (areas.testFlag(ADS_NS::CenterDropArea)) +// { +// _center = createDropWidget(":/img/dock-center.png"); +// _grid->addWidget(_center, 1, 1, Qt::AlignCenter); + // } +} + +void DropSplitAreas::showEvent(QShowEvent* e) +{ + resize(_overlay->size()); + move(_overlay->pos()); } ADS_NAMESPACE_END diff --git a/AdvancedDockingSystem/src/SectionTitleWidget.cpp b/AdvancedDockingSystem/src/SectionTitleWidget.cpp index b1649c0..bd2ca6f 100644 --- a/AdvancedDockingSystem/src/SectionTitleWidget.cpp +++ b/AdvancedDockingSystem/src/SectionTitleWidget.cpp @@ -83,6 +83,7 @@ void SectionTitleWidget::mouseReleaseEvent(QMouseEvent* ev) SectionWidget* sw = cw->sectionAt(cw->mapFromGlobal(ev->globalPos())); if (sw) { + cw->_dropOverlay->setAllowedAreas(ADS_NS::AllAreas); DropArea loc = cw->_dropOverlay->showDropOverlay(sw); if (loc != InvalidDropArea) { @@ -194,25 +195,30 @@ void SectionTitleWidget::mouseMoveEvent(QMouseEvent* ev) section = cw->sectionAt(cw->mapFromGlobal(QCursor::pos())); if (section) { + cw->_dropOverlay->setAllowedAreas(ADS_NS::AllAreas); cw->_dropOverlay->showDropOverlay(section); } // Mouse is at the edge of the ContainerWidget // Top, Right, Bottom, Left else if (cw->outerTopDropRect().contains(cw->mapFromGlobal(QCursor::pos()))) { - cw->_dropOverlay->showDropOverlay(cw, cw->outerTopDropRect(), ADS_NS::TopDropArea); + cw->_dropOverlay->setAllowedAreas(ADS_NS::TopDropArea); + cw->_dropOverlay->showDropOverlay(cw, cw->outerTopDropRect()); } else if (cw->outerRightDropRect().contains(cw->mapFromGlobal(QCursor::pos()))) { - cw->_dropOverlay->showDropOverlay(cw, cw->outerRightDropRect(), ADS_NS::RightDropArea); + cw->_dropOverlay->setAllowedAreas(ADS_NS::RightDropArea); + cw->_dropOverlay->showDropOverlay(cw, cw->outerRightDropRect()); } else if (cw->outerBottomDropRect().contains(cw->mapFromGlobal(QCursor::pos()))) { - cw->_dropOverlay->showDropOverlay(cw, cw->outerBottomDropRect(), ADS_NS::BottomDropArea); + cw->_dropOverlay->setAllowedAreas(ADS_NS::BottomDropArea); + cw->_dropOverlay->showDropOverlay(cw, cw->outerBottomDropRect()); } else if (cw->outerLeftDropRect().contains(cw->mapFromGlobal(QCursor::pos()))) { - cw->_dropOverlay->showDropOverlay(cw, cw->outerLeftDropRect(), ADS_NS::LeftDropArea); + cw->_dropOverlay->setAllowedAreas(ADS_NS::LeftDropArea); + cw->_dropOverlay->showDropOverlay(cw, cw->outerLeftDropRect()); } else {