src/gui/widgets/qwidgetresizehandler.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the QtGui module of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 #include "qwidgetresizehandler_p.h"
00025 
00026 #ifndef QT_NO_RESIZEHANDLER
00027 #include "qframe.h"
00028 #include "qapplication.h"
00029 #include "qdesktopwidget.h"
00030 #include "qcursor.h"
00031 #include "qsizegrip.h"
00032 #include "qevent.h"
00033 #if defined(Q_WS_WIN)
00034 #include "qt_windows.h"
00035 #endif
00036 #include "qdebug.h"
00037 #include "private/qlayoutengine_p.h"
00038 
00039 #define RANGE 4
00040 
00041 static bool resizeHorizontalDirectionFixed = false;
00042 static bool resizeVerticalDirectionFixed = false;
00043 
00044 QWidgetResizeHandler::QWidgetResizeHandler(QWidget *parent, QWidget *cw)
00045     : QObject(parent), widget(parent), childWidget(cw ? cw : parent),
00046       fw(0), extrahei(0), buttonDown(false), moveResizeMode(false), sizeprotect(true), movingEnabled(true)
00047 {
00048     mode = Nowhere;
00049     widget->setMouseTracking(true);
00050     QFrame *frame = qobject_cast<QFrame*>(widget);
00051     range = frame ? frame->frameWidth() : RANGE;
00052     range = qMax(RANGE, range);
00053     activeForMove = activeForResize = true;
00054     widget->installEventFilter(this);
00055 }
00056 
00057 void QWidgetResizeHandler::setActive(Action ac, bool b)
00058 {
00059     if (ac & Move)
00060         activeForMove = b;
00061     if (ac & Resize)
00062         activeForResize = b;
00063 
00064     if (!isActive())
00065         setMouseCursor(Nowhere);
00066 }
00067 
00068 bool QWidgetResizeHandler::isActive(Action ac) const
00069 {
00070     bool b = false;
00071     if (ac & Move) b = activeForMove;
00072     if (ac & Resize) b |= activeForResize;
00073 
00074     return b;
00075 }
00076 
00077 bool QWidgetResizeHandler::eventFilter(QObject *o, QEvent *ee)
00078 {
00079     if (!isActive()
00080         || (ee->type() != QEvent::MouseButtonPress
00081             && ee->type() != QEvent::MouseButtonRelease
00082             && ee->type() != QEvent::MouseMove
00083             && ee->type() != QEvent::KeyPress
00084             && ee->type() != QEvent::ShortcutOverride)
00085         )
00086         return false;
00087 
00088     Q_ASSERT(o == widget);
00089     QWidget *w = widget;
00090     if (QApplication::activePopupWidget()) {
00091         if (buttonDown && ee->type() == QEvent::MouseButtonRelease)
00092             buttonDown = false;
00093         return false;
00094     }
00095 
00096     QMouseEvent *e = (QMouseEvent*)ee;
00097     switch (e->type()) {
00098     case QEvent::MouseButtonPress: {
00099         if (w->isMaximized())
00100             break;
00101         if (!widget->rect().contains(widget->mapFromGlobal(e->globalPos())))
00102             return false;
00103         if (e->button() == Qt::LeftButton) {
00104 #if defined(Q_WS_X11)
00105             /*
00106                Implicit grabs do not stop the X server from changing
00107                the cursor in children, which looks *really* bad when
00108                doing resizingk, so we grab the cursor. Note that we do
00109                not do this on Windows since double clicks are lost due
00110                to the grab (see change 198463).
00111             */
00112             if (e->spontaneous())
00113 #  if !defined(QT_NO_CURSOR)
00114                 widget->grabMouse(widget->cursor());
00115 #  else
00116                 widget->grabMouse();
00117 #  endif // QT_NO_CURSOR
00118 #endif // Q_WS_X11
00119             buttonDown = false;
00120             emit activate();
00121             bool me = movingEnabled;
00122             movingEnabled = (me && o == widget);
00123             mouseMoveEvent(e);
00124             movingEnabled = me;
00125             buttonDown = true;
00126             moveOffset = widget->mapFromGlobal(e->globalPos());
00127             invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
00128             if (mode == Center) {
00129                 if (movingEnabled)
00130                     return true;
00131             } else {
00132                 return true;
00133             }
00134         }
00135     } break;
00136     case QEvent::MouseButtonRelease:
00137         if (w->isMaximized())
00138             break;
00139         if (e->button() == Qt::LeftButton) {
00140             moveResizeMode = false;
00141             buttonDown = false;
00142             widget->releaseMouse();
00143             widget->releaseKeyboard();
00144             if (mode == Center) {
00145                 if (movingEnabled)
00146                     return true;
00147             } else {
00148                 return true;
00149             }
00150         }
00151         break;
00152     case QEvent::MouseMove: {
00153         if (w->isMaximized())
00154             break;
00155         buttonDown = buttonDown && (e->buttons() & Qt::LeftButton); // safety, state machine broken!
00156         bool me = movingEnabled;
00157         movingEnabled = (me && o == widget && (buttonDown || moveResizeMode));
00158         mouseMoveEvent(e);
00159         movingEnabled = me;
00160         if (mode == Center) {
00161             if (movingEnabled)
00162                 return true;
00163         } else {
00164             return true;
00165         }
00166     } break;
00167     case QEvent::KeyPress:
00168         keyPressEvent((QKeyEvent*)e);
00169         break;
00170     case QEvent::ShortcutOverride:
00171         if (buttonDown) {
00172             ((QKeyEvent*)ee)->accept();
00173             return true;
00174         }
00175         break;
00176     default:
00177         break;
00178     }
00179 
00180     return false;
00181 }
00182 
00183 void QWidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
00184 {
00185     QPoint pos = widget->mapFromGlobal(e->globalPos());
00186     if (!moveResizeMode && !buttonDown) {
00187         if (pos.y() <= range && pos.x() <= range)
00188             mode = TopLeft;
00189         else if (pos.y() >= widget->height()-range && pos.x() >= widget->width()-range)
00190             mode = BottomRight;
00191         else if (pos.y() >= widget->height()-range && pos.x() <= range)
00192             mode = BottomLeft;
00193         else if (pos.y() <= range && pos.x() >= widget->width()-range)
00194             mode = TopRight;
00195         else if (pos.y() <= range)
00196             mode = Top;
00197         else if (pos.y() >= widget->height()-range)
00198             mode = Bottom;
00199         else if (pos.x() <= range)
00200             mode = Left;
00201         else if ( pos.x() >= widget->width()-range)
00202             mode = Right;
00203         else if (widget->rect().contains(pos))
00204             mode = Center;
00205         else
00206             mode = Nowhere;
00207 
00208         if (widget->isMinimized() || !isActive(Resize))
00209             mode = Center;
00210 #ifndef QT_NO_CURSOR
00211         setMouseCursor(mode);
00212 #endif
00213         return;
00214     }
00215 
00216     if (mode == Center && !movingEnabled)
00217         return;
00218 
00219     if (widget->testAttribute(Qt::WA_WState_ConfigPending))
00220         return;
00221 
00222 
00223     QPoint globalPos = (!widget->isWindow() && widget->parentWidget()) ?
00224                        widget->parentWidget()->mapFromGlobal(e->globalPos()) : e->globalPos();
00225     if (!widget->isWindow() && !widget->parentWidget()->rect().contains(globalPos)) {
00226         if (globalPos.x() < 0)
00227             globalPos.rx() = 0;
00228         if (globalPos.y() < 0)
00229             globalPos.ry() = 0;
00230         if (sizeprotect && globalPos.x() > widget->parentWidget()->width())
00231             globalPos.rx() = widget->parentWidget()->width();
00232         if (sizeprotect && globalPos.y() > widget->parentWidget()->height())
00233             globalPos.ry() = widget->parentWidget()->height();
00234     }
00235 
00236     QPoint p = globalPos + invertedMoveOffset;
00237     QPoint pp = globalPos - moveOffset;
00238 
00239 #ifdef Q_WS_X11
00240     // Workaround for window managers which refuse to move a tool window partially offscreen.
00241     QRect desktop = qApp->desktop()->availableGeometry(widget);
00242     pp.rx() = qMax(pp.x(), desktop.left());
00243     pp.ry() = qMax(pp.y(), desktop.top());
00244     p.rx() = qMin(p.x(), desktop.right());
00245     p.ry() = qMin(p.y(), desktop.bottom());
00246 #endif
00247 
00248     QSize ms = qSmartMinSize(childWidget);
00249     int mw = ms.width();
00250     int mh = ms.height();
00251     if (childWidget != widget) {
00252         mw += 2 * fw;
00253         mh += 2 * fw + extrahei;
00254     }
00255 
00256     QSize maxsize(childWidget->maximumSize());
00257     if (childWidget != widget)
00258         maxsize += QSize(2 * fw, 2 * fw + extrahei);
00259     QSize mpsize(widget->geometry().right() - pp.x() + 1,
00260                   widget->geometry().bottom() - pp.y() + 1);
00261     mpsize = mpsize.expandedTo(widget->minimumSize()).expandedTo(QSize(mw, mh))
00262                     .boundedTo(maxsize);
00263     QPoint mp(widget->geometry().right() - mpsize.width() + 1,
00264                widget->geometry().bottom() - mpsize.height() + 1);
00265 
00266     QRect geom = widget->geometry();
00267 
00268     switch (mode) {
00269     case TopLeft:
00270         geom = QRect(mp, widget->geometry().bottomRight()) ;
00271         break;
00272     case BottomRight:
00273         geom = QRect(widget->geometry().topLeft(), p) ;
00274         break;
00275     case BottomLeft:
00276         geom = QRect(QPoint(mp.x(), widget->geometry().y()), QPoint(widget->geometry().right(), p.y())) ;
00277         break;
00278     case TopRight:
00279         geom = QRect(QPoint(widget->geometry().x(), mp.y()), QPoint(p.x(), widget->geometry().bottom())) ;
00280         break;
00281     case Top:
00282         geom = QRect(QPoint(widget->geometry().left(), mp.y()), widget->geometry().bottomRight()) ;
00283         break;
00284     case Bottom:
00285         geom = QRect(widget->geometry().topLeft(), QPoint(widget->geometry().right(), p.y())) ;
00286         break;
00287     case Left:
00288         geom = QRect(QPoint(mp.x(), widget->geometry().top()), widget->geometry().bottomRight()) ;
00289         break;
00290     case Right:
00291         geom = QRect(widget->geometry().topLeft(), QPoint(p.x(), widget->geometry().bottom())) ;
00292         break;
00293     case Center:
00294         geom.moveTopLeft(pp);
00295         break;
00296     default:
00297         break;
00298     }
00299 
00300     geom = QRect(geom.topLeft(),
00301                   geom.size().expandedTo(widget->minimumSize())
00302                              .expandedTo(QSize(mw, mh))
00303                              .boundedTo(maxsize));
00304 
00305     if (geom != widget->geometry() &&
00306         (widget->isWindow() || widget->parentWidget()->rect().intersects(geom))) {
00307         if (mode == Center)
00308             widget->move(geom.topLeft());
00309         else
00310             widget->setGeometry(geom);
00311     }
00312 
00313     QApplication::syncX();
00314 }
00315 
00316 void QWidgetResizeHandler::setMouseCursor(MousePosition m)
00317 {
00318 #ifdef QT_NO_CURSOR
00319     Q_UNUSED(m);
00320 #else
00321     QObjectList children = widget->children();
00322     for (int i = 0; i < children.size(); ++i) {
00323         if (QWidget *w = qobject_cast<QWidget*>(children.at(i))) {
00324             if (!w->testAttribute(Qt::WA_SetCursor) && !w->inherits("QWorkspaceTitleBar")) {
00325                 w->setCursor(Qt::ArrowCursor);
00326             }
00327         }
00328     }
00329 
00330     switch (m) {
00331     case TopLeft:
00332     case BottomRight:
00333         widget->setCursor(Qt::SizeFDiagCursor);
00334         break;
00335     case BottomLeft:
00336     case TopRight:
00337         widget->setCursor(Qt::SizeBDiagCursor);
00338         break;
00339     case Top:
00340     case Bottom:
00341         widget->setCursor(Qt::SizeVerCursor);
00342         break;
00343     case Left:
00344     case Right:
00345         widget->setCursor(Qt::SizeHorCursor);
00346         break;
00347     default:
00348         widget->setCursor(Qt::ArrowCursor);
00349         break;
00350     }
00351 #endif // QT_NO_CURSOR
00352 }
00353 
00354 void QWidgetResizeHandler::keyPressEvent(QKeyEvent * e)
00355 {
00356     if (!isMove() && !isResize())
00357         return;
00358     bool is_control = e->modifiers() & Qt::ControlModifier;
00359     int delta = is_control?1:8;
00360     QPoint pos = QCursor::pos();
00361     switch (e->key()) {
00362     case Qt::Key_Left:
00363         pos.rx() -= delta;
00364         if (pos.x() <= QApplication::desktop()->geometry().left()) {
00365             if (mode == TopLeft || mode == BottomLeft) {
00366                 moveOffset.rx() += delta;
00367                 invertedMoveOffset.rx() += delta;
00368             } else {
00369                 moveOffset.rx() -= delta;
00370                 invertedMoveOffset.rx() -= delta;
00371             }
00372         }
00373         if (isResize() && !resizeHorizontalDirectionFixed) {
00374             resizeHorizontalDirectionFixed = true;
00375             if (mode == BottomRight)
00376                 mode = BottomLeft;
00377             else if (mode == TopRight)
00378                 mode = TopLeft;
00379 #ifndef QT_NO_CURSOR
00380             setMouseCursor(mode);
00381             widget->grabMouse(widget->cursor());
00382 #else
00383             widget->grabMouse();
00384 #endif
00385         }
00386         break;
00387     case Qt::Key_Right:
00388         pos.rx() += delta;
00389         if (pos.x() >= QApplication::desktop()->geometry().right()) {
00390             if (mode == TopRight || mode == BottomRight) {
00391                 moveOffset.rx() += delta;
00392                 invertedMoveOffset.rx() += delta;
00393             } else {
00394                 moveOffset.rx() -= delta;
00395                 invertedMoveOffset.rx() -= delta;
00396             }
00397         }
00398         if (isResize() && !resizeHorizontalDirectionFixed) {
00399             resizeHorizontalDirectionFixed = true;
00400             if (mode == BottomLeft)
00401                 mode = BottomRight;
00402             else if (mode == TopLeft)
00403                 mode = TopRight;
00404 #ifndef QT_NO_CURSOR
00405             setMouseCursor(mode);
00406             widget->grabMouse(widget->cursor());
00407 #else
00408             widget->grabMouse();
00409 #endif
00410         }
00411         break;
00412     case Qt::Key_Up:
00413         pos.ry() -= delta;
00414         if (pos.y() <= QApplication::desktop()->geometry().top()) {
00415             if (mode == TopLeft || mode == TopRight) {
00416                 moveOffset.ry() += delta;
00417                 invertedMoveOffset.ry() += delta;
00418             } else {
00419                 moveOffset.ry() -= delta;
00420                 invertedMoveOffset.ry() -= delta;
00421             }
00422         }
00423         if (isResize() && !resizeVerticalDirectionFixed) {
00424             resizeVerticalDirectionFixed = true;
00425             if (mode == BottomLeft)
00426                 mode = TopLeft;
00427             else if (mode == BottomRight)
00428                 mode = TopRight;
00429 #ifndef QT_NO_CURSOR
00430             setMouseCursor(mode);
00431             widget->grabMouse(widget->cursor());
00432 #else
00433             widget->grabMouse();
00434 #endif
00435         }
00436         break;
00437     case Qt::Key_Down:
00438         pos.ry() += delta;
00439         if (pos.y() >= QApplication::desktop()->geometry().bottom()) {
00440             if (mode == BottomLeft || mode == BottomRight) {
00441                 moveOffset.ry() += delta;
00442                 invertedMoveOffset.ry() += delta;
00443             } else {
00444                 moveOffset.ry() -= delta;
00445                 invertedMoveOffset.ry() -= delta;
00446             }
00447         }
00448         if (isResize() && !resizeVerticalDirectionFixed) {
00449             resizeVerticalDirectionFixed = true;
00450             if (mode == TopLeft)
00451                 mode = BottomLeft;
00452             else if (mode == TopRight)
00453                 mode = BottomRight;
00454 #ifndef QT_NO_CURSOR
00455             setMouseCursor(mode);
00456             widget->grabMouse(widget->cursor());
00457 #else
00458             widget->grabMouse();
00459 #endif
00460         }
00461         break;
00462     case Qt::Key_Space:
00463     case Qt::Key_Return:
00464     case Qt::Key_Enter:
00465     case Qt::Key_Escape:
00466         moveResizeMode = false;
00467         widget->releaseMouse();
00468         widget->releaseKeyboard();
00469         buttonDown = false;
00470         break;
00471     default:
00472         return;
00473     }
00474     QCursor::setPos(pos);
00475 }
00476 
00477 
00478 void QWidgetResizeHandler::doResize()
00479 {
00480     if (!activeForResize)
00481         return;
00482 
00483     moveResizeMode = true;
00484     moveOffset = widget->mapFromGlobal(QCursor::pos());
00485     if (moveOffset.x() < widget->width()/2) {
00486         if (moveOffset.y() < widget->height()/2)
00487             mode = TopLeft;
00488         else
00489             mode = BottomLeft;
00490     } else {
00491         if (moveOffset.y() < widget->height()/2)
00492             mode = TopRight;
00493         else
00494             mode = BottomRight;
00495     }
00496     invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
00497 #ifndef QT_NO_CURSOR
00498     setMouseCursor(mode);
00499     widget->grabMouse(widget->cursor() );
00500 #else
00501     widget->grabMouse();
00502 #endif
00503     widget->grabKeyboard();
00504     resizeHorizontalDirectionFixed = false;
00505     resizeVerticalDirectionFixed = false;
00506 }
00507 
00508 void QWidgetResizeHandler::doMove()
00509 {
00510     if (!activeForMove)
00511         return;
00512 
00513     mode = Center;
00514     moveResizeMode = true;
00515     moveOffset = widget->mapFromGlobal(QCursor::pos());
00516     invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
00517 #ifndef QT_NO_CURSOR
00518     widget->grabMouse(Qt::SizeAllCursor);
00519 #else
00520     widget->grabMouse();
00521 #endif
00522     widget->grabKeyboard();
00523 }
00524 
00525 #endif //QT_NO_RESIZEHANDLER

Generated on Thu Mar 15 11:57:10 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1