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