~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to src/widgets/widgets/qwidgetresizehandler.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 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
#include "qdebug.h"
 
52
#include "private/qlayoutengine_p.h"
 
53
 
 
54
QT_BEGIN_NAMESPACE
 
55
 
 
56
#define RANGE 4
 
57
 
 
58
static bool resizeHorizontalDirectionFixed = false;
 
59
static bool resizeVerticalDirectionFixed = false;
 
60
 
 
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)
 
64
{
 
65
    mode = Nowhere;
 
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);
 
72
}
 
73
 
 
74
void QWidgetResizeHandler::setActive(Action ac, bool b)
 
75
{
 
76
    if (ac & Move)
 
77
        activeForMove = b;
 
78
    if (ac & Resize)
 
79
        activeForResize = b;
 
80
 
 
81
    if (!isActive())
 
82
        setMouseCursor(Nowhere);
 
83
}
 
84
 
 
85
bool QWidgetResizeHandler::isActive(Action ac) const
 
86
{
 
87
    bool b = false;
 
88
    if (ac & Move) b = activeForMove;
 
89
    if (ac & Resize) b |= activeForResize;
 
90
 
 
91
    return b;
 
92
}
 
93
 
 
94
bool QWidgetResizeHandler::eventFilter(QObject *o, QEvent *ee)
 
95
{
 
96
    if (!isActive()
 
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)
 
102
        )
 
103
        return false;
 
104
 
 
105
    Q_ASSERT(o == widget);
 
106
    QWidget *w = widget;
 
107
    if (QApplication::activePopupWidget()) {
 
108
        if (buttonDown && ee->type() == QEvent::MouseButtonRelease)
 
109
            buttonDown = false;
 
110
        return false;
 
111
    }
 
112
 
 
113
    QMouseEvent *e = (QMouseEvent*)ee;
 
114
    switch (e->type()) {
 
115
    case QEvent::MouseButtonPress: {
 
116
        if (w->isMaximized())
 
117
            break;
 
118
        if (!widget->rect().contains(widget->mapFromGlobal(e->globalPos())))
 
119
            return false;
 
120
        if (e->button() == Qt::LeftButton) {
 
121
#if defined(Q_WS_X11)
 
122
            /*
 
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).
 
128
            */
 
129
            if (e->spontaneous())
 
130
#  if !defined(QT_NO_CURSOR)
 
131
                widget->grabMouse(widget->cursor());
 
132
#  else
 
133
                widget->grabMouse();
 
134
#  endif // QT_NO_CURSOR
 
135
#endif // Q_WS_X11
 
136
            buttonDown = false;
 
137
            emit activate();
 
138
            bool me = movingEnabled;
 
139
            movingEnabled = (me && o == widget);
 
140
            mouseMoveEvent(e);
 
141
            movingEnabled = me;
 
142
            buttonDown = true;
 
143
            moveOffset = widget->mapFromGlobal(e->globalPos());
 
144
            invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
 
145
            if (mode == Center) {
 
146
                if (movingEnabled)
 
147
                    return true;
 
148
            } else {
 
149
                return true;
 
150
            }
 
151
        }
 
152
    } break;
 
153
    case QEvent::MouseButtonRelease:
 
154
        if (w->isMaximized())
 
155
            break;
 
156
        if (e->button() == Qt::LeftButton) {
 
157
            moveResizeMode = false;
 
158
            buttonDown = false;
 
159
            widget->releaseMouse();
 
160
            widget->releaseKeyboard();
 
161
            if (mode == Center) {
 
162
                if (movingEnabled)
 
163
                    return true;
 
164
            } else {
 
165
                return true;
 
166
            }
 
167
        }
 
168
        break;
 
169
    case QEvent::MouseMove: {
 
170
        if (w->isMaximized())
 
171
            break;
 
172
        buttonDown = buttonDown && (e->buttons() & Qt::LeftButton); // safety, state machine broken!
 
173
        bool me = movingEnabled;
 
174
        movingEnabled = (me && o == widget && (buttonDown || moveResizeMode));
 
175
        mouseMoveEvent(e);
 
176
        movingEnabled = me;
 
177
        if (mode == Center) {
 
178
            if (movingEnabled)
 
179
                return true;
 
180
        } else {
 
181
            return true;
 
182
        }
 
183
    } break;
 
184
    case QEvent::KeyPress:
 
185
        keyPressEvent((QKeyEvent*)e);
 
186
        break;
 
187
    case QEvent::ShortcutOverride:
 
188
        if (buttonDown) {
 
189
            ((QKeyEvent*)ee)->accept();
 
190
            return true;
 
191
        }
 
192
        break;
 
193
    default:
 
194
        break;
 
195
    }
 
