Rewrite the canvas item's paint logic.
[profile/ivi/qtdeclarative.git] / src / declarative / graphicsitems / qdeclarativemousearea.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativemousearea_p.h"
43 #include "private/qdeclarativemousearea_p_p.h"
44
45 #include "private/qdeclarativeevents_p_p.h"
46
47 #include <QGraphicsSceneMouseEvent>
48
49 #include <float.h>
50
51 QT_BEGIN_NAMESPACE
52 static const int PressAndHoldDelay = 800;
53
54 QDeclarativeDrag::QDeclarativeDrag(QObject *parent)
55 : QObject(parent), _target(0), _axis(XandYAxis), _xmin(-FLT_MAX), _xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX),
56 _active(false), _filterChildren(false)
57 {
58 }
59
60 QDeclarativeDrag::~QDeclarativeDrag()
61 {
62 }
63
64 QGraphicsObject *QDeclarativeDrag::target() const
65 {
66     return _target;
67 }
68
69 void QDeclarativeDrag::setTarget(QGraphicsObject *t)
70 {
71     if (_target == t)
72         return;
73     _target = t;
74     emit targetChanged();
75 }
76
77 void QDeclarativeDrag::resetTarget()
78 {
79     if (!_target)
80         return;
81     _target = 0;
82     emit targetChanged();
83 }
84
85 QDeclarativeDrag::Axis QDeclarativeDrag::axis() const
86 {
87     return _axis;
88 }
89
90 void QDeclarativeDrag::setAxis(QDeclarativeDrag::Axis a)
91 {
92     if (_axis == a)
93         return;
94     _axis = a;
95     emit axisChanged();
96 }
97
98 qreal QDeclarativeDrag::xmin() const
99 {
100     return _xmin;
101 }
102
103 void QDeclarativeDrag::setXmin(qreal m)
104 {
105     if (_xmin == m)
106         return;
107     _xmin = m;
108     emit minimumXChanged();
109 }
110
111 qreal QDeclarativeDrag::xmax() const
112 {
113     return _xmax;
114 }
115
116 void QDeclarativeDrag::setXmax(qreal m)
117 {
118     if (_xmax == m)
119         return;
120     _xmax = m;
121     emit maximumXChanged();
122 }
123
124 qreal QDeclarativeDrag::ymin() const
125 {
126     return _ymin;
127 }
128
129 void QDeclarativeDrag::setYmin(qreal m)
130 {
131     if (_ymin == m)
132         return;
133     _ymin = m;
134     emit minimumYChanged();
135 }
136
137 qreal QDeclarativeDrag::ymax() const
138 {
139     return _ymax;
140 }
141
142 void QDeclarativeDrag::setYmax(qreal m)
143 {
144     if (_ymax == m)
145         return;
146     _ymax = m;
147     emit maximumYChanged();
148 }
149
150 bool QDeclarativeDrag::active() const
151 {
152     return _active;
153 }
154
155 void QDeclarativeDrag::setActive(bool drag)
156 {
157     if (_active == drag)
158         return;
159     _active = drag;
160     emit activeChanged();
161 }
162
163 bool QDeclarativeDrag::filterChildren() const
164 {
165     return _filterChildren;
166 }
167
168 void QDeclarativeDrag::setFilterChildren(bool filter)
169 {
170     if (_filterChildren == filter)
171         return;
172     _filterChildren = filter;
173     emit filterChildrenChanged();
174 }
175
176 QDeclarativeMouseAreaPrivate::~QDeclarativeMouseAreaPrivate()
177 {
178     delete drag;
179 }
180
181 /*!
182     \qmlclass MouseArea QDeclarativeMouseArea
183     \ingroup qml-basic-interaction-elements
184     \since 4.7
185     \brief The MouseArea item enables simple mouse handling.
186     \inherits Item
187
188     A MouseArea is an invisible item that is typically used in conjunction with
189     a visible item in order to provide mouse handling for that item.
190     By effectively acting as a proxy, the logic for mouse handling can be
191     contained within a MouseArea item.
192
193     For basic key handling, see the \l{Keys}{Keys attached property}.
194
195     The \l enabled property is used to enable and disable mouse handling for
196     the proxied item. When disabled, the mouse area becomes transparent to
197     mouse events.
198
199     The \l pressed read-only property indicates whether or not the user is
200     holding down a mouse button over the mouse area. This property is often
201     used in bindings between properties in a user interface. The containsMouse
202     read-only property indicates the presence of the mouse cursor over the
203     mouse area but, by default, only when a mouse button is held down; see below
204     for further details.
205
206     Information about the mouse position and button clicks are provided via
207     signals for which event handler properties are defined. The most commonly
208     used involved handling mouse presses and clicks: onClicked, onDoubleClicked,
209     onPressed, onReleased and onPressAndHold.
210
211     By default, MouseArea items only report mouse clicks and not changes to the
212     position of the mouse cursor. Setting the hoverEnabled property ensures that
213     handlers defined for onPositionChanged, onEntered and onExited are used and
214     that the containsMouse property is updated even when no mouse buttons are
215     pressed.
216
217     \section1 Example Usage
218
219     \div {class="float-right"}
220     \inlineimage qml-mousearea-snippet.png
221     \enddiv
222
223     The following example uses a MouseArea in a \l Rectangle that changes
224     the \l Rectangle color to red when clicked:
225
226     \snippet doc/src/snippets/declarative/mousearea/mousearea.qml import
227     \codeline
228     \snippet doc/src/snippets/declarative/mousearea/mousearea.qml intro
229
230     \clearfloat
231     Many MouseArea signals pass a \l{MouseEvent}{mouse} parameter that contains
232     additional information about the mouse event, such as the position, button,
233     and any key modifiers.
234
235     Here is an extension of the previous example that produces a different
236     color when the area is right clicked:
237
238     \snippet doc/src/snippets/declarative/mousearea/mousearea.qml intro-extended
239
240     \sa MouseEvent, {declarative/touchinteraction/mousearea}{MouseArea example}
241 */
242
243 /*!
244     \qmlsignal MouseArea::onEntered()
245
246     This handler is called when the mouse enters the mouse area.
247
248     By default the onEntered handler is only called while a button is
249     pressed. Setting hoverEnabled to true enables handling of
250     onEntered when no mouse button is pressed.
251
252     \sa hoverEnabled
253 */
254
255 /*!
256     \qmlsignal MouseArea::onExited()
257
258     This handler is called when the mouse exists the mouse area.
259
260     By default the onExited handler is only called while a button is
261     pressed. Setting hoverEnabled to true enables handling of
262     onExited when no mouse button is pressed.
263
264     \sa hoverEnabled
265 */
266
267 /*!
268     \qmlsignal MouseArea::onPositionChanged(MouseEvent mouse)
269
270     This handler is called when the mouse position changes.
271
272     The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
273     position, and any buttons currently pressed.
274
275     The \e accepted property of the MouseEvent parameter is ignored in this handler.
276
277     By default the onPositionChanged handler is only called while a button is
278     pressed.  Setting hoverEnabled to true enables handling of
279     onPositionChanged when no mouse button is pressed.
280 */
281
282 /*!
283     \qmlsignal MouseArea::onClicked(MouseEvent mouse)
284
285     This handler is called when there is a click. A click is defined as a press followed by a release,
286     both inside the MouseArea (pressing, moving outside the MouseArea, and then moving back inside and
287     releasing is also considered a click).
288
289     The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
290     position of the release of the click, and whether the click was held.
291
292     The \e accepted property of the MouseEvent parameter is ignored in this handler.
293 */
294
295 /*!
296     \qmlsignal MouseArea::onPressed(MouseEvent mouse)
297
298     This handler is called when there is a press.
299     The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
300     position and which button was pressed.
301
302     The \e accepted property of the MouseEvent parameter determines whether this MouseArea
303     will handle the press and all future mouse events until release.  The default is to accept
304     the event and not allow other MouseArea beneath this one to handle the event.  If \e accepted
305     is set to false, no further events will be sent to this MouseArea until the button is next
306     pressed.
307 */
308
309 /*!
310     \qmlsignal MouseArea::onReleased(MouseEvent mouse)
311
312     This handler is called when there is a release.
313     The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
314     position of the release of the click, and whether the click was held.
315
316     The \e accepted property of the MouseEvent parameter is ignored in this handler.
317
318     \sa onCanceled
319 */
320
321 /*!
322     \qmlsignal MouseArea::onPressAndHold(MouseEvent mouse)
323
324     This handler is called when there is a long press (currently 800ms).
325     The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
326     position of the press, and which button is pressed.
327
328     The \e accepted property of the MouseEvent parameter is ignored in this handler.
329 */
330
331 /*!
332     \qmlsignal MouseArea::onDoubleClicked(MouseEvent mouse)
333
334     This handler is called when there is a double-click (a press followed by a release followed by a press).
335     The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
336     position of the release of the click, and whether the click was held.
337
338     If the \e accepted property of the \l {MouseEvent}{mouse} parameter is set to false
339     in the handler, the onPressed/onReleased/onClicked handlers will be called for the second
340     click; otherwise they are suppressed.  The accepted property defaults to true.
341 */
342
343 /*!
344     \qmlsignal MouseArea::onCanceled()
345
346     This handler is called when mouse events have been canceled, either because an event was not accepted, or
347     because another element stole the mouse event handling.
348
349     This signal is for advanced use: it is useful when there is more than one MouseArea
350     that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter
351     case, if you execute some logic on the pressed signal and then start dragging, the
352     \l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset
353     the logic when the MouseArea has lost the mouse handling to the \l Flickable,
354     \c onCanceled should be used in addition to onReleased.
355 */
356
357 QDeclarativeMouseArea::QDeclarativeMouseArea(QDeclarativeItem *parent)
358   : QDeclarativeItem(*(new QDeclarativeMouseAreaPrivate), parent)
359 {
360     Q_D(QDeclarativeMouseArea);
361     d->init();
362 }
363
364 QDeclarativeMouseArea::~QDeclarativeMouseArea()
365 {
366 }
367
368 /*!
369     \qmlproperty real MouseArea::mouseX
370     \qmlproperty real MouseArea::mouseY
371     These properties hold the coordinates of the mouse cursor.
372
373     If the hoverEnabled property is false then these properties will only be valid
374     while a button is pressed, and will remain valid as long as the button is held
375     down even if the mouse is moved outside the area.
376
377     By default, this property is false.
378
379     If hoverEnabled is true then these properties will be valid when:
380     \list
381         \i no button is pressed, but the mouse is within the MouseArea (containsMouse is true).
382         \i a button is pressed and held, even if it has since moved out of the area.
383     \endlist
384
385     The coordinates are relative to the MouseArea.
386 */
387 qreal QDeclarativeMouseArea::mouseX() const
388 {
389     Q_D(const QDeclarativeMouseArea);
390     return d->lastPos.x();
391 }
392
393 qreal QDeclarativeMouseArea::mouseY() const
394 {
395     Q_D(const QDeclarativeMouseArea);
396     return d->lastPos.y();
397 }
398
399 /*!
400     \qmlproperty bool MouseArea::enabled
401     This property holds whether the item accepts mouse events.
402
403     By default, this property is true.
404 */
405 bool QDeclarativeMouseArea::isEnabled() const
406 {
407     Q_D(const QDeclarativeMouseArea);
408     return d->absorb;
409 }
410
411 void QDeclarativeMouseArea::setEnabled(bool a)
412 {
413     Q_D(QDeclarativeMouseArea);
414     if (a != d->absorb) {
415         d->absorb = a;
416         emit enabledChanged();
417     }
418 }
419
420 /*!
421     \qmlproperty bool MouseArea::preventStealing
422     \since Quick 1.1
423     This property holds whether the mouse events may be stolen from this
424     MouseArea.
425
426     If a MouseArea is placed within an item that filters child mouse
427     events, such as Flickable, the mouse
428     events may be stolen from the MouseArea if a gesture is recognized
429     by the parent element, e.g. a flick gesture.  If preventStealing is
430     set to true, no element will steal the mouse events.
431
432     Note that setting preventStealing to true once an element has started
433     stealing events will have no effect until the next press event.
434
435     By default this property is false.
436 */
437 bool QDeclarativeMouseArea::preventStealing() const
438 {
439     Q_D(const QDeclarativeMouseArea);
440     return d->preventStealing;
441 }
442
443 void QDeclarativeMouseArea::setPreventStealing(bool prevent)
444 {
445     Q_D(QDeclarativeMouseArea);
446     if (prevent != d->preventStealing) {
447         d->preventStealing = prevent;
448         setKeepMouseGrab(d->preventStealing && d->absorb);
449         emit preventStealingChanged();
450     }
451 }
452
453 /*!
454     \qmlproperty MouseButtons MouseArea::pressedButtons
455     This property holds the mouse buttons currently pressed.
456
457     It contains a bitwise combination of:
458     \list
459     \o Qt.LeftButton
460     \o Qt.RightButton
461     \o Qt.MiddleButton
462     \endlist
463
464     The code below displays "right" when the right mouse buttons is pressed:
465
466     \snippet doc/src/snippets/declarative/mousearea/mousearea.qml mousebuttons
467
468     \sa acceptedButtons
469 */
470 Qt::MouseButtons QDeclarativeMouseArea::pressedButtons() const
471 {
472     Q_D(const QDeclarativeMouseArea);
473     return d->lastButtons;
474 }
475
476 void QDeclarativeMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
477 {
478     Q_D(QDeclarativeMouseArea);
479     d->moved = false;
480     d->stealMouse = d->preventStealing;
481     if (!d->absorb)
482         QDeclarativeItem::mousePressEvent(event);
483     else {
484         d->longPress = false;
485         d->saveEvent(event);
486         if (d->drag) {
487             d->dragX = drag()->axis() & QDeclarativeDrag::XAxis;
488             d->dragY = drag()->axis() & QDeclarativeDrag::YAxis;
489         }
490         if (d->drag)
491             d->drag->setActive(false);
492         setHovered(true);
493         d->startScene = event->scenePos();
494         // we should only start timer if pressAndHold is connected to.
495         if (d->isPressAndHoldConnected())
496             d->pressAndHoldTimer.start(PressAndHoldDelay, this);
497         setKeepMouseGrab(d->stealMouse);
498         event->setAccepted(setPressed(true));
499     }
500 }
501
502 void QDeclarativeMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
503 {
504     Q_D(QDeclarativeMouseArea);
505     if (!d->absorb) {
506         QDeclarativeItem::mouseMoveEvent(event);
507         return;
508     }
509
510     d->saveEvent(event);
511
512     // ### we should skip this if these signals aren't used
513     // ### can GV handle this for us?
514     bool contains = boundingRect().contains(d->lastPos);
515     if (d->hovered && !contains)
516         setHovered(false);
517     else if (!d->hovered && contains)
518         setHovered(true);
519
520     if (d->drag && d->drag->target()) {
521         if (!d->moved) {
522             d->startX = drag()->target()->x();
523             d->startY = drag()->target()->y();
524         }
525
526         QPointF startLocalPos;
527         QPointF curLocalPos;
528         if (drag()->target()->parentItem()) {
529             startLocalPos = drag()->target()->parentItem()->mapFromScene(d->startScene);
530             curLocalPos = drag()->target()->parentItem()->mapFromScene(event->scenePos());
531         } else {
532             startLocalPos = d->startScene;
533             curLocalPos = event->scenePos();
534         }
535
536         const int dragThreshold = QApplication::startDragDistance();
537         qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
538         qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
539
540         if (keepMouseGrab() && d->stealMouse)
541             d->drag->setActive(true);
542
543         if (d->dragX && d->drag->active()) {
544             qreal x = (curLocalPos.x() - startLocalPos.x()) + d->startX;
545             if (x < drag()->xmin())
546                 x = drag()->xmin();
547             else if (x > drag()->xmax())
548                 x = drag()->xmax();
549             drag()->target()->setX(x);
550         }
551         if (d->dragY && d->drag->active()) {
552             qreal y = (curLocalPos.y() - startLocalPos.y()) + d->startY;
553             if (y < drag()->ymin())
554                 y = drag()->ymin();
555             else if (y > drag()->ymax())
556                 y = drag()->ymax();
557             drag()->target()->setY(y);
558         }
559
560         if (!keepMouseGrab()) {
561             if ((!d->dragY && dy < dragThreshold && d->dragX && dx > dragThreshold)
562                 || (!d->dragX && dx < dragThreshold && d->dragY && dy > dragThreshold)
563                 || (d->dragX && d->dragY && (dx > dragThreshold || dy > dragThreshold))) {
564                 setKeepMouseGrab(true);
565                 d->stealMouse = true;
566             }
567         }
568
569         d->moved = true;
570     }
571     QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
572     emit mousePositionChanged(&me);
573     me.setX(d->lastPos.x());
574     me.setY(d->lastPos.y());
575     emit positionChanged(&me);
576 }
577
578
579 void QDeclarativeMouseArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
580 {
581     Q_D(QDeclarativeMouseArea);
582     d->stealMouse = false;
583     if (!d->absorb) {
584         QDeclarativeItem::mouseReleaseEvent(event);
585     } else {
586         d->saveEvent(event);
587         setPressed(false);
588         if (d->drag)
589             d->drag->setActive(false);
590         // If we don't accept hover, we need to reset containsMouse.
591         if (!acceptHoverEvents())
592             setHovered(false);
593         QGraphicsScene *s = scene();
594         if (s && s->mouseGrabberItem() == this)
595             ungrabMouse();
596         setKeepMouseGrab(false);
597     }
598     d->doubleClick = false;
599 }
600
601 void QDeclarativeMouseArea::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
602 {
603     Q_D(QDeclarativeMouseArea);
604     if (!d->absorb) {
605         QDeclarativeItem::mouseDoubleClickEvent(event);
606     } else {
607         if (d->isDoubleClickConnected())
608             d->doubleClick = true;
609         d->saveEvent(event);
610         QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
611         me.setAccepted(d->isDoubleClickConnected());
612         emit this->doubleClicked(&me);
613         QDeclarativeItem::mouseDoubleClickEvent(event);
614     }
615 }
616
617 void QDeclarativeMouseArea::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
618 {
619     Q_D(QDeclarativeMouseArea);
620     if (!d->absorb)
621         QDeclarativeItem::hoverEnterEvent(event);
622     else {
623         d->lastPos = event->pos();
624         setHovered(true);
625         QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, event->modifiers(), false, false);
626         emit mousePositionChanged(&me);
627     }
628 }
629
630 void QDeclarativeMouseArea::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
631 {
632     Q_D(QDeclarativeMouseArea);
633     if (!d->absorb) {
634         QDeclarativeItem::hoverMoveEvent(event);
635     } else {
636         d->lastPos = event->pos();
637         QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, event->modifiers(), false, false);
638         emit mousePositionChanged(&me);
639         me.setX(d->lastPos.x());
640         me.setY(d->lastPos.y());
641         emit positionChanged(&me);
642     }
643 }
644
645 void QDeclarativeMouseArea::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
646 {
647     Q_D(QDeclarativeMouseArea);
648     if (!d->absorb)
649         QDeclarativeItem::hoverLeaveEvent(event);
650     else
651         setHovered(false);
652 }
653
654 #ifndef QT_NO_CONTEXTMENU
655 void QDeclarativeMouseArea::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
656 {
657     bool acceptsContextMenuButton;
658 #if defined(Q_OS_SYMBIAN)
659     // In Symbian a Long Tap on the screen will trigger. See QSymbianControl::HandleLongTapEventL().
660     acceptsContextMenuButton = acceptedButtons() & Qt::LeftButton;
661 #elif defined(Q_WS_WINCE)
662     // ### WinCE can trigger context menu event with a gesture in the left button or a
663     // click with the right button. Since we have no way here to differentiate them when
664     // event happens, accepting either of the them will block the event.
665     acceptsContextMenuButton = acceptedButtons() & (Qt::LeftButton | Qt::RightButton);
666 #else
667     acceptsContextMenuButton = acceptedButtons() & Qt::RightButton;
668 #endif
669
670     if (isEnabled() && event->reason() == QGraphicsSceneContextMenuEvent::Mouse
671         && acceptsContextMenuButton) {
672         // Do not let the context menu event propagate to items behind.
673         return;
674     }
675
676     QDeclarativeItem::contextMenuEvent(event);
677 }
678 #endif // QT_NO_CONTEXTMENU
679
680 bool QDeclarativeMouseArea::sceneEvent(QEvent *event)
681 {
682     bool rv = QDeclarativeItem::sceneEvent(event);
683     if (event->type() == QEvent::UngrabMouse) {
684         Q_D(QDeclarativeMouseArea);
685         if (d->pressed) {
686             // if our mouse grab has been removed (probably by Flickable), fix our
687             // state
688             d->pressed = false;
689             d->stealMouse = false;
690             setKeepMouseGrab(false);
691             emit canceled();
692             emit pressedChanged();
693             if (d->hovered) {
694                 d->hovered = false;
695                 emit hoveredChanged();
696             }
697         }
698     }
699     return rv;
700 }
701
702 bool QDeclarativeMouseArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
703 {
704     Q_D(QDeclarativeMouseArea);
705     QGraphicsSceneMouseEvent mouseEvent(event->type());
706     QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
707
708     QGraphicsScene *s = scene();
709     QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
710     bool stealThisEvent = d->stealMouse;
711     if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
712         mouseEvent.setAccepted(false);
713         for (int i = 0x1; i <= 0x10; i <<= 1) {
714             if (event->buttons() & i) {
715                 Qt::MouseButton button = Qt::MouseButton(i);
716                 mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
717             }
718         }
719         mouseEvent.setScenePos(event->scenePos());
720         mouseEvent.setLastScenePos(event->lastScenePos());
721         mouseEvent.setPos(mapFromScene(event->scenePos()));
722         mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
723
724         switch(mouseEvent.type()) {
725         case QEvent::GraphicsSceneMouseMove:
726             mouseMoveEvent(&mouseEvent);
727             break;
728         case QEvent::GraphicsSceneMousePress:
729             mousePressEvent(&mouseEvent);
730             break;
731         case QEvent::GraphicsSceneMouseRelease:
732             mouseReleaseEvent(&mouseEvent);
733             break;
734         default:
735             break;
736         }
737         grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
738         if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
739             grabMouse();
740
741         return stealThisEvent;
742     }
743     if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
744         if (d->pressed) {
745             d->pressed = false;
746             d->stealMouse = false;
747             if (s && s->mouseGrabberItem() == this)
748                 ungrabMouse();
749             emit canceled();
750             emit pressedChanged();
751             if (d->hovered) {
752                 d->hovered = false;
753                 emit hoveredChanged();
754             }
755         }
756     }
757     return false;
758 }
759
760 bool QDeclarativeMouseArea::sceneEventFilter(QGraphicsItem *i, QEvent *e)
761 {
762     Q_D(QDeclarativeMouseArea);
763     if (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren())
764         return QDeclarativeItem::sceneEventFilter(i, e);
765     switch (e->type()) {
766     case QEvent::GraphicsSceneMousePress:
767     case QEvent::GraphicsSceneMouseMove:
768     case QEvent::GraphicsSceneMouseRelease:
769         return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
770     default:
771         break;
772     }
773
774     return QDeclarativeItem::sceneEventFilter(i, e);
775 }
776
777 void QDeclarativeMouseArea::timerEvent(QTimerEvent *event)
778 {
779     Q_D(QDeclarativeMouseArea);
780     if (event->timerId() == d->pressAndHoldTimer.timerId()) {
781         d->pressAndHoldTimer.stop();
782         bool dragged = d->drag && d->drag->active();
783         if (d->pressed && dragged == false && d->hovered == true) {
784             d->longPress = true;
785             QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
786             emit pressAndHold(&me);
787         }
788     }
789 }
790
791 void QDeclarativeMouseArea::geometryChanged(const QRectF &newGeometry,
792                                             const QRectF &oldGeometry)
793 {
794     Q_D(QDeclarativeMouseArea);
795     QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
796
797     if (d->lastScenePos.isNull)
798         d->lastScenePos = mapToScene(d->lastPos);
799     else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
800         d->lastPos = mapFromScene(d->lastScenePos);
801 }
802
803 QVariant QDeclarativeMouseArea::itemChange(GraphicsItemChange change,
804                                        const QVariant &value)
805 {
806     Q_D(QDeclarativeMouseArea);
807     switch (change) {
808     case ItemVisibleHasChanged:
809         if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse()))
810             setHovered(!d->hovered);
811         break;
812     default:
813         break;
814     }
815
816     return QDeclarativeItem::itemChange(change, value);
817 }
818
819 /*!
820     \qmlproperty bool MouseArea::hoverEnabled
821     This property holds whether hover events are handled.
822
823     By default, mouse events are only handled in response to a button event, or when a button is
824     pressed.  Hover enables handling of all mouse events even when no mouse button is
825     pressed.
826
827     This property affects the containsMouse property and the onEntered, onExited and
828     onPositionChanged signals.
829 */
830 bool QDeclarativeMouseArea::hoverEnabled() const
831 {
832     return acceptHoverEvents();
833 }
834
835 void QDeclarativeMouseArea::setHoverEnabled(bool h)
836 {
837     Q_D(QDeclarativeMouseArea);
838     if (h == acceptHoverEvents())
839         return;
840
841     setAcceptHoverEvents(h);
842     emit hoverEnabledChanged();
843     if (d->hovered != isUnderMouse())
844         setHovered(!d->hovered);
845 }
846
847 /*!
848     \qmlproperty bool MouseArea::containsMouse
849     This property holds whether the mouse is currently inside the mouse area.
850
851     \warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
852     In addition, if hoverEnabled is false, containsMouse will only be valid when the mouse is pressed.
853 */
854 bool QDeclarativeMouseArea::hovered() const
855 {
856     Q_D(const QDeclarativeMouseArea);
857     return d->hovered;
858 }
859
860 /*!
861     \qmlproperty bool MouseArea::pressed
862     This property holds whether the mouse area is currently pressed.
863 */
864 bool QDeclarativeMouseArea::pressed() const
865 {
866     Q_D(const QDeclarativeMouseArea);
867     return d->pressed;
868 }
869
870 void QDeclarativeMouseArea::setHovered(bool h)
871 {
872     Q_D(QDeclarativeMouseArea);
873     if (d->hovered != h) {
874         d->hovered = h;
875         emit hoveredChanged();
876         d->hovered ? emit entered() : emit exited();
877     }
878 }
879
880 /*!
881     \qmlproperty Qt::MouseButtons MouseArea::acceptedButtons
882     This property holds the mouse buttons that the mouse area reacts to.
883
884     The available buttons are:
885     \list
886     \o Qt.LeftButton
887     \o Qt.RightButton
888     \o Qt.MiddleButton
889     \endlist
890
891     To accept more than one button the flags can be combined with the
892     "|" (or) operator:
893
894     \code
895     MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
896     \endcode
897
898     The default value is \c Qt.LeftButton.
899 */
900 Qt::MouseButtons QDeclarativeMouseArea::acceptedButtons() const
901 {
902     return acceptedMouseButtons();
903 }
904
905 void QDeclarativeMouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
906 {
907     if (buttons != acceptedMouseButtons()) {
908         setAcceptedMouseButtons(buttons);
909         emit acceptedButtonsChanged();
910     }
911 }
912
913 bool QDeclarativeMouseArea::setPressed(bool p)
914 {
915     Q_D(QDeclarativeMouseArea);
916     bool dragged = d->drag && d->drag->active();
917     bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
918
919     if (d->pressed != p) {
920         d->pressed = p;
921         QDeclarativeMouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
922         if (d->pressed) {
923             if (!d->doubleClick)
924                 emit pressed(&me);
925             me.setX(d->lastPos.x());
926             me.setY(d->lastPos.y());
927             emit mousePositionChanged(&me);
928             emit pressedChanged();
929         } else {
930             emit released(&me);
931             me.setX(d->lastPos.x());
932             me.setY(d->lastPos.y());
933             emit pressedChanged();
934             if (isclick && !d->longPress && !d->doubleClick)
935                 emit clicked(&me);
936         }
937
938         return me.isAccepted();
939     }
940     return false;
941 }
942
943 QDeclarativeDrag *QDeclarativeMouseArea::drag()
944 {
945     Q_D(QDeclarativeMouseArea);
946     if (!d->drag)
947         d->drag = new QDeclarativeDrag;
948     return d->drag;
949 }
950
951 /*!
952     \qmlproperty Item MouseArea::drag.target
953     \qmlproperty bool MouseArea::drag.active
954     \qmlproperty enumeration MouseArea::drag.axis
955     \qmlproperty real MouseArea::drag.minimumX
956     \qmlproperty real MouseArea::drag.maximumX
957     \qmlproperty real MouseArea::drag.minimumY
958     \qmlproperty real MouseArea::drag.maximumY
959     \qmlproperty bool MouseArea::drag.filterChildren
960
961     \c drag provides a convenient way to make an item draggable.
962
963     \list
964     \i \c drag.target specifies the id of the item to drag.
965     \i \c drag.active specifies if the target item is currently being dragged.
966     \i \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XandYAxis)
967     \i \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
968     \endlist
969
970     The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
971     of the rectangle is reduced when it is dragged to the right.
972
973     \snippet doc/src/snippets/declarative/mousearea/mousearea.qml drag
974
975     \note Items cannot be dragged if they are anchored for the requested 
976     \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
977     for \c rect in the above example, it cannot be dragged along the X-axis.
978     This can be avoided by settng the anchor value to \c undefined in 
979     an \l onPressed handler.
980
981     If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas.  This
982     enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
983
984     \snippet doc/src/snippets/declarative/mousearea/mouseareadragfilter.qml dragfilter
985
986 */
987
988 QT_END_NAMESPACE