Qt 4.8
qwidgetresizehandler.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
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 
58 
59 #define RANGE 4
60 
61 static bool resizeHorizontalDirectionFixed = false;
62 static bool resizeVerticalDirectionFixed = false;
63 
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);
75 }
76 
78 {
79  if (ac & Move)
80  activeForMove = b;
81  if (ac & Resize)
82  activeForResize = b;
83 
84  if (!isActive())
86 }
87 
89 {
90  bool b = false;
91  if (ac & Move) b = activeForMove;
92  if (ac & Resize) b |= activeForResize;
93 
94  return b;
95 }
96 
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;
112  buttonDown = false;
113  return false;
114  }
115 
116  QMouseEvent *e = (QMouseEvent*)ee;
117  switch (e->type()) {
119  if (w->isMaximized())
120  break;
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)
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;
148  if (mode == Center) {
149  if (movingEnabled)
150  return true;
151  } else {
152  return true;
153  }
154  }
155  } break;
157  if (w->isMaximized())
158  break;
159  if (e->button() == Qt::LeftButton) {
160  moveResizeMode = false;
161  buttonDown = false;
162  widget->releaseMouse();
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:
189  break;
191  if (buttonDown) {
192  ((QKeyEvent*)ee)->accept();
193  return true;
194  }
195  break;
196  default:
197  break;
198  }
199 
200  return false;
201 }
202 
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
232 #endif
233  return;
234  }
235 
236  if (mode == Center && !movingEnabled)
237  return;
238 
240  return;
241 
242 
243  QPoint globalPos = (!widget->isWindow() && widget->parentWidget()) ?
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.
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 
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 
334 }
335 
337 {
338 #ifdef QT_NO_CURSOR
339  Q_UNUSED(m);
340 #else
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:
354  break;
355  case BottomLeft:
356  case TopRight:
358  break;
359  case Top:
360  case Bottom:
362  break;
363  case Left:
364  case Right:
366  break;
367  default:
369  break;
370  }
371 #endif // QT_NO_CURSOR
372 }
373 
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  }
395  if (mode == BottomRight)
396  mode = BottomLeft;
397  else if (mode == TopRight)
398  mode = TopLeft;
399 #ifndef QT_NO_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  }
420  if (mode == BottomLeft)
421  mode = BottomRight;
422  else if (mode == TopLeft)
423  mode = TopRight;
424 #ifndef QT_NO_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  }
445  if (mode == BottomLeft)
446  mode = TopLeft;
447  else if (mode == BottomRight)
448  mode = TopRight;
449 #ifndef QT_NO_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  }
470  if (mode == TopLeft)
471  mode = BottomLeft;
472  else if (mode == TopRight)
473  mode = BottomRight;
474 #ifndef QT_NO_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();
489  buttonDown = false;
490  break;
491  default:
492  return;
493  }
494  QCursor::setPos(pos);
495 }
496 
497 
499 {
500  if (!activeForResize)
501  return;
502 
503  moveResizeMode = true;
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  }
517 #ifndef QT_NO_CURSOR
520 #else
521  widget->grabMouse();
522 #endif
523  widget->grabKeyboard();
526 }
527 
529 {
530  if (!activeForMove)
531  return;
532 
533  mode = Center;
534  moveResizeMode = true;
537 #ifndef QT_NO_CURSOR
539 #else
540  widget->grabMouse();
541 #endif
542  widget->grabKeyboard();
543 }
544 
546 
547 #endif //QT_NO_RESIZEHANDLER
QSize maximumSize
the widget&#39;s maximum size in pixels
Definition: qwidget.h:173
QSize minimumSize
the widget&#39;s minimum size
Definition: qwidget.h:172
QWidget * parentWidget() const
Returns the parent of this widget, or 0 if it does not have any parent widget.
Definition: qwidget.h:1035
The QKeyEvent class describes a key event.
Definition: qevent.h:224
void grabMouse()
Grabs the mouse input.
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
Q_GUI_EXPORT QSize qSmartMinSize(const QSize &sizeHint, const QSize &minSizeHint, const QSize &minSize, const QSize &maxSize, const QSizePolicy &sizePolicy)
QPointer< QWidget > widget
int width
the width of the widget excluding any window frame
Definition: qwidget.h:166
bool isWindow() const
Returns true if the widget is an independent window, otherwise returns false.
Definition: qwidget.h:945
bool eventFilter(QObject *o, QEvent *e)
Filters events if this object has been installed as an event filter for the watched object...
void keyPressEvent(QKeyEvent *e)
void setMouseCursor(MousePosition m)
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
QSize expandedTo(const QSize &) const
Returns a size holding the maximum width and height of this size and the given otherSize.
Definition: qsize.h:187
int left() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:240
int & ry()
Returns a reference to the y coordinate of this point.
Definition: qpoint.h:143
void mouseMoveEvent(QMouseEvent *e)
void setGeometry(int x, int y, int w, int h)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qwidget.h:1017
int bottom() const
Returns the y-coordinate of the rectangle&#39;s bottom edge.
Definition: qrect.h:249
T * qobject_cast(QObject *object)
Definition: qobject.h:375
static void setPos(int x, int y)
Moves the cursor (hot spot) to the global screen position (x, y).
Definition: qcursor_mac.mm:315
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
Qt::KeyboardModifiers modifiers() const
Returns the keyboard modifier flags that existed immediately after the event occurred.
Definition: qevent.cpp:999
int key() const
Returns the code of the key that was pressed or released.
Definition: qevent.h:231
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QPoint bottomRight() const
Returns the position of the rectangle&#39;s bottom-right corner.
Definition: qrect.h:291
void releaseMouse()
Releases the mouse grab.
int height
the height of the widget excluding any window frame
Definition: qwidget.h:167
bool testAttribute(Qt::WidgetAttribute) const
Returns true if attribute attribute is set on this widget; otherwise returns false.
Definition: qwidget.h:1041
static bool resizeHorizontalDirectionFixed
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
bool spontaneous() const
Returns true if the event originated outside the application (a system event); otherwise returns fals...
Definition: qcoreevent.h:304
int & rx()
Returns a reference to the x coordinate of this point.
Definition: qpoint.h:140
void setCursor(const QCursor &)
Definition: qwidget.cpp:5290
#define QT_NO_CURSOR
QCursor cursor
the cursor shape for this widget
Definition: qwidget.h:183
Qt::MouseButton button() const
Returns the button that caused the event.
Definition: qevent.h:101
bool contains(const QPoint &p, bool proper=false) const
Returns true if the given point is inside or on the edge of the rectangle, otherwise returns false...
Definition: qrect.cpp:1101
bool isMaximized() const
Definition: qwidget.cpp:3074
void setMouseTracking(bool enable)
Definition: qwidget.h:990
The QMouseEvent class contains parameters that describe a mouse event.
Definition: qevent.h:85
static QDesktopWidget * desktop()
Returns the desktop widget (also called the root window).
void grabKeyboard()
Grabs the keyboard input.
int top() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:243
static QWidget * activePopupWidget()
Returns the active popup widget.
Qt::MouseButtons buttons() const
Returns the button state when the event was generated.
Definition: qevent.h:102
int right() const
Returns the x-coordinate of the rectangle&#39;s right edge.
Definition: qrect.h:246
QRect rect
the internal geometry of the widget excluding any window frame
Definition: qwidget.h:168
int y() const
Returns the y-coordinate of the rectangle&#39;s top edge.
Definition: qrect.h:255
static void syncX()
Synchronizes with the X server in the X11 implementation.
int x() const
Returns the x-coordinate of the rectangle&#39;s left edge.
Definition: qrect.h:252
The QPoint class defines a point in the plane using integer precision.
Definition: qpoint.h:53
void installEventFilter(QObject *)
Installs an event filter filterObj on this object.
Definition: qobject.cpp:2070
int size() const
Returns the number of items in the list.
Definition: qlist.h:137
static bool resizeVerticalDirectionFixed
The QRect class defines a rectangle in the plane using integer precision.
Definition: qrect.h:58
QWidgetResizeHandler(QWidget *parent, QWidget *cw=0)
const QObjectList & children() const
Returns a list of child objects.
Definition: qobject.h:197
void releaseKeyboard()
Releases the keyboard grab.
int y() const
Returns the y coordinate of this point.
Definition: qpoint.h:131
QPoint mapFromGlobal(const QPoint &) const
Translates the global screen coordinate pos to widget coordinates.
bool isMinimized() const
Definition: qwidget.cpp:3027
#define RANGE
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
bool intersects(const QRect &r) const
Returns true if this rectangle intersects with the given rectangle (i.
Definition: qrect.cpp:1429
int x() const
Returns the x coordinate of this point.
Definition: qpoint.h:128
const QRect availableGeometry(int screen=-1) const
const QRect & geometry() const
int frameWidth
the width of the frame that is drawn.
Definition: qframe.h:64
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
Type type() const
Returns the event type.
Definition: qcoreevent.h:303
The QFrame class is the base class of widgets that can have a frame.
Definition: qframe.h:55
const QPoint & globalPos() const
Returns the global position of the mouse cursor at the time of the event.
Definition: qevent.h:96
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
QRect geometry
the geometry of the widget relative to its parent and excluding the window frame
Definition: qwidget.h:158
void move(int x, int y)
This corresponds to move(QPoint(x, y)).
Definition: qwidget.h:1011
static QPoint pos()
Returns the position of the cursor (hot spot) in global screen coordinates.
Definition: qcursor_mac.mm:310
QPoint topLeft() const
Returns the position of the rectangle&#39;s top-left corner.
Definition: qrect.h:288