196
 
 
197
    return false;
 
198
}
 
199
 
 
200
void QWidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
 
201
{
 
202
    QPoint pos = widget->mapFromGlobal(e->globalPos());
 
203
    if (!moveResizeMode && !buttonDown) {
 
204
        if (pos.y() <= range && pos.x() <= range)
 
205
            mode = TopLeft;
 
206
        else if (pos.y() >= widget->height()-range && pos.x() >= widget->width()-range)
 
207
            mode = BottomRight;
 
208
        else if (pos.y() >= widget->height()-range && pos.x() <= range)
 
209
            mode = BottomLeft;
 
210
        else if (pos.y() <= range && pos.x() >= widget->width()-range)
 
211
            mode = TopRight;
 
212
        else if (pos.y() <= range)
 
213
            mode = Top;
 
214
        else if (pos.y() >= widget->height()-range)
 
215
            mode = Bottom;
 
216
        else if (pos.x() <= range)
 
217
            mode = Left;
 
218
        else if ( pos.x() >= widget->width()-range)
 
219
            mode = Right;
 
220
        else if (widget->rect().contains(pos))
 
221
            mode = Center;
 
222
        else
 
223
            mode = Nowhere;
 
224
 
 
225
        if (widget->isMinimized() || !isActive(Resize))
 
226
            mode = Center;
 
227
#ifndef QT_NO_CURSOR
 
228
        setMouseCursor(mode);
 
229
#endif
 
230
        return;
 
231
    }
 
232
 
 
233
    if (mode == Center && !movingEnabled)
 
234
        return;
 
235
 
 
236
    if (widget->testAttribute(Qt::WA_WState_ConfigPending))
 
237
        return;
 
238
 
 
239
 
 
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)
 
244
            globalPos.rx() = 0;
 
245
        if (globalPos.y() < 0)
 
246
            globalPos.ry() = 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();
 
251
    }
 
252
 
 
253
    QPoint p = globalPos + invertedMoveOffset;
 
254
    QPoint pp = globalPos - moveOffset;
 
255
 
 
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());
 
263
    }
 
264
 
 
265
    QSize ms = qSmartMinSize(childWidget);
 
266
    int mw = ms.width();
 
267
    int mh = ms.height();
 
268
    if (childWidget != widget) {
 
269
        mw += 2 * fw;
 
270
        mh += 2 * fw + extrahei;
 
271
    }
 
272
 
 
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))
 
279
                    .boundedTo(maxsize);
 
280
    QPoint mp(widget->geometry().right() - mpsize.width() + 1,
 
281
               widget->geometry().bottom() - mpsize.height() + 1);
 
282
 
 
283
    QRect geom = widget->geometry();
 
284
 
 
285
    switch (mode) {
 
286
    case TopLeft:
 
287
        geom = QRect(mp, widget->geometry().bottomRight()) ;
 
288
        break;
 
289
    case BottomRight:
 
290
        geom = QRect(widget->geometry().topLeft(), p) ;
 
291
        break;
 
292
    case BottomLeft:
 
293
        geom = QRect(QPoint(mp.x(), widget->geometry().y()), QPoint(widget->geometry().right(), p.y())) ;
 
294
        break;
 
295
    case TopRight:
 
296
        geom = QRect(QPoint(widget->geometry().x(), mp.y()), QPoint(p.x(), widget->geometry().bottom())) ;
 
297
        break;
 
298
    case Top:
 
299
        geom = QRect(QPoint(widget->geometry().left(), mp.y()), widget->geometry().bottomRight()) ;
 
300
        break;
 
301
    case Bottom:
 
302
        geom = QRect(widget->geometry().topLeft(), QPoint(widget->geometry().right(), p.y())) ;
 
303
        break;
 
304
    case Left:
 
305
        geom = QRect(QPoint(mp.x(), widget->geometry().top()), widget->geometry().bottomRight()) ;
 
306
        break;
 
307
    case Right:
 
308
        geom = QRect(widget->geometry().topLeft(), QPoint(p.x(), widget->geometry().bottom())) ;
 
309
        break;
 
310
    case Center:
 
311
        geom.moveTopLeft(pp);
 
312
        break;
 
313
    default:
 
314
        break;
 
315
    }
 
