Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / qtquick1 / graphicsitems / qdeclarativemousearea.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
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/qtquick1/mousearea/mousearea.qml import
230     \codeline
231     \snippet doc/src/snippets/qtquick1/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/qtquick1/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/qtquick1/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_WS_WINCE)
688     // ### WinCE can trigger context menu event with a gesture in the left button or a
689     // click with the right button. Since we have no way here to differentiate them when
690     // event happens, accepting either of the them will block the event.
691     acceptsContextMenuButton = acceptedButtons() & (Qt::LeftButton | Qt::RightButton);
692 #else
693     acceptsContextMenuButton = acceptedButtons() & Qt::RightButton;
694 #endif
695
696     if (isEnabled() && event->reason() == QGraphicsSceneContextMenuEvent::Mouse
697         && acceptsContextMenuButton) {
698         // Do not let the context menu event propagate to items behind.
699         return;
700     }
701
702     QDeclarativeItem::contextMenuEvent(event);
703 }
704 #endif // QT_NO_CONTEXTMENU
705
706 bool QDeclarative1MouseArea::sceneEvent(QEvent *event)
707 {
708     bool rv = QDeclarativeItem::sceneEvent(event);
709     if (event->type() == QEvent::UngrabMouse) {
710         Q_D(QDeclarative1MouseArea);
711         if (d->pressed) {
712             // if our mouse grab has been removed (probably by Flickable), fix our
713             // state
714             d->pressed = false;
715             d->stealMouse = false;
716             setKeepMouseGrab(false);
717             emit canceled();
718             emit pressedChanged();
719             if (d->hovered) {
720                 d->hovered = false;
721                 emit hoveredChanged();
722             }
723         }
724     }
725     return rv;
726 }
727
728 bool QDeclarative1MouseArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
729 {
730     Q_D(QDeclarative1MouseArea);
731     QGraphicsSceneMouseEvent mouseEvent(event->type());
732     QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
733
734     QGraphicsScene *s = scene();
735     QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
736     bool stealThisEvent = d->stealMouse;
737     if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
738         mouseEvent.setAccepted(false);
739         for (int i = 0x1; i <= 0x10; i <<= 1) {
740             if (event->buttons() & i) {
741                 Qt::MouseButton button = Qt::MouseButton(i);
742                 mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
743             }
744         }
745         mouseEvent.setScenePos(event->scenePos());
746         mouseEvent.setLastScenePos(event->lastScenePos());
747         mouseEvent.setPos(mapFromScene(event->scenePos()));
748         mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
749
750         switch(mouseEvent.type()) {
751         case QEvent::GraphicsSceneMouseMove:
752             mouseMoveEvent(&mouseEvent);
753             break;
754         case QEvent::GraphicsSceneMousePress:
755             mousePressEvent(&mouseEvent);
756             break;
757         case QEvent::GraphicsSceneMouseRelease:
758             mouseReleaseEvent(&mouseEvent);
759             break;
760         default:
761             break;
762         }
763         grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
764         if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
765             grabMouse();
766
767         return stealThisEvent;
768     }
769     if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
770         if (d->pressed) {
771             d->pressed = false;
772             d->stealMouse = false;
773             if (s && s->mouseGrabberItem() == this)
774                 ungrabMouse();
775             emit canceled();
776             emit pressedChanged();
777             if (d->hovered) {
778                 d->hovered = false;
779                 emit hoveredChanged();
780             }
781         }
782     }
783     return false;
784 }
785
786 bool QDeclarative1MouseArea::sceneEventFilter(QGraphicsItem *i, QEvent *e)
787 {
788     Q_D(QDeclarative1MouseArea);
789     if (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren())
790         return QDeclarativeItem::sceneEventFilter(i, e);
791     switch (e->type()) {
792     case QEvent::GraphicsSceneMousePress:
793     case QEvent::GraphicsSceneMouseMove:
794     case QEvent::GraphicsSceneMouseRelease:
795         return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
796     default:
797         break;
798     }
799
800     return QDeclarativeItem::sceneEventFilter(i, e);
801 }
802
803 void QDeclarative1MouseArea::timerEvent(QTimerEvent *event)
804 {
805     Q_D(QDeclarative1MouseArea);
806     if (event->timerId() == d->pressAndHoldTimer.timerId()) {
807         d->pressAndHoldTimer.stop();
808         bool dragged = d->drag && d->drag->active();
809         if (d->pressed && dragged == false && d->hovered == true) {
810             d->longPress = true;
811             QDeclarative1MouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
812             emit pressAndHold(&me);
813         }
814     }
815 }
816
817 void QDeclarative1MouseArea::geometryChanged(const QRectF &newGeometry,
818                                             const QRectF &oldGeometry)
819 {
820     Q_D(QDeclarative1MouseArea);
821     QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
822
823     if (d->lastScenePos.isNull)
824         d->lastScenePos = mapToScene(d->lastPos);
825     else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
826         d->lastPos = mapFromScene(d->lastScenePos);
827 }
828
829 QVariant QDeclarative1MouseArea::itemChange(GraphicsItemChange change,
830                                        const QVariant &value)
831 {
832     Q_D(QDeclarative1MouseArea);
833     switch (change) {
834     case ItemVisibleHasChanged:
835         if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse()))
836             setHovered(!d->hovered);
837         break;
838     default:
839         break;
840     }
841
842     return QDeclarativeItem::itemChange(change, value);
843 }
844
845 /*!
846     \qmlproperty bool QtQuick1::MouseArea::hoverEnabled
847     This property holds whether hover events are handled.
848
849     By default, mouse events are only handled in response to a button event, or when a button is
850     pressed.  Hover enables handling of all mouse events even when no mouse button is
851     pressed.
852
853     This property affects the containsMouse property and the onEntered, onExited and
854     onPositionChanged signals.
855 */
856 bool QDeclarative1MouseArea::hoverEnabled() const
857 {
858     return acceptHoverEvents();
859 }
860
861 void QDeclarative1MouseArea::setHoverEnabled(bool h)
862 {
863     Q_D(QDeclarative1MouseArea);
864     if (h == acceptHoverEvents())
865         return;
866
867     setAcceptHoverEvents(h);
868     emit hoverEnabledChanged();
869     if (d->hovered != isUnderMouse())
870         setHovered(!d->hovered);
871 }
872
873 /*!
874     \qmlproperty bool QtQuick1::MouseArea::containsMouse
875     This property holds whether the mouse is currently inside the mouse area.
876
877     \warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
878     In addition, if hoverEnabled is false, containsMouse will only be valid when the mouse is pressed.
879 */
880 bool QDeclarative1MouseArea::hovered() const
881 {
882     Q_D(const QDeclarative1MouseArea);
883     return d->hovered;
884 }
885
886 /*!
887     \qmlproperty bool QtQuick1::MouseArea::pressed
888     This property holds whether the mouse area is currently pressed.
889 */
890 bool QDeclarative1MouseArea::pressed() const
891 {
892     Q_D(const QDeclarative1MouseArea);
893     return d->pressed;
894 }
895
896 void QDeclarative1MouseArea::setHovered(bool h)
897 {
898     Q_D(QDeclarative1MouseArea);
899     if (d->hovered != h) {
900         d->hovered = h;
901         emit hoveredChanged();
902         d->hovered ? emit entered() : emit exited();
903     }
904 }
905
906 /*!
907     \qmlproperty QtQuick1::Qt::MouseButtons MouseArea::acceptedButtons
908     This property holds the mouse buttons that the mouse area reacts to.
909
910     The available buttons are:
911     \list
912     \o Qt.LeftButton
913     \o Qt.RightButton
914     \o Qt.MiddleButton
915     \endlist
916
917     To accept more than one button the flags can be combined with the
918     "|" (or) operator:
919
920     \code
921     MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
922     \endcode
923
924     The default value is \c Qt.LeftButton.
925 */
926 Qt::MouseButtons QDeclarative1MouseArea::acceptedButtons() const
927 {
928     return acceptedMouseButtons();
929 }
930
931 void QDeclarative1MouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
932 {
933     if (buttons != acceptedMouseButtons()) {
934         setAcceptedMouseButtons(buttons);
935         emit acceptedButtonsChanged();
936     }
937 }
938
939 bool QDeclarative1MouseArea::setPressed(bool p)
940 {
941     Q_D(QDeclarative1MouseArea);
942     bool dragged = d->drag && d->drag->active();
943     bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
944
945     if (d->pressed != p) {
946         d->pressed = p;
947         QDeclarative1MouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
948         if (d->pressed) {
949             if (!d->doubleClick)
950                 emit pressed(&me);
951             me.setX(d->lastPos.x());
952             me.setY(d->lastPos.y());
953             emit mousePositionChanged(&me);
954             emit pressedChanged();
955         } else {
956             emit released(&me);
957             me.setX(d->lastPos.x());
958             me.setY(d->lastPos.y());
959             emit pressedChanged();
960             if (isclick && !d->longPress && !d->doubleClick)
961                 emit clicked(&me);
962         }
963
964         return me.isAccepted();
965     }
966     return false;
967 }
968
969 QDeclarative1Drag *QDeclarative1MouseArea::drag()
970 {
971     Q_D(QDeclarative1MouseArea);
972     if (!d->drag)
973         d->drag = new QDeclarative1Drag;
974     return d->drag;
975 }
976
977 /*!
978     \qmlproperty Item QtQuick1::MouseArea::drag.target
979     \qmlproperty bool QtQuick1::MouseArea::drag.active
980     \qmlproperty enumeration QtQuick1::MouseArea::drag.axis
981     \qmlproperty real QtQuick1::MouseArea::drag.minimumX
982     \qmlproperty real QtQuick1::MouseArea::drag.maximumX
983     \qmlproperty real QtQuick1::MouseArea::drag.minimumY
984     \qmlproperty real QtQuick1::MouseArea::drag.maximumY
985     \qmlproperty bool QtQuick1::MouseArea::drag.filterChildren
986
987     \c drag provides a convenient way to make an item draggable.
988
989     \list
990     \i \c drag.target specifies the id of the item to drag.
991     \i \c drag.active specifies if the target item is currently being dragged.
992     \i \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XandYAxis)
993     \i \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
994     \endlist
995
996     The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
997     of the rectangle is reduced when it is dragged to the right.
998
999     \snippet doc/src/snippets/qtquick1/mousearea/mousearea.qml drag
1000
1001     \note Items cannot be dragged if they are anchored for the requested 
1002     \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
1003     for \c rect in the above example, it cannot be dragged along the X-axis.
1004     This can be avoided by settng the anchor value to \c undefined in 
1005     an \l onPressed handler.
1006
1007     If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas.  This
1008     enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
1009
1010     \snippet doc/src/snippets/qtquick1/mousearea/mouseareadragfilter.qml dragfilter
1011
1012 */
1013
1014 QT_END_NAMESPACE