00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00107
00108
00109
00110
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);
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
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