316
 
 
317
    geom = QRect(geom.topLeft(),
 
318
                  geom.size().expandedTo(widget->minimumSize())
 
319
                             .expandedTo(QSize(mw, mh))
 
320
                             .boundedTo(maxsize));
 
321
 
 
322
    if (geom != widget->geometry() &&
 
323
        (widget->isWindow() || widget->parentWidget()->rect().intersects(geom))) {
 
324
        if (mode == Center)
 
325
            widget->move(geom.topLeft());
 
326
        else
 
327
            widget->setGeometry(geom);
 
328
    }
 
329
}
 
330
 
 
331
void QWidgetResizeHandler::setMouseCursor(MousePosition m)
 
332
{
 
333
#ifdef QT_NO_CURSOR
 
334
    Q_UNUSED(m);
 
335
#else
 
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);
 
341
            }
 
342
        }
 
343
    }
 
344
 
 
345
    switch (m) {
 
346
    case TopLeft:
 
347
    case BottomRight:
 
348
        widget->setCursor(Qt::SizeFDiagCursor);
 
349
        break;
 
350
    case BottomLeft:
 
351
    case TopRight:
 
352
        widget->setCursor(Qt::SizeBDiagCursor);
 
353
        break;
 
354
    case Top:
 
355
    case Bottom:
 
356
        widget->setCursor(Qt::SizeVerCursor);
 
357
        break;
 
358
    case Left:
 
359
    case Right:
 
360
        widget->setCursor(Qt::SizeHorCursor);
 
361
        break;
 
362
    default:
 
363
        widget->setCursor(Qt::ArrowCursor);
 
364
        break;
 
365
    }
 
366
#endif // QT_NO_CURSOR
 
367
}
 
368
 
 
369
void QWidgetResizeHandler::keyPressEvent(QKeyEvent * e)
 
370
{
 
371
    if (!isMove() && !isResize())
 
372
        return;
 
373
    bool is_control = e->modifiers() & Qt::ControlModifier;
 
374
    int delta = is_control?1:8;
 
375
    QPoint pos = QCursor::pos();
 
376
    switch (e->key()) {
 
377
    case Qt::Key_Left:
 
378
        pos.rx() -= delta;
 
379
        if (pos.x() <= QApplication::desktop()->geometry().left()) {
 
380
            if (mode == TopLeft || mode == BottomLeft) {
 
381
                moveOffset.rx() += delta;
 
382
                invertedMoveOffset.rx() += delta;
 
383
            } else {
 
384
                moveOffset.rx() -= delta;
 
385
                invertedMoveOffset.rx() -= delta;
 
386
            }
 
387
        }
 
388
        if (isResize() && !resizeHorizontalDirectionFixed) {
 
389
            resizeHorizontalDirectionFixed = true;
 
390
            if (mode == BottomRight)
 
391
                mode = BottomLeft;
 
392
            else if (mode == TopRight)
 
393
                mode = TopLeft;
 
394
#ifndef QT_NO_CURSOR
 
395
            setMouseCursor(mode);
 
396
            widget->grabMouse(widget->cursor());
 
397
#else
 
398
            widget->grabMouse();
 
399
#endif
 
400
        }
 
401
        break;
 
402
    case Qt::Key_Right:
 
403
        pos.rx() += delta;
 
404
        if (pos.x() >= QApplication::desktop()->geometry().right()) {
 
405
            if (mode == TopRight || mode == BottomRight) {
 
406
                moveOffset.rx() += delta;
 
407
                invertedMoveOffset.rx() += delta;
 
408
            } else {
 
409
                moveOffset.rx() -= delta;
 
410
                invertedMoveOffset.rx() -= delta;
 
411
            }
 
412
        }
 
413
        if (isResize() && !resizeHorizontalDirectionFixed) {
 
414
            resizeHorizontalDirectionFixed = true;
 
415
            if (mode == BottomLeft)
 
416
                mode = BottomRight;
 
417
            else if (mode == TopLeft)
 
418
                mode = TopRight;
 
419
#ifndef QT_NO_CURSOR
 
420
            setMouseCursor(mode);
 
421
            widget->grabMouse(widget->cursor());
 
422
#else
 
423
            widget->grabMouse();
 
424
#endif
 
425
        }
 
426
        break;
 
427
    case Qt::Key_Up:
 
428
        pos.ry() -= delta;
 
429
        if (pos.y() <= QApplication::desktop()->geometry().top()) {
 
430
            if (mode == TopLeft || mode == TopRight) {
 
431
                moveOffset.ry() += delta;
 
432
                invertedMoveOffset.ry() += delta;
 
433
            } else {
 
434
                moveOffset.ry() -= delta;
 
435
                invertedMoveOffset.ry() -= delta;
 
436
            }
 
437
        }
 
438
        if (isResize() && !resizeVerticalDirectionFixed) {
 
439
            resizeVerticalDirectionFixed = true;
 
440
            if (mode == BottomLeft)
 
441
                mode = TopLeft;
 
442
            else if (mode == BottomRight)
 
443
                mode = TopRight;
 
444
#ifndef QT_NO_CURSOR
 
445
            setMouseCursor(mode);
 
446
            widget->grabMouse(widget->cursor());
 
447
#else
 
448
            widget->grabMouse();
 
449
#endif
 
450
        }
 
451
        break;
 
452
    case Qt::Key_Down:
 
453
        pos.ry() += delta;
 
454
        if (pos.y() >= QApplication::desktop()->geometry().bottom()) {
 
455
            if (mode == BottomLeft || mode == BottomRight) {
 
456
                moveOffset.ry() += delta;
 
457
                invertedMoveOffset.ry() += delta;
 
458
            } else {
 
459
                moveOffset.ry() -= delta;
 
460
                invertedMoveOffset.ry() -= delta;
 
461
            }
 
462
        }
 
463
        if (isResize() && !resizeVerticalDirectionFixed) {
 
464
            resizeVerticalDirectionFixed = true;
 
465
            if (mode == TopLeft)
 
466
                mode = BottomLeft;
 
467
            else if (mode == TopRight)
 
468
                mode = BottomRight;
 
469
#ifndef QT_NO_CURSOR
 
470
            setMouseCursor(mode);
 
471
            widget->grabMouse(widget->cursor());
 
472
#else
 
473
            widget->grabMouse();
 
474
#endif
 
475
        }
 
476
        break;
 
477
    case Qt::Key_Space:
 
478
    case Qt::Key_Return:
 
479
    case Qt::Key_Enter:
 
480
    case Qt::Key_Escape:
 
481
        moveResizeMode = false;
 
482
        widget->releaseMouse();
 
483
        widget->releaseKeyboard();
 
484
        buttonDown = false;
 
485
        break;
 
486
    default:
 
487
        return;
 
488
    }
 
489
    QCursor::setPos(pos);
 
490
}
 
