void DragBaseBoxLayout::addWidget(QWidget* widget)
{
this->layout()->addWidget(widget);
}
void DragBaseBoxLayout::hideIndicator(Indicator i)
{
if (m_indicators[i])
m_indicators[i]->hide();
}
void DragBaseBoxLayout::showIndicator(Indicator i, const QRect &geometry, const QPalette &p)
{
if (!m_indicators[i])
m_indicators[i] = new InvisibleWidget(this);
QWidget *indicator = m_indicators[i];
indicator->setAutoFillBackground(true);
indicator->setPalette(p);
indicator->setGeometry(geometry);
indicator->show();
indicator->raise();
}
void DragBaseBoxLayout::setImageTransparency(QImage &image, int alpha)
{
const int height = image.height();
for (int l = 0; l < height; l++) {
QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(l));
QRgb *lineEnd = line + image.width();
for (; line < lineEnd; line++) {
const QRgb rgba = *line;
*line = qRgba(qRed(rgba), qGreen(rgba), qBlue(rgba), alpha);
}
}
}
int DragBaseBoxLayout::findItemAt(const QPoint &pos) const
{
if (!layout())
return -1;
const QLayout *lt = layout();
const int count = lt->count();
if (count == 0)
return -1;
int best = -1;
int bestIndex = -1;
for (int index = 0; index < count; index++) {
QLayoutItem *item = lt->itemAt(index);
bool visible = true;
if (const QWidget *w = item->widget())
visible = w->isVisible();
if (visible) {
const QRect g = item->geometry();
const int dist = (g.center() - pos).manhattanLength();
if (best == -1 || dist < best) {
best = dist;
bestIndex = index;
}
}
}
return bestIndex;
}
bool DragBaseBoxLayout::eventFilter(QObject *watched, QEvent *event)
{
if (watched == this){
if (event->type() == QEvent::ChildRemoved && m_isDragout){
QBoxLayout* layout = dynamic_cast<QBoxLayout*>(this->layout());
layout->insertWidget(m_srcIndex, m_widget);
m_widget->show();
}
}
return QWidget::eventFilter(watched, event);
}
void DragBaseBoxLayout::mousePressEvent(QMouseEvent *event)
{
QWidget *child = static_cast<QWidget*>(childAt(event->pos()));
m_srcIndex = layout()->indexOf(child);
if (!child || m_srcIndex == -1)
return;
m_widget = child;
child->hide();
layout()->removeWidget(child);
QMimeData *mimeData = new QMimeData;
mimeData->setData(m_dargItemstr, "");
QDrag *drag = new QDrag(this);
QImage& image = child->grab().toImage();
setImageTransparency(image, 120);
drag->setMimeData(mimeData);
drag->setPixmap(QPixmap::fromImage(image));
drag->setHotSpot(event->pos() - child->pos());
drag->exec(Qt::MoveAction);
}
QRect DragHBoxLayout::extendedGeometry(int index) const
{
QLayoutItem *item = layout()->itemAt(index);
QRect g = item->geometry();
const QBoxLayout *box = static_cast<const QBoxLayout*>(layout());
if (index == 0){
QPoint topLeft = g.topLeft();
topLeft.rx() = layout()->geometry().left();
g.setTopLeft(topLeft);
return g;
}
if (index < box->count() - 1)
return g;
QPoint bottomRight = g.bottomRight();
bottomRight.rx() = layout()->geometry().right();
g.setBottomRight(bottomRight);
return g;
}
void DragHBoxLayout::adjustIndicator(const QPoint &pos, int index)
{
if (index == -1) {
hideIndicator(LeftIndicator);
hideIndicator(TopIndicator);
hideIndicator(RightIndicator);
hideIndicator(BottomIndicator);
return;
}
m_currentIndex = index;
QLayoutItem *item = layout()->itemAt(index);
const QRect g = extendedGeometry(index);
QPalette bluePalette;
bluePalette.setColor(QPalette::Window, Qt::blue);
hideIndicator(LeftIndicator);
hideIndicator(TopIndicator);
const int fromRight = g.right() - pos.x();
const int fromLeft = pos.x() - g.x();
const int fromLeftRight = qMin(fromRight, fromLeft);
hideIndicator(BottomIndicator);
const bool closeToLeft = fromLeftRight == fromLeft;
m_currentIndex = closeToLeft ? m_currentIndex : m_currentIndex + 1;
showIndicator(RightIndicator, QRect(closeToLeft ? g.x() : g.right() + 1 - indicatorSize, g.y(), indicatorSize, g.height()), bluePalette);
}
void DragHBoxLayout::highlightWidget(QWidget *widget, const QPoint &pos)
{
const int index = findItemAt(pos);
adjustIndicator(pos, index);
}
void DragHBoxLayout::dragEnterEvent(QDragEnterEvent * event)
{
if (event->mimeData()->hasFormat(m_dargItemstr)) {
m_isDragout = false;
highlightWidget(m_widget, event->pos());
event->setDropAction(Qt::MoveAction);
event->accept();
}
else {
event->ignore();
}
}
void DragHBoxLayout::dragMoveEvent(QDragMoveEvent * event)
{
if (event->mimeData()->hasFormat(m_dargItemstr)) {
m_isDragout = false;
highlightWidget(m_widget, event->pos());
event->setDropAction(Qt::MoveAction);
event->accept();
}
else {
event->ignore();
}
}
void DragHBoxLayout::dragLeaveEvent(QDragLeaveEvent*/* event*/)
{
m_isDragout = true;
adjustIndicator(QPoint(), -1);
}
void DragHBoxLayout::dropEvent(QDropEvent * event)
{
if (event->mimeData()->hasFormat(m_dargItemstr)) {
hideIndicator(RightIndicator);
QBoxLayout* layout = dynamic_cast<QBoxLayout*>(this->layout());
m_widget->show();
layout->insertWidget(m_currentIndex, m_widget);
event->setDropAction(Qt::MoveAction);
event->accept();
}
else {
event->ignore();
}
}
QRect DragVBoxLayout::extendedGeometry(int index) const
{
QLayoutItem *item = layout()->itemAt(index);
QRect g = item->geometry();
const QBoxLayout *box = static_cast<const QBoxLayout*>(layout());
if (index == 0){
QPoint topLeft = g.topLeft();
topLeft.ry() = layout()->geometry().top();
g.setTopLeft(topLeft);
return g;
}
if (index < box->count() - 1)
return g;
QPoint bottomRight = g.bottomRight();
bottomRight.ry() = layout()->geometry().bottom();
g.setBottomRight(bottomRight);
return g;
}
void DragVBoxLayout::adjustIndicator(const QPoint &pos, int index)
{
if (index == -1) {
hideIndicator(LeftIndicator);
hideIndicator(TopIndicator);
hideIndicator(RightIndicator);
hideIndicator(BottomIndicator);
return;
}
m_currentIndex = index;
QLayoutItem *item = layout()->itemAt(index);
const QRect g = extendedGeometry(index);
QPalette bluePalette;
bluePalette.setColor(QPalette::Window, Qt::blue);
hideIndicator(LeftIndicator);
hideIndicator(TopIndicator);
const int fromBottom = g.bottom() - pos.y();
const int fromTop = pos.y() - g.y();
const int fromBottomTop = qMin(fromBottom, fromTop);
hideIndicator(RightIndicator);
const bool closeToTop = fromBottomTop == fromTop;
m_currentIndex = closeToTop ? m_currentIndex : m_currentIndex + 1;
showIndicator(BottomIndicator, QRect(g.x(), closeToTop ? g.y() : g.bottom() + 1 - indicatorSize, g.width(), indicatorSize), bluePalette);
}
void DragVBoxLayout::highlightWidget(QWidget *widget, const QPoint &pos)
{
const int index = findItemAt(pos);
adjustIndicator(pos, index);
}
void DragVBoxLayout::dragEnterEvent(QDragEnterEvent * event)
{
if (event->mimeData()->hasFormat(m_dargItemstr)) {
m_isDragout = false;
highlightWidget(m_widget, event->pos());
event->setDropAction(Qt::MoveAction);
event->accept();
}
else {
event->ignore();
}
}
void DragVBoxLayout::dragMoveEvent(QDragMoveEvent * event)
{
if (event->mimeData()->hasFormat(m_dargItemstr)) {
m_isDragout = false;
highlightWidget(m_widget, event->pos());
event->setDropAction(Qt::MoveAction);
event->accept();
}
else {
event->ignore();
}
}
void DragVBoxLayout::dragLeaveEvent(QDragLeaveEvent*/* event*/)
{
m_isDragout = true;
adjustIndicator(QPoint(), -1);
}
void DragVBoxLayout::dropEvent(QDropEvent * event)
{
if (event->mimeData()->hasFormat(m_dargItemstr)) {
hideIndicator(BottomIndicator);
QBoxLayout* layout = dynamic_cast<QBoxLayout*>(this->layout());
m_widget->show();
layout->insertWidget(m_currentIndex, m_widget);
event->setDropAction(Qt::MoveAction);
event->accept();
}
else {
event->ignore();
}
}