source: trunk/src/gui/widgets/qwidgetresizehandler.cpp@ 112

Last change on this file since 112 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 17.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qwidgetresizehandler_p.h"
43
44#ifndef QT_NO_RESIZEHANDLER
45#include "qframe.h"
46#include "qapplication.h"
47#include "qdesktopwidget.h"
48#include "qcursor.h"
49#include "qsizegrip.h"
50#include "qevent.h"
51#if defined(Q_WS_WIN)
52#include "qt_windows.h"
53#endif
54#include "qdebug.h"
55#include "private/qlayoutengine_p.h"
56
57QT_BEGIN_NAMESPACE
58
59#define RANGE 4
60
61static bool resizeHorizontalDirectionFixed = false;
62static bool resizeVerticalDirectionFixed = false;
63
64QWidgetResizeHandler::QWidgetResizeHandler(QWidget *parent, QWidget *cw)
65 : QObject(parent), widget(parent), childWidget(cw ? cw : parent),
66 fw(0), extrahei(0), buttonDown(false), moveResizeMode(false), sizeprotect(true), movingEnabled(true)
67{
68 mode = Nowhere;
69 widget->setMouseTracking(true);
70 QFrame *frame = qobject_cast<QFrame*>(widget);
71 range = frame ? frame->frameWidth() : RANGE;
72 range = qMax(RANGE, range);
73 activeForMove = activeForResize = true;
74 widget->installEventFilter(this);
75}
76
77void QWidgetResizeHandler::setActive(Action ac, bool b)
78{
79 if (ac & Move)
80 activeForMove = b;
81 if (ac & Resize)
82 activeForResize = b;
83
84 if (!isActive())
85 setMouseCursor(Nowhere);
86}
87
88bool QWidgetResizeHandler::isActive(Action ac) const
89{
90 bool b = false;
91 if (ac & Move) b = activeForMove;
92 if (ac & Resize) b |= activeForResize;
93
94 return b;
95}
96
97bool QWidgetResizeHandler::eventFilter(QObject *o, QEvent *ee)
98{
99 if (!isActive()
100 || (ee->type() != QEvent::MouseButtonPress
101 && ee->type() != QEvent::MouseButtonRelease
102 && ee->type() != QEvent::MouseMove
103 && ee->type() != QEvent::KeyPress
104 && ee->type() != QEvent::ShortcutOverride)
105 )
106 return false;
107
108 Q_ASSERT(o == widget);
109 QWidget *w = widget;
110 if (QApplication::activePopupWidget()) {
111 if (buttonDown && ee->type() == QEvent::MouseButtonRelease)
112 buttonDown = false;
113 return false;
114 }
115
116 QMouseEvent *e = (QMouseEvent*)ee;
117 switch (e->type()) {
118 case QEvent::MouseButtonPress: {
119 if (w->isMaximized())
120 break;
121 if (!widget->rect().contains(widget->mapFromGlobal(e->globalPos())))
122 return false;
123 if (e->button() == Qt::LeftButton) {
124#if defined(Q_WS_X11)
125 /*
126 Implicit grabs do not stop the X server from changing
127 the cursor in children, which looks *really* bad when
128 doing resizingk, so we grab the cursor. Note that we do
129 not do this on Windows since double clicks are lost due
130 to the grab (see change 198463).
131 */
132 if (e->spontaneous())
133# if !defined(QT_NO_CURSOR)
134 widget->grabMouse(widget->cursor());
135# else
136 widget->grabMouse();
137# endif // QT_NO_CURSOR
138#endif // Q_WS_X11
139 buttonDown = false;
140 emit activate();
141 bool me = movingEnabled;
142 movingEnabled = (me && o == widget);
143 mouseMoveEvent(e);
144 movingEnabled = me;
145 buttonDown = true;
146 moveOffset = widget->mapFromGlobal(e->globalPos());
147 invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
148 if (mode == Center) {
149 if (movingEnabled)
150 return true;
151 } else {
152 return true;
153 }
154 }
155 } break;
156 case QEvent::MouseButtonRelease:
157 if (w->isMaximized())
158 break;
159 if (e->button() == Qt::LeftButton) {
160 moveResizeMode = false;
161 buttonDown = false;
162 widget->releaseMouse();
163 widget->releaseKeyboard();
164 if (mode == Center) {
165 if (movingEnabled)
166 return true;
167 } else {
168 return true;
169 }
170 }
171 break;
172 case QEvent::MouseMove: {
173 if (w->isMaximized())
174 break;
175 buttonDown = buttonDown && (e->buttons() & Qt::LeftButton); // safety, state machine broken!
176 bool me = movingEnabled;
177 movingEnabled = (me && o == widget && (buttonDown || moveResizeMode));
178 mouseMoveEvent(e);
179 movingEnabled = me;
180 if (mode == Center) {
181 if (movingEnabled)
182 return true;
183 } else {
184 return true;
185 }
186 } break;
187 case QEvent::KeyPress:
188 keyPressEvent((QKeyEvent*)e);
189 break;
190 case QEvent::ShortcutOverride:
191 if (buttonDown) {
192 ((QKeyEvent*)ee)->accept();
193 return true;
194 }
195 break;
196 default:
197 break;
198 }
199
200 return false;
201}
202
203void QWidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
204{
205 QPoint pos = widget->mapFromGlobal(e->globalPos());
206 if (!moveResizeMode && !buttonDown) {
207 if (pos.y() <= range && pos.x() <= range)
208 mode = TopLeft;
209 else if (pos.y() >= widget->height()-range && pos.x() >= widget->width()-range)
210 mode = BottomRight;
211 else if (pos.y() >= widget->height()-range && pos.x() <= range)
212 mode = BottomLeft;
213 else if (pos.y() <= range && pos.x() >= widget->width()-range)
214 mode = TopRight;
215 else if (pos.y() <= range)
216 mode = Top;
217 else if (pos.y() >= widget->height()-range)
218 mode = Bottom;
219 else if (pos.x() <= range)
220 mode = Left;
221 else if ( pos.x() >= widget->width()-range)
222 mode = Right;
223 else if (widget->rect().contains(pos))
224 mode = Center;
225 else
226 mode = Nowhere;
227
228 if (widget->isMinimized() || !isActive(Resize))
229 mode = Center;
230#ifndef QT_NO_CURSOR
231 setMouseCursor(mode);
232#endif
233 return;
234 }
235
236 if (mode == Center && !movingEnabled)
237 return;
238
239 if (widget->testAttribute(Qt::WA_WState_ConfigPending))
240 return;
241
242
243 QPoint globalPos = (!widget->isWindow() && widget->parentWidget()) ?
244 widget->parentWidget()->mapFromGlobal(e->globalPos()) : e->globalPos();
245 if (!widget->isWindow() && !widget->parentWidget()->rect().contains(globalPos)) {
246 if (globalPos.x() < 0)
247 globalPos.rx() = 0;
248 if (globalPos.y() < 0)
249 globalPos.ry() = 0;
250 if (sizeprotect && globalPos.x() > widget->parentWidget()->width())
251 globalPos.rx() = widget->parentWidget()->width();
252 if (sizeprotect && globalPos.y() > widget->parentWidget()->height())
253 globalPos.ry() = widget->parentWidget()->height();
254 }
255
256 QPoint p = globalPos + invertedMoveOffset;
257 QPoint pp = globalPos - moveOffset;
258
259#ifdef Q_WS_X11
260 // Workaround for window managers which refuse to move a tool window partially offscreen.
261 QRect desktop = qApp->desktop()->availableGeometry(widget);
262 pp.rx() = qMax(pp.x(), desktop.left());
263 pp.ry() = qMax(pp.y(), desktop.top());
264 p.rx() = qMin(p.x(), desktop.right());
265 p.ry() = qMin(p.y(), desktop.bottom());
266#endif
267
268 QSize ms = qSmartMinSize(childWidget);
269 int mw = ms.width();
270 int mh = ms.height();
271 if (childWidget != widget) {
272 mw += 2 * fw;
273 mh += 2 * fw + extrahei;
274 }
275
276 QSize maxsize(childWidget->maximumSize());
277 if (childWidget != widget)
278 maxsize += QSize(2 * fw, 2 * fw + extrahei);
279 QSize mpsize(widget->geometry().right() - pp.x() + 1,
280 widget->geometry().bottom() - pp.y() + 1);
281 mpsize = mpsize.expandedTo(widget->minimumSize()).expandedTo(QSize(mw, mh))
282 .boundedTo(maxsize);
283 QPoint mp(widget->geometry().right() - mpsize.width() + 1,
284 widget->geometry().bottom() - mpsize.height() + 1);
285
286 QRect geom = widget->geometry();
287
288 switch (mode) {
289 case TopLeft:
290 geom = QRect(mp, widget->geometry().bottomRight()) ;
291 break;
292 case BottomRight:
293 geom = QRect(widget->geometry().topLeft(), p) ;
294 break;
295 case BottomLeft:
296 geom = QRect(QPoint(mp.x(), widget->geometry().y()), QPoint(widget->geometry().right(), p.y())) ;
297 break;
298 case TopRight:
299 geom = QRect(QPoint(widget->geometry().x(), mp.y()), QPoint(p.x(), widget->geometry().bottom())) ;
300 break;
301 case Top:
302 geom = QRect(QPoint(widget->geometry().left(), mp.y()), widget->geometry().bottomRight()) ;
303 break;
304 case Bottom:
305 geom = QRect(widget->geometry().topLeft(), QPoint(widget->geometry().right(), p.y())) ;
306 break;
307 case Left:
308 geom = QRect(QPoint(mp.x(), widget->geometry().top()), widget->geometry().bottomRight()) ;
309 break;
310 case Right:
311 geom = QRect(widget->geometry().topLeft(), QPoint(p.x(), widget->geometry().bottom())) ;
312 break;
313 case Center:
314 geom.moveTopLeft(pp);
315 break;
316 default:
317 break;
318 }
319
320 geom = QRect(geom.topLeft(),
321 geom.size().expandedTo(widget->minimumSize())
322 .expandedTo(QSize(mw, mh))
323 .boundedTo(maxsize));
324
325 if (geom != widget->geometry() &&
326 (widget->isWindow() || widget->parentWidget()->rect().intersects(geom))) {
327 if (mode == Center)
328 widget->move(geom.topLeft());
329 else
330 widget->setGeometry(geom);
331 }
332
333 QApplication::syncX();
334}
335
336void QWidgetResizeHandler::setMouseCursor(MousePosition m)
337{
338#ifdef QT_NO_CURSOR
339 Q_UNUSED(m);
340#else
341 QObjectList children = widget->children();
342 for (int i = 0; i < children.size(); ++i) {
343 if (QWidget *w = qobject_cast<QWidget*>(children.at(i))) {
344 if (!w->testAttribute(Qt::WA_SetCursor) && !w->inherits("QWorkspaceTitleBar")) {
345 w->setCursor(Qt::ArrowCursor);
346 }
347 }
348 }
349
350 switch (m) {
351 case TopLeft:
352 case BottomRight:
353 widget->setCursor(Qt::SizeFDiagCursor);
354 break;
355 case BottomLeft:
356 case TopRight:
357 widget->setCursor(Qt::SizeBDiagCursor);
358 break;
359 case Top:
360 case Bottom:
361 widget->setCursor(Qt::SizeVerCursor);
362 break;
363 case Left:
364 case Right:
365 widget->setCursor(Qt::SizeHorCursor);
366 break;
367 default:
368 widget->setCursor(Qt::ArrowCursor);
369 break;
370 }
371#endif // QT_NO_CURSOR
372}
373
374void QWidgetResizeHandler::keyPressEvent(QKeyEvent * e)
375{
376 if (!isMove() && !isResize())
377 return;
378 bool is_control = e->modifiers() & Qt::ControlModifier;
379 int delta = is_control?1:8;
380 QPoint pos = QCursor::pos();
381 switch (e->key()) {
382 case Qt::Key_Left:
383 pos.rx() -= delta;
384 if (pos.x() <= QApplication::desktop()->geometry().left()) {
385 if (mode == TopLeft || mode == BottomLeft) {
386 moveOffset.rx() += delta;
387 invertedMoveOffset.rx() += delta;
388 } else {
389 moveOffset.rx() -= delta;
390 invertedMoveOffset.rx() -= delta;
391 }
392 }
393 if (isResize() && !resizeHorizontalDirectionFixed) {
394 resizeHorizontalDirectionFixed = true;
395 if (mode == BottomRight)
396 mode = BottomLeft;
397 else if (mode == TopRight)
398 mode = TopLeft;
399#ifndef QT_NO_CURSOR
400 setMouseCursor(mode);
401 widget->grabMouse(widget->cursor());
402#else
403 widget->grabMouse();
404#endif
405 }
406 break;
407 case Qt::Key_Right:
408 pos.rx() += delta;
409 if (pos.x() >= QApplication::desktop()->geometry().right()) {
410 if (mode == TopRight || mode == BottomRight) {
411 moveOffset.rx() += delta;
412 invertedMoveOffset.rx() += delta;
413 } else {
414 moveOffset.rx() -= delta;
415 invertedMoveOffset.rx() -= delta;
416 }
417 }
418 if (isResize() && !resizeHorizontalDirectionFixed) {
419 resizeHorizontalDirectionFixed = true;
420 if (mode == BottomLeft)
421 mode = BottomRight;
422 else if (mode == TopLeft)
423 mode = TopRight;
424#ifndef QT_NO_CURSOR
425 setMouseCursor(mode);
426 widget->grabMouse(widget->cursor());
427#else
428 widget->grabMouse();
429#endif
430 }
431 break;
432 case Qt::Key_Up:
433 pos.ry() -= delta;
434 if (pos.y() <= QApplication::desktop()->geometry().top()) {
435 if (mode == TopLeft || mode == TopRight) {
436 moveOffset.ry() += delta;
437 invertedMoveOffset.ry() += delta;
438 } else {
439 moveOffset.ry() -= delta;
440 invertedMoveOffset.ry() -= delta;
441 }
442 }
443 if (isResize() && !resizeVerticalDirectionFixed) {
444 resizeVerticalDirectionFixed = true;
445 if (mode == BottomLeft)
446 mode = TopLeft;
447 else if (mode == BottomRight)
448 mode = TopRight;
449#ifndef QT_NO_CURSOR
450 setMouseCursor(mode);
451 widget->grabMouse(widget->cursor());
452#else
453 widget->grabMouse();
454#endif
455 }
456 break;
457 case Qt::Key_Down:
458 pos.ry() += delta;
459 if (pos.y() >= QApplication::desktop()->geometry().bottom()) {
460 if (mode == BottomLeft || mode == BottomRight) {
461 moveOffset.ry() += delta;
462 invertedMoveOffset.ry() += delta;
463 } else {
464 moveOffset.ry() -= delta;
465 invertedMoveOffset.ry() -= delta;
466 }
467 }
468 if (isResize() && !resizeVerticalDirectionFixed) {
469 resizeVerticalDirectionFixed = true;
470 if (mode == TopLeft)
471 mode = BottomLeft;
472 else if (mode == TopRight)
473 mode = BottomRight;
474#ifndef QT_NO_CURSOR
475 setMouseCursor(mode);
476 widget->grabMouse(widget->cursor());
477#else
478 widget->grabMouse();
479#endif
480 }
481 break;
482 case Qt::Key_Space:
483 case Qt::Key_Return:
484 case Qt::Key_Enter:
485 case Qt::Key_Escape:
486 moveResizeMode = false;
487 widget->releaseMouse();
488 widget->releaseKeyboard();
489 buttonDown = false;
490 break;
491 default:
492 return;
493 }
494 QCursor::setPos(pos);
495}
496
497
498void QWidgetResizeHandler::doResize()
499{
500 if (!activeForResize)
501 return;
502
503 moveResizeMode = true;
504 moveOffset = widget->mapFromGlobal(QCursor::pos());
505 if (moveOffset.x() < widget->width()/2) {
506 if (moveOffset.y() < widget->height()/2)
507 mode = TopLeft;
508 else
509 mode = BottomLeft;
510 } else {
511 if (moveOffset.y() < widget->height()/2)
512 mode = TopRight;
513 else
514 mode = BottomRight;
515 }
516 invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
517#ifndef QT_NO_CURSOR
518 setMouseCursor(mode);
519 widget->grabMouse(widget->cursor() );
520#else
521 widget->grabMouse();
522#endif
523 widget->grabKeyboard();
524 resizeHorizontalDirectionFixed = false;
525 resizeVerticalDirectionFixed = false;
526}
527
528void QWidgetResizeHandler::doMove()
529{
530 if (!activeForMove)
531 return;
532
533 mode = Center;
534 moveResizeMode = true;
535 moveOffset = widget->mapFromGlobal(QCursor::pos());
536 invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
537#ifndef QT_NO_CURSOR
538 widget->grabMouse(Qt::SizeAllCursor);
539#else
540 widget->grabMouse();
541#endif
542 widget->grabKeyboard();
543}
544
545QT_END_NAMESPACE
546
547#endif //QT_NO_RESIZEHANDLER
Note: See TracBrowser for help on using the repository browser.