491
 
 
492
 
 
493
void QWidgetResizeHandler::doResize()
 
494
{
 
495
    if (!activeForResize)
 
496
        return;
 
497
 
 
498
    moveResizeMode = true;
 
499
    moveOffset = widget->mapFromGlobal(QCursor::pos());
 
500
    if (moveOffset.x() < widget->width()/2) {
 
501
        if (moveOffset.y() < widget->height()/2)
 
502
            mode = TopLeft;
 
503
        else
 
504
            mode = BottomLeft;
 
505
    } else {
 
506
        if (moveOffset.y() < widget->height()/2)
 
507
            mode = TopRight;
 
508
        else
 
509
            mode = BottomRight;
 
510
    }
 
511
    invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
 
512
#ifndef QT_NO_CURSOR
 
513
    setMouseCursor(mode);
 
514
    widget->grabMouse(widget->cursor() );
 
515
#else
 
516
    widget->grabMouse();
 
517
#endif
 
518
    widget->grabKeyboard();
 
519
    resizeHorizontalDirectionFixed = false;
 
520
    resizeVerticalDirectionFixed = false;
 
521
}
 
522
 
 
523
void QWidgetResizeHandler::doMove()
 
524
{
 
525
    if (!activeForMove)
 
526
        return;
 
527
 
 
528
    mode = Center;
 
529
    moveResizeMode = true;
 
530
    moveOffset = widget->mapFromGlobal(QCursor::pos());
 
531
    invertedMoveOffset = widget->rect().bottomRight() - moveOffset;
 
532
#ifndef QT_NO_CURSOR
 
533
    widget->grabMouse(Qt::SizeAllCursor);
 
534
#else
 
535
    widget->grabMouse();
 
536
#endif
 
537
    widget->grabKeyboard();
 
538
}
 
539
 
 
540
QT_END_NAMESPACE
 
541
 
 
542
#endif //QT_NO_RESIZEHANDLER