123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655 |
- #include "WidgetResizeHandler.h"
- #include <QFrame>
- #include <QApplication>
- #include <QDesktopWidget>
- #include <QCursor>
- #if QT_CONFIG(sizegrip)
- #include <QSizeGrip>
- #endif
- #include <QEvent>
- #include <QDebug>
- #include "../titlebar/TitleBar.h"
- #define RANGE 8
- static bool resizeHorizontalDirectionFixed = false;
- static bool resizeVerticalDirectionFixed = false;
- WidgetResizeHandler::WidgetResizeHandler(QWidget *parent, QWidget *cw)
- : QObject(parent), m_widget(parent), m_childWidget(cw ? cw : parent),
- m_fw(0), m_extrahei(0), m_buttonDown(false),
- m_moveResizeMode(false), m_sizeprotect(true), m_movingEnabled(true)
- {
- m_mode = Nowhere;
- m_widget->installEventFilter(this);
- m_widget->setMouseTracking(true);
- QFrame *frame = qobject_cast<QFrame*>(m_widget);
- m_range = frame ? frame->frameWidth() : RANGE;
- m_range = qMax(RANGE, m_range);
- m_activeForMove = m_activeForResize = true;
- m_widget->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
- m_titleBar = new TitleBar(m_widget);
- m_widget->resize(500, 500);
- m_titleBar->raise();
- setTitleBarHeight(m_titleBar->height());
- }
- void WidgetResizeHandler::setTitleBar(TitleBar * tBar)
- {
- if (tBar != m_titleBar) {
- m_titleBar->deleteLater();
- m_titleBar = tBar;
- m_titleBar->setParent(m_widget);
- m_titleBar->raise();
- setTitleBarHeight(m_titleBar->height());
- }
- }
- TitleBar * WidgetResizeHandler::getTitleBar() const
- {
- return m_titleBar;
- }
- void WidgetResizeHandler::setResizeEnabled(bool isEnabled)
- {
- setActive(Resize, isEnabled);
- }
- bool WidgetResizeHandler::getResizeEnabled() const
- {
- return m_activeForResize;
- }
- void WidgetResizeHandler::setActive(Action ac, bool b)
- {
- if (ac & Move)
- m_activeForMove = b;
- if (ac & Resize)
- m_activeForResize = b;
- if (!isActive())
- setMouseCursor(Nowhere);
- }
- bool WidgetResizeHandler::isActive(Action ac) const
- {
- bool b = false;
- if (ac & Move) b = m_activeForMove;
- if (ac & Resize) b |= m_activeForResize;
- return b;
- }
- bool WidgetResizeHandler::eventFilter(QObject *o, QEvent *ee)
- {
- if (o == m_widget)
- {
- qDebug() << ee;
- }
- if (!isActive()
- || (ee->type() != QEvent::MouseButtonPress
- && ee->type() != QEvent::MouseButtonRelease
- && ee->type() != QEvent::MouseMove
- && ee->type() != QEvent::KeyPress
- && ee->type() != QEvent::ShortcutOverride
- && ee->type() != QEvent::MouseButtonDblClick
- && ee->type() != QEvent::Resize)
- )
- return false;
- Q_ASSERT(o == m_widget);
- QWidget *w = m_widget;
- if (QApplication::activePopupWidget())
- {
- if (m_buttonDown && ee->type() == QEvent::MouseButtonRelease)
- m_buttonDown = false;
- return false;
- }
- switch (ee->type())
- {
- case QEvent::MouseButtonPress:
- {
- QMouseEvent *e = static_cast<QMouseEvent *>(ee);
- if (w->isMaximized())
- break;
- const QRect widgetRect = m_widget->rect().marginsAdded(QMargins(m_range, m_range, m_range, m_range));
- const QPoint cursorPoint = m_widget->mapFromGlobal(e->globalPos());
- if (!widgetRect.contains(cursorPoint) || m_mode == Nowhere)
- return false;
- if (e->button() == Qt::LeftButton)
- {
- #if 0 // Used to be included in Qt4 for Q_WS_X11
- /*
- Implicit grabs do not stop the X server from changing
- the cursor in children, which looks *really* bad when
- doing resizingk, so we grab the cursor. Note that we do
- not do this on Windows since double clicks are lost due
- to the grab (see change 198463).
- */
- if (e->spontaneous())
- # if !defined(QT_NO_CURSOR)
- widget->grabMouse(widget->cursor());
- # else
- widget->grabMouse();
- # endif // QT_NO_CURSOR
- #endif
- m_buttonDown = false;
- emit activate();
- bool me = m_movingEnabled;
- m_movingEnabled = (me && o == m_widget);
- mouseMoveEvent(e);
- m_movingEnabled = me;
- m_buttonDown = true;
- m_moveOffset = m_widget->mapFromGlobal(e->globalPos());
- m_invertedMoveOffset = m_widget->rect().bottomRight() - m_moveOffset;
- if (m_mode == Center)
- {
- if (m_movingEnabled)
- return true;
- }
- else
- {
- return true;
- }
- }
- }
- break;
- case QEvent::MouseButtonRelease:
- if (w->isMaximized())
- break;
- if (w->pos().ry() <= 0)
- {
- w->move(QPoint(w->pos().rx(), 0));
- }
- if (static_cast<QMouseEvent *>(ee)->button() == Qt::LeftButton)
- {
- m_moveResizeMode = false;
- m_buttonDown = false;
- m_widget->releaseMouse();
- m_widget->releaseKeyboard();
- if (m_mode == Center)
- {
- if (m_movingEnabled)
- return true;
- }
- else
- {
- return true;
- }
- }
- break;
- case QEvent::MouseMove:
- {
- if (w->isMaximized())
- {
- break;
- }
- QMouseEvent *e = static_cast<QMouseEvent *>(ee);
- m_buttonDown = m_buttonDown && (e->buttons() & Qt::LeftButton); // safety, state machine broken!
- bool me = m_movingEnabled;
- m_movingEnabled = (me && o == m_widget && (m_buttonDown || m_moveResizeMode));
- mouseMoveEvent(e);
- m_movingEnabled = me;
- if (m_mode == Center)
- {
- if (m_movingEnabled)
- return true;
- }
- else
- {
- return true;
- }
- }
- break;
- case QEvent::KeyPress:
- keyPressEvent(static_cast<QKeyEvent *>(ee));
- break;
- case QEvent::ShortcutOverride:
- if (m_buttonDown)
- {
- ee->accept();
- return true;
- }
- break;
- case QEvent::MouseButtonDblClick:
- {
- QMouseEvent *e = static_cast<QMouseEvent *>(ee);
- if (e && e->pos().y() <= m_titleBarHeight)
- {
- if (w->isMaximized())
- {
- w->showNormal();
- }
- else
- {
- w->showMaximized();
- }
- }
- break;
- }
- case QEvent::Resize:
- {
- m_titleBar->resize(m_widget->width(), m_titleBar->height());
- }
- default:
- break;
- }
- return false;
- }
- void WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
- {
- QPoint pos = m_widget->mapFromGlobal(e->globalPos());
- if (!m_moveResizeMode && !m_buttonDown)
- {
- if (pos.y() <= m_range && pos.x() <= m_range)
- m_mode = TopLeft;
- else if (pos.y() >= m_widget->height() - m_range && pos.x() >= m_widget->width() - m_range)
- m_mode = BottomRight;
- else if (pos.y() >= m_widget->height() - m_range && pos.x() <= m_range)
- m_mode = BottomLeft;
- else if (pos.y() <= m_range && pos.x() >= m_widget->width() - m_range)
- m_mode = TopRight;
- else if (pos.y() <= m_range)
- m_mode = Top;
- else if (pos.y() >= m_widget->height() - m_range)
- m_mode = Bottom;
- else if (pos.x() <= m_range)
- m_mode = Left;
- else if (pos.x() >= m_widget->width() - m_range)
- m_mode = Right;
- else if (m_widget->rect().contains(pos))
- m_mode = Center;
- else
- m_mode = Nowhere;
- if (m_widget->isMinimized() || !isActive(Resize))
- m_mode = Center;
- #ifndef QT_NO_CURSOR
- setMouseCursor(m_mode);
- #endif
- return;
- }
- if (m_mode == Center && !m_movingEnabled)
- return;
- if (m_widget->testAttribute(Qt::WA_WState_ConfigPending))
- return;
- QPoint globalPos = (!m_widget->isWindow() && m_widget->parentWidget()) ?
- m_widget->parentWidget()->mapFromGlobal(e->globalPos()) : e->globalPos();
- if (!m_widget->isWindow() && !m_widget->parentWidget()->rect().contains(globalPos))
- {
- if (globalPos.x() < 0)
- globalPos.rx() = 0;
- if (globalPos.y() < 0)
- globalPos.ry() = 0;
- if (m_sizeprotect && globalPos.x() > m_widget->parentWidget()->width())
- globalPos.rx() = m_widget->parentWidget()->width();
- if (m_sizeprotect && globalPos.y() > m_widget->parentWidget()->height())
- globalPos.ry() = m_widget->parentWidget()->height();
- }
- QPoint p = globalPos + m_invertedMoveOffset;
- QPoint pp = globalPos - m_moveOffset;
- // Workaround for window managers which refuse to move a tool window partially offscreen.
- if (QGuiApplication::platformName() == QLatin1String("xcb"))
- {
- const QRect desktop = qApp->desktop()->availableGeometry(m_widget);
- pp.rx() = qMax(pp.x(), desktop.left());
- pp.ry() = qMax(pp.y(), desktop.top());
- p.rx() = qMin(p.x(), desktop.right());
- p.ry() = qMin(p.y(), desktop.bottom());
- }
- QSize ms = qSmartMinSize(m_childWidget->sizeHint(), m_childWidget->minimumSizeHint(),
- m_childWidget->minimumSize(), m_childWidget->maximumSize(),
- m_childWidget->sizePolicy());
- int mw = ms.width();
- int mh = ms.height();
- if (m_childWidget != m_widget)
- {
- mw += 2 * m_fw;
- mh += 2 * m_fw + m_extrahei;
- }
- QSize maxsize(m_childWidget->maximumSize());
- if (m_childWidget != m_widget)
- maxsize += QSize(2 * m_fw, 2 * m_fw + m_extrahei);
- QSize mpsize(m_widget->geometry().right() - pp.x() + 1,
- m_widget->geometry().bottom() - pp.y() + 1);
- mpsize = mpsize.expandedTo(m_widget->minimumSize()).expandedTo(QSize(mw, mh))
- .boundedTo(maxsize);
- QPoint mp(m_widget->geometry().right() - mpsize.width() + 1,
- m_widget->geometry().bottom() - mpsize.height() + 1);
- QRect geom = m_widget->geometry();
- switch (m_mode)
- {
- case TopLeft:
- geom = QRect(mp, m_widget->geometry().bottomRight());
- break;
- case BottomRight:
- geom = QRect(m_widget->geometry().topLeft(), p);
- break;
- case BottomLeft:
- geom = QRect(QPoint(mp.x(), m_widget->geometry().y()), QPoint(m_widget->geometry().right(), p.y()));
- break;
- case TopRight:
- geom = QRect(QPoint(m_widget->geometry().x(), mp.y()), QPoint(p.x(), m_widget->geometry().bottom()));
- break;
- case Top:
- geom = QRect(QPoint(m_widget->geometry().left(), mp.y()), m_widget->geometry().bottomRight());
- break;
- case Bottom:
- geom = QRect(m_widget->geometry().topLeft(), QPoint(m_widget->geometry().right(), p.y()));
- break;
- case Left:
- geom = QRect(QPoint(mp.x(), m_widget->geometry().top()), m_widget->geometry().bottomRight());
- break;
- case Right:
- geom = QRect(m_widget->geometry().topLeft(), QPoint(p.x(), m_widget->geometry().bottom()));
- break;
- case Center:
- geom.moveTopLeft(pp);
- break;
- default:
- break;
- }
- geom = QRect(geom.topLeft(),
- geom.size().expandedTo(m_widget->minimumSize())
- .expandedTo(QSize(mw, mh))
- .boundedTo(maxsize));
- if (geom != m_widget->geometry() &&
- (m_widget->isWindow() || m_widget->parentWidget()->rect().intersects(geom)))
- {
- if (m_mode == Center)
- {
- m_widget->move(geom.topLeft());
- }
- else
- m_widget->setGeometry(geom);
- }
- }
- void WidgetResizeHandler::setMouseCursor(MousePosition m)
- {
- #ifdef QT_NO_CURSOR
- Q_UNUSED(m);
- #else
- QObjectList children = m_widget->children();
- for (int i = 0; i < children.size(); ++i)
- {
- if (QWidget *w = qobject_cast<QWidget*>(children.at(i)))
- {
- if (!w->testAttribute(Qt::WA_SetCursor))
- {
- w->setCursor(Qt::ArrowCursor);
- }
- }
- }
- switch (m)
- {
- case TopLeft:
- case BottomRight:
- m_widget->setCursor(Qt::SizeFDiagCursor);
- break;
- case BottomLeft:
- case TopRight:
- m_widget->setCursor(Qt::SizeBDiagCursor);
- break;
- case Top:
- case Bottom:
- m_widget->setCursor(Qt::SizeVerCursor);
- break;
- case Left:
- case Right:
- m_widget->setCursor(Qt::SizeHorCursor);
- break;
- default:
- m_widget->setCursor(Qt::ArrowCursor);
- break;
- }
- #endif // QT_NO_CURSOR
- }
- void WidgetResizeHandler::keyPressEvent(QKeyEvent * e)
- {
- if (!isMove() && !isResize())
- return;
- bool is_control = e->modifiers() & Qt::ControlModifier;
- int delta = is_control ? 1 : 8;
- QPoint pos = QCursor::pos();
- switch (e->key())
- {
- case Qt::Key_Left:
- pos.rx() -= delta;
- if (pos.x() <= qApp->desktop()->geometry().left())
- {
- if (m_mode == TopLeft || m_mode == BottomLeft)
- {
- m_moveOffset.rx() += delta;
- m_invertedMoveOffset.rx() += delta;
- }
- else
- {
- m_moveOffset.rx() -= delta;
- m_invertedMoveOffset.rx() -= delta;
- }
- }
- if (isResize() && !resizeHorizontalDirectionFixed)
- {
- resizeHorizontalDirectionFixed = true;
- if (m_mode == BottomRight)
- m_mode = BottomLeft;
- else if (m_mode == TopRight)
- m_mode = TopLeft;
- #ifndef QT_NO_CURSOR
- setMouseCursor(m_mode);
- m_widget->grabMouse(m_widget->cursor());
- #else
- widget->grabMouse();
- #endif
- }
- break;
- case Qt::Key_Right:
- pos.rx() += delta;
- if (pos.x() >= qApp->desktop()->geometry().right())
- {
- if (m_mode == TopRight || m_mode == BottomRight)
- {
- m_moveOffset.rx() += delta;
- m_invertedMoveOffset.rx() += delta;
- }
- else
- {
- m_moveOffset.rx() -= delta;
- m_invertedMoveOffset.rx() -= delta;
- }
- }
- if (isResize() && !resizeHorizontalDirectionFixed)
- {
- resizeHorizontalDirectionFixed = true;
- if (m_mode == BottomLeft)
- m_mode = BottomRight;
- else if (m_mode == TopLeft)
- m_mode = TopRight;
- #ifndef QT_NO_CURSOR
- setMouseCursor(m_mode);
- m_widget->grabMouse(m_widget->cursor());
- #else
- widget->grabMouse();
- #endif
- }
- break;
- case Qt::Key_Up:
- pos.ry() -= delta;
- if (pos.y() <= qApp->desktop()->geometry().top())
- {
- if (m_mode == TopLeft || m_mode == TopRight)
- {
- m_moveOffset.ry() += delta;
- m_invertedMoveOffset.ry() += delta;
- }
- else
- {
- m_moveOffset.ry() -= delta;
- m_invertedMoveOffset.ry() -= delta;
- }
- }
- if (isResize() && !resizeVerticalDirectionFixed)
- {
- resizeVerticalDirectionFixed = true;
- if (m_mode == BottomLeft)
- m_mode = TopLeft;
- else if (m_mode == BottomRight)
- m_mode = TopRight;
- #ifndef QT_NO_CURSOR
- setMouseCursor(m_mode);
- m_widget->grabMouse(m_widget->cursor());
- #else
- widget->grabMouse();
- #endif
- }
- break;
- case Qt::Key_Down:
- pos.ry() += delta;
- if (pos.y() >= qApp->desktop()->geometry().bottom())
- {
- if (m_mode == BottomLeft || m_mode == BottomRight)
- {
- m_moveOffset.ry() += delta;
- m_invertedMoveOffset.ry() += delta;
- }
- else
- {
- m_moveOffset.ry() -= delta;
- m_invertedMoveOffset.ry() -= delta;
- }
- }
- if (isResize() && !resizeVerticalDirectionFixed)
- {
- resizeVerticalDirectionFixed = true;
- if (m_mode == TopLeft)
- m_mode = BottomLeft;
- else if (m_mode == TopRight)
- m_mode = BottomRight;
- #ifndef QT_NO_CURSOR
- setMouseCursor(m_mode);
- m_widget->grabMouse(m_widget->cursor());
- #else
- widget->grabMouse();
- #endif
- }
- break;
- case Qt::Key_Space:
- case Qt::Key_Return:
- case Qt::Key_Enter:
- case Qt::Key_Escape:
- m_moveResizeMode = false;
- m_widget->releaseMouse();
- m_widget->releaseKeyboard();
- m_buttonDown = false;
- break;
- default:
- return;
- }
- QCursor::setPos(pos);
- }
- QSize WidgetResizeHandler::qSmartMinSize(const QSize &sizeHint, const QSize &minSizeHint, const QSize &minSize, const QSize &maxSize, const QSizePolicy &sizePolicy)
- {
- QSize s(0, 0);
- if (sizePolicy.horizontalPolicy() != QSizePolicy::Ignored)
- {
- if (sizePolicy.horizontalPolicy() & QSizePolicy::ShrinkFlag)
- s.setWidth(minSizeHint.width());
- else
- s.setWidth(qMax(sizeHint.width(), minSizeHint.width()));
- }
- if (sizePolicy.verticalPolicy() != QSizePolicy::Ignored)
- {
- if (sizePolicy.verticalPolicy() & QSizePolicy::ShrinkFlag)
- {
- s.setHeight(minSizeHint.height());
- }
- else
- {
- s.setHeight(qMax(sizeHint.height(), minSizeHint.height()));
- }
- }
- s = s.boundedTo(maxSize);
- if (minSize.width() > 0)
- s.setWidth(minSize.width());
- if (minSize.height() > 0)
- s.setHeight(minSize.height());
- return s.expandedTo(QSize(0, 0));
- }
- void WidgetResizeHandler::doResize()
- {
- if (!m_activeForResize)
- return;
- m_moveResizeMode = true;
- m_moveOffset = m_widget->mapFromGlobal(QCursor::pos());
- if (m_moveOffset.x() < m_widget->width() / 2)
- {
- if (m_moveOffset.y() < m_widget->height() / 2)
- m_mode = TopLeft;
- else
- m_mode = BottomLeft;
- }
- else
- {
- if (m_moveOffset.y() < m_widget->height() / 2)
- m_mode = TopRight;
- else
- m_mode = BottomRight;
- }
- m_invertedMoveOffset = m_widget->rect().bottomRight() - m_moveOffset;
- #ifndef QT_NO_CURSOR
- setMouseCursor(m_mode);
- m_widget->grabMouse(m_widget->cursor());
- #else
- widget->grabMouse();
- #endif
- m_widget->grabKeyboard();
- resizeHorizontalDirectionFixed = false;
- resizeVerticalDirectionFixed = false;
- }
- void WidgetResizeHandler::doMove()
- {
- if (!m_activeForMove)
- return;
- m_mode = Center;
- m_moveResizeMode = true;
- m_moveOffset = m_widget->mapFromGlobal(QCursor::pos());
- m_invertedMoveOffset = m_widget->rect().bottomRight() - m_moveOffset;
- #ifndef QT_NO_CURSOR
- m_widget->grabMouse(Qt::SizeAllCursor);
- #else
- widget->grabMouse();
- #endif
- m_widget->grabKeyboard();
- }
|