Qt-Advanced-Docking-System/AdvancedDockingSystem/src/DropOverlay.cpp

366 lines
8.4 KiB
C++
Raw Normal View History

#include "ads/DropOverlay.h"
2015-12-09 19:21:38 +08:00
#include <QPointer>
#include <QPaintEvent>
#include <QResizeEvent>
#include <QMoveEvent>
#include <QPainter>
#include <QGridLayout>
#include <QCursor>
#include <QIcon>
#include <QLabel>
2015-12-09 19:21:38 +08:00
ADS_NAMESPACE_BEGIN
// Helper /////////////////////////////////////////////////////////////
static QWidget* createDropWidget(const QString& img)
{
2016-02-12 14:15:10 +08:00
QLabel* label = new QLabel();
2015-12-09 19:21:38 +08:00
label->setObjectName("DropAreaLabel");
label->setPixmap(QPixmap(img));
return label;
}
///////////////////////////////////////////////////////////////////////
DropOverlay::DropOverlay(QWidget* parent) :
2015-12-09 19:21:38 +08:00
QFrame(parent),
_allowedAreas(InvalidDropArea),
_splitAreas(new DropSplitAreas(this)),
_fullAreaDrop(false),
_lastLocation(InvalidDropArea)
2015-12-09 19:21:38 +08:00
{
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
2015-12-09 19:21:38 +08:00
setWindowOpacity(0.2);
setWindowTitle("DropOverlay");
2015-12-09 19:21:38 +08:00
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
2015-12-09 19:21:38 +08:00
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
setLayout(l);
_splitAreas->setVisible(false);
setVisible(false);
2015-12-09 19:21:38 +08:00
}
DropOverlay::~DropOverlay()
{
delete _splitAreas;
_splitAreas = NULL;
2015-12-09 19:21:38 +08:00
}
void DropOverlay::setAllowedAreas(DropAreas areas)
{
if (areas == _allowedAreas)
return;
_allowedAreas = areas;
_splitAreas->reset();
_splitAreas->move(pos());
_splitAreas->resize(size());
}
DropAreas DropOverlay::allowedAreas() const
{
return _allowedAreas;
}
2015-12-09 19:21:38 +08:00
DropArea DropOverlay::cursorLocation() const
{
2016-02-12 14:15:10 +08:00
DropArea loc = InvalidDropArea;
2015-12-09 19:21:38 +08:00
if (_splitAreas)
{
loc = _splitAreas->cursorLocation();
}
return loc;
}
DropArea DropOverlay::showDropOverlay(QWidget* target)
{
if (_target == target)
{
// Hint: We could update geometry of overlay here.
DropArea da = cursorLocation();
if (da != _lastLocation)
{
repaint();
_lastLocation = da;
}
return da;
}
hideDropOverlay();
_fullAreaDrop = false;
_target = target;
_targetRect = QRect();
_lastLocation = InvalidDropArea;
// Move it over the target.
resize(target->size());
move(target->mapToGlobal(target->rect().topLeft()));
show();
return cursorLocation();
}
void DropOverlay::showDropOverlay(QWidget* target, const QRect& targetAreaRect)
{
if (_target == target && _targetRect == targetAreaRect)
{
return;
}
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();
_fullAreaDrop = false;
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
_target.clear();
#else
_target = 0;
#endif
_targetRect = QRect();
_lastLocation = InvalidDropArea;
}
2015-12-09 19:21:38 +08:00
void DropOverlay::paintEvent(QPaintEvent*)
{
QPainter p(this);
// Always draw drop-rect over the entire rect()
if (_fullAreaDrop)
{
QRect r = rect();
p.fillRect(r, QBrush(QColor(0, 100, 255), Qt::Dense4Pattern));
p.setBrush(QBrush(QColor(0, 100, 255)));
p.drawRect(r);
return;
}
// Draw rect based on location
QRect r = rect();
const DropArea da = cursorLocation();
switch (da)
{
case ADS_NS::TopDropArea:
r.setHeight(r.height() / 2);
break;
case ADS_NS::RightDropArea:
r.setX(r.width() / 2);
break;
case ADS_NS::BottomDropArea:
r.setY(r.height() / 2);
break;
case ADS_NS::LeftDropArea:
r.setWidth(r.width() / 2);
break;
case ADS_NS::CenterDropArea:
r = rect();
break;
default:
r = QRect();
}
if (!r.isNull())
{
p.fillRect(r, QBrush(QColor(0, 100, 255), Qt::Dense4Pattern));
p.setBrush(QBrush(QColor(0, 100, 255)));
p.drawRect(r);
}
2015-12-09 19:21:38 +08:00
// Draw rect over the entire size + border.
// auto r = rect();
// r.setWidth(r.width() - 1);
// r.setHeight(r.height() - 1);
2015-12-09 19:21:38 +08:00
// p.fillRect(r, QBrush(QColor(0, 100, 255), Qt::Dense4Pattern));
// p.setBrush(QBrush(QColor(0, 100, 255)));
// p.drawRect(r);
}
void DropOverlay::showEvent(QShowEvent*)
{
_splitAreas->show();
}
void DropOverlay::hideEvent(QHideEvent*)
{
_splitAreas->hide();
2015-12-09 19:21:38 +08:00
}
void DropOverlay::resizeEvent(QResizeEvent* e)
{
_splitAreas->resize(e->size());
2015-12-09 19:21:38 +08:00
}
void DropOverlay::moveEvent(QMoveEvent* e)
{
_splitAreas->move(e->pos());
2015-12-09 19:21:38 +08:00
}
///////////////////////////////////////////////////////////////////////
DropSplitAreas::DropSplitAreas(DropOverlay* overlay) :
QWidget(overlay->parentWidget()),
_overlay(overlay),
_widgets()
2015-12-09 19:21:38 +08:00
{
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
setWindowTitle("DropSplitAreas");
2015-12-09 19:21:38 +08:00
setAttribute(Qt::WA_TranslucentBackground);
_grid = new QGridLayout();
_grid->setContentsMargins(0, 0, 0, 0);
_grid->setSpacing(6);
2015-12-09 19:21:38 +08:00
QBoxLayout* bl1 = new QBoxLayout(QBoxLayout::TopToBottom);
bl1->setContentsMargins(0, 0, 0, 0);
bl1->setSpacing(0);
setLayout(bl1);
QBoxLayout* bl2 = new QBoxLayout(QBoxLayout::LeftToRight);
bl2->setContentsMargins(0, 0, 0, 0);
bl2->setSpacing(0);
bl1->addStretch(1);
bl1->addLayout(bl2);
bl2->addStretch(1);
bl2->addLayout(_grid, 0);
2015-12-09 19:21:38 +08:00
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);
}
2015-12-09 19:21:38 +08:00
DropArea DropSplitAreas::cursorLocation() const
{
const QPoint pos = mapFromGlobal(QCursor::pos());
QHashIterator<DropArea, QWidget*> i(_widgets);
while (i.hasNext())
2015-12-09 19:21:38 +08:00
{
i.next();
if (_overlay->allowedAreas().testFlag(i.key())
&& i.value()
&& i.value()->isVisible()
&& i.value()->geometry().contains(pos))
{
return i.key();
}
2015-12-09 19:21:38 +08:00
}
return InvalidDropArea;
}
void DropSplitAreas::setWidgetForArea(QWidget* widget, DropArea area)
{
QWidget* oldWidget = _widgets.take(area);
if (oldWidget)
2015-12-09 19:21:38 +08:00
{
_grid->removeWidget(oldWidget);
delete oldWidget;
oldWidget = NULL;
2015-12-09 19:21:38 +08:00
}
if (!widget)
return;
switch (area)
2015-12-09 19:21:38 +08:00
{
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;
2015-12-09 19:21:38 +08:00
}
_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());
2015-12-09 19:21:38 +08:00
}
ADS_NAMESPACE_END