1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtGui module of the Qt Toolkit.
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.
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.
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.
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.
40
****************************************************************************/
42
#include "qwidgetresizehandler_p.h"
44
#ifndef QT_NO_RESIZEHANDLER
46
#include "qapplication.h"
47
#include "qdesktopwidget.h"
49
#include "qsizegrip.h"
52
#include "private/qlayoutengine_p.h"
58
static bool resizeHorizontalDirectionFixed = false;
59
static bool resizeVerticalDirectionFixed = false;
61
QWidgetResizeHandler::QWidgetResizeHandler(QWidget *parent, QWidget *cw)
62
: QObject(parent), widget(parent), childWidget(cw ? cw : parent),
63
fw(0), extrahei(0), buttonDown(false), moveResizeMode(false), sizeprotect(true), movingEnabled(true)
66
widget->setMouseTracking(true);
67
QFrame *frame = qobject_cast<QFrame*>(widget);
68
range = frame ? frame->frameWidth() : RANGE;
69
range = qMax(RANGE, range);
70
activeForMove = activeForResize = true;
71
widget->installEventFilter(this);
74
void QWidgetResizeHandler::setActive(Action ac, bool b)
82
setMouseCursor(Nowhere);
85
bool QWidgetResizeHandler::isActive(Action ac) const
88
if (ac & Move) b = activeForMove;
89
if (ac & Resize) b |= activeForResize;
94
bool QWidgetResizeHandler::eventFilter(QObject *o, QEvent *ee)
97
|| (ee->type() != QEvent::MouseButtonPress
98
&& ee->type() != QEvent::MouseButtonRelease
99
&& ee->type() != QEvent::MouseMove
100
&& ee->type() != QEvent::KeyPress
101
&& ee->type() != QEvent::ShortcutOverride)
105
Q_ASSERT(o == widget);
107
if (QApplication::activePopupWidget()) {
108
if (buttonDown && ee->type() == QEvent::MouseButtonRelease)
113
QMouseEvent *e = (QMouseEvent*)ee;
115
case QEvent::MouseButtonPress: {
116
if (w->isMaximized())
118
if (!widget->rect().contains(widget->mapFromGlobal(e->globalPos())))
120
if (e->button() == Qt::LeftButton) {
121
#if defined(Q_WS_X11)
123
Implicit grabs do not stop the X server from changing
124
the cursor in children, which looks *really* bad when
125
doing resizingk, so we grab the cursor. Note that we do
126
not do this on Windows since double clicks are lost due
127
to the grab (see change 198463).
129
if (e->spontaneous())
130
# if !defined(QT_NO_CURSOR)
131
widget->grabMouse(widget->cursor());
134
# endif // QT_NO_CURSOR
138
bool me = movingEnabled;
139
movingEnabled = (me && o == widget);
143
moveOffset = widget->mapFromGlobal(e->globalPos());
144
invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
145
if (mode == Center) {
153
case QEvent::MouseButtonRelease:
154
if (w->isMaximized())
156
if (e->button() == Qt::LeftButton) {
157
moveResizeMode = false;
159
widget->releaseMouse();
160
widget->releaseKeyboard();
161
if (mode == Center) {
169
case QEvent::MouseMove: {
170
if (w->isMaximized())
172
buttonDown = buttonDown && (e->buttons() & Qt::LeftButton); // safety, state machine broken!
173
bool me = movingEnabled;
174
movingEnabled = (me && o == widget && (buttonDown || moveResizeMode));
177
if (mode == Center) {
184
case QEvent::KeyPress:
185
keyPressEvent((QKeyEvent*)e);
187
case QEvent::ShortcutOverride:
189
((QKeyEvent*)ee)->accept();
200
void QWidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
202
QPoint pos = widget->mapFromGlobal(e->globalPos());
203
if (!moveResizeMode && !buttonDown) {
204
if (pos.y() <= range && pos.x() <= range)
206
else if (pos.y() >= widget->height()-range && pos.x() >= widget->width()-range)
208
else if (pos.y() >= widget->height()-range && pos.x() <= range)
210
else if (pos.y() <= range && pos.x() >= widget->width()-range)
212
else if (pos.y() <= range)
214
else if (pos.y() >= widget->height()-range)
216
else if (pos.x() <= range)
218
else if ( pos.x() >= widget->width()-range)
220
else if (widget->rect().contains(pos))
225
if (widget->isMinimized() || !isActive(Resize))
228
setMouseCursor(mode);
233
if (mode == Center && !movingEnabled)
236
if (widget->testAttribute(Qt::WA_WState_ConfigPending))
240
QPoint globalPos = (!widget->isWindow() && widget->parentWidget()) ?
241
widget->parentWidget()->mapFromGlobal(e->globalPos()) : e->globalPos();
242
if (!widget->isWindow() && !widget->parentWidget()->rect().contains(globalPos)) {
243
if (globalPos.x() < 0)
245
if (globalPos.y() < 0)
247
if (sizeprotect && globalPos.x() > widget->parentWidget()->width())
248
globalPos.rx() = widget->parentWidget()->width();
249
if (sizeprotect && globalPos.y() > widget->parentWidget()->height())
250
globalPos.ry() = widget->parentWidget()->height();
253
QPoint p = globalPos + invertedMoveOffset;
254
QPoint pp = globalPos - moveOffset;
256
// Workaround for window managers which refuse to move a tool window partially offscreen.
257
if (QGuiApplication::platformName() == QLatin1String("xcb")) {
258
const QRect desktop = QApplication::desktop()->availableGeometry(widget);
259
pp.rx() = qMax(pp.x(), desktop.left());
260
pp.ry() = qMax(pp.y(), desktop.top());
261
p.rx() = qMin(p.x(), desktop.right());
262
p.ry() = qMin(p.y(), desktop.bottom());
265
QSize ms = qSmartMinSize(childWidget);
267
int mh = ms.height();
268
if (childWidget != widget) {
270
mh += 2 * fw + extrahei;
273
QSize maxsize(childWidget->maximumSize());
274
if (childWidget != widget)
275
maxsize += QSize(2 * fw, 2 * fw + extrahei);
276
QSize mpsize(widget->geometry().right() - pp.x() + 1,
277
widget->geometry().bottom() - pp.y() + 1);
278
mpsize = mpsize.expandedTo(widget->minimumSize()).expandedTo(QSize(mw, mh))
280
QPoint mp(widget->geometry().right() - mpsize.width() + 1,
281
widget->geometry().bottom() - mpsize.height() + 1);
283
QRect geom = widget->geometry();
287
geom = QRect(mp, widget->geometry().bottomRight()) ;
290
geom = QRect(widget->geometry().topLeft(), p) ;
293
geom = QRect(QPoint(mp.x(), widget->geometry().y()), QPoint(widget->geometry().right(), p.y())) ;
296
geom = QRect(QPoint(widget->geometry().x(), mp.y()), QPoint(p.x(), widget->geometry().bottom())) ;
299
geom = QRect(QPoint(widget->geometry().left(), mp.y()), widget->geometry().bottomRight()) ;
302
geom = QRect(widget->geometry().topLeft(), QPoint(widget->geometry().right(), p.y())) ;
305
geom = QRect(QPoint(mp.x(), widget->geometry().top()), widget->geometry().bottomRight()) ;
308
geom = QRect(widget->geometry().topLeft(), QPoint(p.x(), widget->geometry().bottom())) ;
311
geom.moveTopLeft(pp);
317
geom = QRect(geom.topLeft(),
318
geom.size().expandedTo(widget->minimumSize())
319
.expandedTo(QSize(mw, mh))
320
.boundedTo(maxsize));
322
if (geom != widget->geometry() &&
323
(widget->isWindow() || widget->parentWidget()->rect().intersects(geom))) {
325
widget->move(geom.topLeft());
327
widget->setGeometry(geom);
331
void QWidgetResizeHandler::setMouseCursor(MousePosition m)
336
QObjectList children = widget->children();
337
for (int i = 0; i < children.size(); ++i) {
338
if (QWidget *w = qobject_cast<QWidget*>(children.at(i))) {
339
if (!w->testAttribute(Qt::WA_SetCursor)) {
340
w->setCursor(Qt::ArrowCursor);
348
widget->setCursor(Qt::SizeFDiagCursor);
352
widget->setCursor(Qt::SizeBDiagCursor);
356
widget->setCursor(Qt::SizeVerCursor);
360
widget->setCursor(Qt::SizeHorCursor);
363
widget->setCursor(Qt::ArrowCursor);
366
#endif // QT_NO_CURSOR
369
void QWidgetResizeHandler::keyPressEvent(QKeyEvent * e)
371
if (!isMove() && !isResize())
373
bool is_control = e->modifiers() & Qt::ControlModifier;
374
int delta = is_control?1:8;
375
QPoint pos = QCursor::pos();
379
if (pos.x() <= QApplication::desktop()->geometry().left()) {
380
if (mode == TopLeft || mode == BottomLeft) {
381
moveOffset.rx() += delta;
382
invertedMoveOffset.rx() += delta;
384
moveOffset.rx() -= delta;
385
invertedMoveOffset.rx() -= delta;
388
if (isResize() && !resizeHorizontalDirectionFixed) {
389
resizeHorizontalDirectionFixed = true;
390
if (mode == BottomRight)
392
else if (mode == TopRight)
395
setMouseCursor(mode);
396
widget->grabMouse(widget->cursor());
404
if (pos.x() >= QApplication::desktop()->geometry().right()) {
405
if (mode == TopRight || mode == BottomRight) {
406
moveOffset.rx() += delta;
407
invertedMoveOffset.rx() += delta;
409
moveOffset.rx() -= delta;
410
invertedMoveOffset.rx() -= delta;
413
if (isResize() && !resizeHorizontalDirectionFixed) {
414
resizeHorizontalDirectionFixed = true;
415
if (mode == BottomLeft)
417
else if (mode == TopLeft)
420
setMouseCursor(mode);
421
widget->grabMouse(widget->cursor());
429
if (pos.y() <= QApplication::desktop()->geometry().top()) {
430
if (mode == TopLeft || mode == TopRight) {
431
moveOffset.ry() += delta;
432
invertedMoveOffset.ry() += delta;
434
moveOffset.ry() -= delta;
435
invertedMoveOffset.ry() -= delta;
438
if (isResize() && !resizeVerticalDirectionFixed) {
439
resizeVerticalDirectionFixed = true;
440
if (mode == BottomLeft)
442
else if (mode == BottomRight)
445
setMouseCursor(mode);
446
widget->grabMouse(widget->cursor());
454
if (pos.y() >= QApplication::desktop()->geometry().bottom()) {
455
if (mode == BottomLeft || mode == BottomRight) {
456
moveOffset.ry() += delta;
457
invertedMoveOffset.ry() += delta;
459
moveOffset.ry() -= delta;
460
invertedMoveOffset.ry() -= delta;
463
if (isResize() && !resizeVerticalDirectionFixed) {
464
resizeVerticalDirectionFixed = true;
467
else if (mode == TopRight)
470
setMouseCursor(mode);
471
widget->grabMouse(widget->cursor());
481
moveResizeMode = false;
482
widget->releaseMouse();
483
widget->releaseKeyboard();
489
QCursor::setPos(pos);
493
void QWidgetResizeHandler::doResize()
495
if (!activeForResize)
498
moveResizeMode = true;
499
moveOffset = widget->mapFromGlobal(QCursor::pos());
500
if (moveOffset.x() < widget->width()/2) {
501
if (moveOffset.y() < widget->height()/2)
506
if (moveOffset.y() < widget->height()/2)
511
invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
513
setMouseCursor(mode);
514
widget->grabMouse(widget->cursor() );
518
widget->grabKeyboard();
519
resizeHorizontalDirectionFixed = false;
520
resizeVerticalDirectionFixed = false;
523
void QWidgetResizeHandler::doMove()
529
moveResizeMode = true;
530
moveOffset = widget->mapFromGlobal(QCursor::pos());
531
invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
533
widget->grabMouse(Qt::SizeAllCursor);
537
widget->grabKeyboard();
542
#endif //QT_NO_RESIZEHANDLER