Bulk update of QtQuick 1 docs to \qmlmodule syntax
[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 exists 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     \sa hoverEnabled
268 */
269
270 /*!
271     \qmlsignal QtQuick1::MouseArea::onPositionChanged(MouseEvent mouse)
272
273     This handler is called when the mouse position changes.
274
275     The \l {MouseEvent}{mouse} parameter provides information about the mouse, including the x and y
276     position, and any buttons currently pressed.
277
278     The \e accepted property of the MouseEvent parameter is ignored in this handler.
279
280     By default the onPositionChanged handler is only called while a button is
281     pressed.  Setting hoverEnabled to true enables handling of
282     onPositionChanged when no mouse button is pressed.
283 */
284
285 /*!
286     \qmlsignal QtQuick1::MouseArea::onClicked(MouseEvent mouse)
287
288     This handler is called when there is a click. A click is defined as a press followed by a release,
289     both inside the MouseArea (pressing, moving outside the MouseArea, and then moving back inside and
290     releasing is also considered a click).
291
292     The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
293     position of the release of the click, and whether the click was held.
294
295     The \e accepted property of the MouseEvent parameter is ignored in this handler.
296 */
297
298 /*!
299     \qmlsignal QtQuick1::MouseArea::onPressed(MouseEvent mouse)
300
301     This handler is called when there is a press.
302     The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
303     position and which button was pressed.
304
305     The \e accepted property of the MouseEvent parameter determines whether this MouseArea
306     will handle the press and all future mouse events until release.  The default is to accept
307     the event and not allow other MouseArea beneath this one to handle the event.  If \e accepted
308     is set to false, no further events will be sent to this MouseArea until the button is next
309     pressed.
310 */
311
312 /*!
313     \qmlsignal QtQuick1::MouseArea::onReleased(MouseEvent mouse)
314
315     This handler is called when there is a release.
316     The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
317     position of the release of the click, and whether the click was held.
318
319     The \e accepted property of the MouseEvent parameter is ignored in this handler.
320
321     \sa onCanceled
322 */
323
324 /*!
325     \qmlsignal QtQuick1::MouseArea::onPressAndHold(MouseEvent mouse)
326
327     This handler is called when there is a long press (currently 800ms).
328     The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
329     position of the press, and which button is pressed.
330
331     The \e accepted property of the MouseEvent parameter is ignored in this handler.
332 */
333
334 /*!
335     \qmlsignal QtQuick1::MouseArea::onDoubleClicked(MouseEvent mouse)
336
337     This handler is called when there is a double-click (a press followed by a release followed by a press).
338     The \l {MouseEvent}{mouse} parameter provides information about the click, including the x and y
339     position of the release of the click, and whether the click was held.
340
341     If the \e accepted property of the \l {MouseEvent}{mouse} parameter is set to false
342     in the handler, the onPressed/onReleased/onClicked handlers will be called for the second
343     click; otherwise they are suppressed.  The accepted property defaults to true.
344 */
345
346 /*!
347     \qmlsignal QtQuick1::MouseArea::onCanceled()
348
349     This handler is called when mouse events have been canceled, either because an event was not accepted, or
350     because another element stole the mouse event handling.
351
352     This signal is for advanced use: it is useful when there is more than one MouseArea
353     that is handling input, or when there is a MouseArea inside a \l Flickable. In the latter
354     case, if you execute some logic on the pressed signal and then start dragging, the
355     \l Flickable will steal the mouse handling from the MouseArea. In these cases, to reset
356     the logic when the MouseArea has lost the mouse handling to the \l Flickable,
357     \c onCanceled should be used in addition to onReleased.
358 */
359
360 QDeclarative1MouseArea::QDeclarative1MouseArea(QDeclarativeItem *parent)
361   : QDeclarativeItem(*(new QDeclarative1MouseAreaPrivate), parent)
362 {
363     Q_D(QDeclarative1MouseArea);
364     d->init();
365 }
366
367 QDeclarative1MouseArea::~QDeclarative1MouseArea()
368 {
369 }
370
371 /*!
372     \qmlproperty real QtQuick1::MouseArea::mouseX
373     \qmlproperty real QtQuick1::MouseArea::mouseY
374     These properties hold the coordinates of the mouse cursor.
375
376     If the hoverEnabled property is false then these properties will only be valid
377     while a button is pressed, and will remain valid as long as the button is held
378     down even if the mouse is moved outside the area.
379
380     By default, this property is false.
381
382     If hoverEnabled is true then these properties will be valid when:
383     \list
384         \i no button is pressed, but the mouse is within the MouseArea (containsMouse is true).
385         \i a button is pressed and held, even if it has since moved out of the area.
386     \endlist
387
388     The coordinates are relative to the MouseArea.
389 */
390 qreal QDeclarative1MouseArea::mouseX() const
391 {
392     Q_D(const QDeclarative1MouseArea);
393     return d->lastPos.x();
394 }
395
396 qreal QDeclarative1MouseArea::mouseY() const
397 {
398     Q_D(const QDeclarative1MouseArea);
399     return d->lastPos.y();
400 }
401
402 /*!
403     \qmlproperty bool QtQuick1::MouseArea::enabled
404     This property holds whether the item accepts mouse events.
405
406     By default, this property is true.
407 */
408 bool QDeclarative1MouseArea::isEnabled() const
409 {
410     Q_D(const QDeclarative1MouseArea);
411     return d->absorb;
412 }
413
414 void QDeclarative1MouseArea::setEnabled(bool a)
415 {
416     Q_D(QDeclarative1MouseArea);
417     if (a != d->absorb) {
418         d->absorb = a;
419         emit enabledChanged();
420     }
421 }
422
423 /*!
424     \qmlproperty bool QtQuick1::MouseArea::preventStealing
425     \since Quick 1.1
426     This property holds whether the mouse events may be stolen from this
427     MouseArea.
428
429     If a MouseArea is placed within an item that filters child mouse
430     events, such as Flickable, the mouse
431     events may be stolen from the MouseArea if a gesture is recognized
432     by the parent element, e.g. a flick gesture.  If preventStealing is
433     set to true, no element will steal the mouse events.
434
435     Note that setting preventStealing to true once an element has started
436     stealing events will have no effect until the next press event.
437
438     By default this property is false.
439 */
440 bool QDeclarative1MouseArea::preventStealing() const
441 {
442     Q_D(const QDeclarative1MouseArea);
443     return d->preventStealing;
444 }
445
446 void QDeclarative1MouseArea::setPreventStealing(bool prevent)
447 {
448     Q_D(QDeclarative1MouseArea);
449     if (prevent != d->preventStealing) {
450         d->preventStealing = prevent;
451         setKeepMouseGrab(d->preventStealing && d->absorb);
452         emit preventStealingChanged();
453     }
454 }
455
456 /*!
457     \qmlproperty MouseButtons QtQuick1::MouseArea::pressedButtons
458     This property holds the mouse buttons currently pressed.
459
460     It contains a bitwise combination of:
461     \list
462     \o Qt.LeftButton
463     \o Qt.RightButton
464     \o Qt.MiddleButton
465     \endlist
466
467     The code below displays "right" when the right mouse buttons is pressed:
468
469     \snippet doc/src/snippets/declarative/mousearea/mousearea.qml mousebuttons
470
471     \sa acceptedButtons
472 */
473 Qt::MouseButtons QDeclarative1MouseArea::pressedButtons() const
474 {
475     Q_D(const QDeclarative1MouseArea);
476     return d->lastButtons;
477 }
478
479 void QDeclarative1MouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event)
480 {
481     Q_D(QDeclarative1MouseArea);
482     d->moved = false;
483     d->stealMouse = d->preventStealing;
484     if (!d->absorb)
485         QDeclarativeItem::mousePressEvent(event);
486     else {
487         d->longPress = false;
488         d->saveEvent(event);
489         if (d->drag) {
490             d->dragX = drag()->axis() & QDeclarative1Drag::XAxis;
491             d->dragY = drag()->axis() & QDeclarative1Drag::YAxis;
492         }
493         if (d->drag)
494             d->drag->setActive(false);
495         setHovered(true);
496         d->startScene = event->scenePos();
497         // we should only start timer if pressAndHold is connected to.
498         if (d->isPressAndHoldConnected())
499             d->pressAndHoldTimer.start(PressAndHoldDelay, this);
500         setKeepMouseGrab(d->stealMouse);
501         event->setAccepted(setPressed(true));
502     }
503 }
504
505 void QDeclarative1MouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
506 {
507     Q_D(QDeclarative1MouseArea);
508     if (!d->absorb) {
509         QDeclarativeItem::mouseMoveEvent(event);
510         return;
511     }
512
513     d->saveEvent(event);
514
515     // ### we should skip this if these signals aren't used
516     // ### can GV handle this for us?
517     bool contains = boundingRect().contains(d->lastPos);
518     if (d->hovered && !contains)
519         setHovered(false);
520     else if (!d->hovered && contains)
521         setHovered(true);
522
523     if (d->drag && d->drag->target()) {
524         if (!d->moved) {
525             d->startX = drag()->target()->x();
526             d->startY = drag()->target()->y();
527         }
528
529         QPointF startLocalPos;
530         QPointF curLocalPos;
531         if (drag()->target()->parentItem()) {
532             startLocalPos = drag()->target()->parentItem()->mapFromScene(d->startScene);
533             curLocalPos = drag()->target()->parentItem()->mapFromScene(event->scenePos());
534         } else {
535             startLocalPos = d->startScene;
536             curLocalPos = event->scenePos();
537         }
538
539         const int dragThreshold = QApplication::startDragDistance();
540         qreal dx = qAbs(curLocalPos.x() - startLocalPos.x());
541         qreal dy = qAbs(curLocalPos.y() - startLocalPos.y());
542
543         if (keepMouseGrab() && d->stealMouse)
544             d->drag->setActive(true);
545
546         if (d->dragX && d->drag->active()) {
547             qreal x = (curLocalPos.x() - startLocalPos.x()) + d->startX;
548             if (x < drag()->xmin())
549                 x = drag()->xmin();
550             else if (x > drag()->xmax())
551                 x = drag()->xmax();
552             drag()->target()->setX(x);
553         }
554         if (d->dragY && d->drag->active()) {
555             qreal y = (curLocalPos.y() - startLocalPos.y()) + d->startY;
556             if (y < drag()->ymin())
557                 y = drag()->ymin();
558             else if (y > drag()->ymax())
559                 y = drag()->ymax();
560             drag()->target()->setY(y);
561         }
562
563         if (!keepMouseGrab()) {
564             if ((!d->dragY && dy < dragThreshold && d->dragX && dx > dragThreshold)
565                 || (!d->dragX && dx < dragThreshold && d->dragY && dy > dragThreshold)
566                 || (d->dragX && d->dragY && (dx > dragThreshold || dy > dragThreshold))) {
567                 setKeepMouseGrab(true);
568                 d->stealMouse = true;
569             }
570         }
571
572         d->moved = true;
573     }
574     QDeclarative1MouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
575     emit mousePositionChanged(&me);
576     me.setX(d->lastPos.x());
577     me.setY(d->lastPos.y());
578     emit positionChanged(&me);
579 }
580
581
582 void QDeclarative1MouseArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
583 {
584     Q_D(QDeclarative1MouseArea);
585     d->stealMouse = false;
586     if (!d->absorb) {
587         QDeclarativeItem::mouseReleaseEvent(event);
588     } else {
589         d->saveEvent(event);
590         setPressed(false);
591         if (d->drag)
592             d->drag->setActive(false);
593         // If we don't accept hover, we need to reset containsMouse.
594         if (!acceptHoverEvents())
595             setHovered(false);
596         QGraphicsScene *s = scene();
597         if (s && s->mouseGrabberItem() == this)
598             ungrabMouse();
599         setKeepMouseGrab(false);
600     }
601     d->doubleClick = false;
602 }
603
604 void QDeclarative1MouseArea::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
605 {
606     Q_D(QDeclarative1MouseArea);
607     if (!d->absorb) {
608         QDeclarativeItem::mouseDoubleClickEvent(event);
609     } else {
610         if (d->isDoubleClickConnected())
611             d->doubleClick = true;
612         d->saveEvent(event);
613         QDeclarative1MouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, true, false);
614         me.setAccepted(d->isDoubleClickConnected());
615         emit this->doubleClicked(&me);
616         QDeclarativeItem::mouseDoubleClickEvent(event);
617     }
618 }
619
620 void QDeclarative1MouseArea::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
621 {
622     Q_D(QDeclarative1MouseArea);
623     if (!d->absorb)
624         QDeclarativeItem::hoverEnterEvent(event);
625     else {
626         d->lastPos = event->pos();
627         setHovered(true);
628         QDeclarative1MouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, event->modifiers(), false, false);
629         emit mousePositionChanged(&me);
630     }
631 }
632
633 void QDeclarative1MouseArea::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
634 {
635     Q_D(QDeclarative1MouseArea);
636     if (!d->absorb) {
637         QDeclarativeItem::hoverMoveEvent(event);
638     } else {
639         d->lastPos = event->pos();
640         QDeclarative1MouseEvent me(d->lastPos.x(), d->lastPos.y(), Qt::NoButton, Qt::NoButton, event->modifiers(), false, false);
641         emit mousePositionChanged(&me);
642         me.setX(d->lastPos.x());
643         me.setY(d->lastPos.y());
644         emit positionChanged(&me);
645     }
646 }
647
648 void QDeclarative1MouseArea::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
649 {
650     Q_D(QDeclarative1MouseArea);
651     if (!d->absorb)
652         QDeclarativeItem::hoverLeaveEvent(event);
653     else
654         setHovered(false);
655 }
656
657 #ifndef QT_NO_CONTEXTMENU
658 void QDeclarative1MouseArea::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
659 {
660     bool acceptsContextMenuButton;
661 #if defined(Q_OS_SYMBIAN)
662     // In Symbian a Long Tap on the screen will trigger. See QSymbianControl::HandleLongTapEventL().
663     acceptsContextMenuButton = acceptedButtons() & Qt::LeftButton;
664 #elif defined(Q_WS_WINCE)
665     // ### WinCE can trigger context menu event with a gesture in the left button or a
666     // click with the right button. Since we have no way here to differentiate them when
667     // event happens, accepting either of the them will block the event.
668     acceptsContextMenuButton = acceptedButtons() & (Qt::LeftButton | Qt::RightButton);
669 #else
670     acceptsContextMenuButton = acceptedButtons() & Qt::RightButton;
671 #endif
672
673     if (isEnabled() && event->reason() == QGraphicsSceneContextMenuEvent::Mouse
674         && acceptsContextMenuButton) {
675         // Do not let the context menu event propagate to items behind.
676         return;
677     }
678
679     QDeclarativeItem::contextMenuEvent(event);
680 }
681 #endif // QT_NO_CONTEXTMENU
682
683 bool QDeclarative1MouseArea::sceneEvent(QEvent *event)
684 {
685     bool rv = QDeclarativeItem::sceneEvent(event);
686     if (event->type() == QEvent::UngrabMouse) {
687         Q_D(QDeclarative1MouseArea);
688         if (d->pressed) {
689             // if our mouse grab has been removed (probably by Flickable), fix our
690             // state
691             d->pressed = false;
692             d->stealMouse = false;
693             setKeepMouseGrab(false);
694             emit canceled();
695             emit pressedChanged();
696             if (d->hovered) {
697                 d->hovered = false;
698                 emit hoveredChanged();
699             }
700         }
701     }
702     return rv;
703 }
704
705 bool QDeclarative1MouseArea::sendMouseEvent(QGraphicsSceneMouseEvent *event)
706 {
707     Q_D(QDeclarative1MouseArea);
708     QGraphicsSceneMouseEvent mouseEvent(event->type());
709     QRectF myRect = mapToScene(QRectF(0, 0, width(), height())).boundingRect();
710
711     QGraphicsScene *s = scene();
712     QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0;
713     bool stealThisEvent = d->stealMouse;
714     if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) {
715         mouseEvent.setAccepted(false);
716         for (int i = 0x1; i <= 0x10; i <<= 1) {
717             if (event->buttons() & i) {
718                 Qt::MouseButton button = Qt::MouseButton(i);
719                 mouseEvent.setButtonDownPos(button, mapFromScene(event->buttonDownPos(button)));
720             }
721         }
722         mouseEvent.setScenePos(event->scenePos());
723         mouseEvent.setLastScenePos(event->lastScenePos());
724         mouseEvent.setPos(mapFromScene(event->scenePos()));
725         mouseEvent.setLastPos(mapFromScene(event->lastScenePos()));
726
727         switch(mouseEvent.type()) {
728         case QEvent::GraphicsSceneMouseMove:
729             mouseMoveEvent(&mouseEvent);
730             break;
731         case QEvent::GraphicsSceneMousePress:
732             mousePressEvent(&mouseEvent);
733             break;
734         case QEvent::GraphicsSceneMouseRelease:
735             mouseReleaseEvent(&mouseEvent);
736             break;
737         default:
738             break;
739         }
740         grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem());
741         if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this)
742             grabMouse();
743
744         return stealThisEvent;
745     }
746     if (mouseEvent.type() == QEvent::GraphicsSceneMouseRelease) {
747         if (d->pressed) {
748             d->pressed = false;
749             d->stealMouse = false;
750             if (s && s->mouseGrabberItem() == this)
751                 ungrabMouse();
752             emit canceled();
753             emit pressedChanged();
754             if (d->hovered) {
755                 d->hovered = false;
756                 emit hoveredChanged();
757             }
758         }
759     }
760     return false;
761 }
762
763 bool QDeclarative1MouseArea::sceneEventFilter(QGraphicsItem *i, QEvent *e)
764 {
765     Q_D(QDeclarative1MouseArea);
766     if (!d->absorb || !isVisible() || !d->drag || !d->drag->filterChildren())
767         return QDeclarativeItem::sceneEventFilter(i, e);
768     switch (e->type()) {
769     case QEvent::GraphicsSceneMousePress:
770     case QEvent::GraphicsSceneMouseMove:
771     case QEvent::GraphicsSceneMouseRelease:
772         return sendMouseEvent(static_cast<QGraphicsSceneMouseEvent *>(e));
773     default:
774         break;
775     }
776
777     return QDeclarativeItem::sceneEventFilter(i, e);
778 }
779
780 void QDeclarative1MouseArea::timerEvent(QTimerEvent *event)
781 {
782     Q_D(QDeclarative1MouseArea);
783     if (event->timerId() == d->pressAndHoldTimer.timerId()) {
784         d->pressAndHoldTimer.stop();
785         bool dragged = d->drag && d->drag->active();
786         if (d->pressed && dragged == false && d->hovered == true) {
787             d->longPress = true;
788             QDeclarative1MouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, false, d->longPress);
789             emit pressAndHold(&me);
790         }
791     }
792 }
793
794 void QDeclarative1MouseArea::geometryChanged(const QRectF &newGeometry,
795                                             const QRectF &oldGeometry)
796 {
797     Q_D(QDeclarative1MouseArea);
798     QDeclarativeItem::geometryChanged(newGeometry, oldGeometry);
799
800     if (d->lastScenePos.isNull)
801         d->lastScenePos = mapToScene(d->lastPos);
802     else if (newGeometry.x() != oldGeometry.x() || newGeometry.y() != oldGeometry.y())
803         d->lastPos = mapFromScene(d->lastScenePos);
804 }
805
806 QVariant QDeclarative1MouseArea::itemChange(GraphicsItemChange change,
807                                        const QVariant &value)
808 {
809     Q_D(QDeclarative1MouseArea);
810     switch (change) {
811     case ItemVisibleHasChanged:
812         if (acceptHoverEvents() && d->hovered != (isVisible() && isUnderMouse()))
813             setHovered(!d->hovered);
814         break;
815     default:
816         break;
817     }
818
819     return QDeclarativeItem::itemChange(change, value);
820 }
821
822 /*!
823     \qmlproperty bool QtQuick1::MouseArea::hoverEnabled
824     This property holds whether hover events are handled.
825
826     By default, mouse events are only handled in response to a button event, or when a button is
827     pressed.  Hover enables handling of all mouse events even when no mouse button is
828     pressed.
829
830     This property affects the containsMouse property and the onEntered, onExited and
831     onPositionChanged signals.
832 */
833 bool QDeclarative1MouseArea::hoverEnabled() const
834 {
835     return acceptHoverEvents();
836 }
837
838 void QDeclarative1MouseArea::setHoverEnabled(bool h)
839 {
840     Q_D(QDeclarative1MouseArea);
841     if (h == acceptHoverEvents())
842         return;
843
844     setAcceptHoverEvents(h);
845     emit hoverEnabledChanged();
846     if (d->hovered != isUnderMouse())
847         setHovered(!d->hovered);
848 }
849
850 /*!
851     \qmlproperty bool QtQuick1::MouseArea::containsMouse
852     This property holds whether the mouse is currently inside the mouse area.
853
854     \warning This property is not updated if the area moves under the mouse: \e containsMouse will not change.
855     In addition, if hoverEnabled is false, containsMouse will only be valid when the mouse is pressed.
856 */
857 bool QDeclarative1MouseArea::hovered() const
858 {
859     Q_D(const QDeclarative1MouseArea);
860     return d->hovered;
861 }
862
863 /*!
864     \qmlproperty bool QtQuick1::MouseArea::pressed
865     This property holds whether the mouse area is currently pressed.
866 */
867 bool QDeclarative1MouseArea::pressed() const
868 {
869     Q_D(const QDeclarative1MouseArea);
870     return d->pressed;
871 }
872
873 void QDeclarative1MouseArea::setHovered(bool h)
874 {
875     Q_D(QDeclarative1MouseArea);
876     if (d->hovered != h) {
877         d->hovered = h;
878         emit hoveredChanged();
879         d->hovered ? emit entered() : emit exited();
880     }
881 }
882
883 /*!
884     \qmlproperty QtQuick1::Qt::MouseButtons MouseArea::acceptedButtons
885     This property holds the mouse buttons that the mouse area reacts to.
886
887     The available buttons are:
888     \list
889     \o Qt.LeftButton
890     \o Qt.RightButton
891     \o Qt.MiddleButton
892     \endlist
893
894     To accept more than one button the flags can be combined with the
895     "|" (or) operator:
896
897     \code
898     MouseArea { acceptedButtons: Qt.LeftButton | Qt.RightButton }
899     \endcode
900
901     The default value is \c Qt.LeftButton.
902 */
903 Qt::MouseButtons QDeclarative1MouseArea::acceptedButtons() const
904 {
905     return acceptedMouseButtons();
906 }
907
908 void QDeclarative1MouseArea::setAcceptedButtons(Qt::MouseButtons buttons)
909 {
910     if (buttons != acceptedMouseButtons()) {
911         setAcceptedMouseButtons(buttons);
912         emit acceptedButtonsChanged();
913     }
914 }
915
916 bool QDeclarative1MouseArea::setPressed(bool p)
917 {
918     Q_D(QDeclarative1MouseArea);
919     bool dragged = d->drag && d->drag->active();
920     bool isclick = d->pressed == true && p == false && dragged == false && d->hovered == true;
921
922     if (d->pressed != p) {
923         d->pressed = p;
924         QDeclarative1MouseEvent me(d->lastPos.x(), d->lastPos.y(), d->lastButton, d->lastButtons, d->lastModifiers, isclick, d->longPress);
925         if (d->pressed) {
926             if (!d->doubleClick)
927                 emit pressed(&me);
928             me.setX(d->lastPos.x());
929             me.setY(d->lastPos.y());
930             emit mousePositionChanged(&me);
931             emit pressedChanged();
932         } else {
933             emit released(&me);
934             me.setX(d->lastPos.x());
935             me.setY(d->lastPos.y());
936             emit pressedChanged();
937             if (isclick && !d->longPress && !d->doubleClick)
938                 emit clicked(&me);
939         }
940
941         return me.isAccepted();
942     }
943     return false;
944 }
945
946 QDeclarative1Drag *QDeclarative1MouseArea::drag()
947 {
948     Q_D(QDeclarative1MouseArea);
949     if (!d->drag)
950         d->drag = new QDeclarative1Drag;
951     return d->drag;
952 }
953
954 /*!
955     \qmlproperty Item QtQuick1::MouseArea::drag.target
956     \qmlproperty bool QtQuick1::MouseArea::drag.active
957     \qmlproperty enumeration QtQuick1::MouseArea::drag.axis
958     \qmlproperty real QtQuick1::MouseArea::drag.minimumX
959     \qmlproperty real QtQuick1::MouseArea::drag.maximumX
960     \qmlproperty real QtQuick1::MouseArea::drag.minimumY
961     \qmlproperty real QtQuick1::MouseArea::drag.maximumY
962     \qmlproperty bool QtQuick1::MouseArea::drag.filterChildren
963
964     \c drag provides a convenient way to make an item draggable.
965
966     \list
967     \i \c drag.target specifies the id of the item to drag.
968     \i \c drag.active specifies if the target item is currently being dragged.
969     \i \c drag.axis specifies whether dragging can be done horizontally (\c Drag.XAxis), vertically (\c Drag.YAxis), or both (\c Drag.XandYAxis)
970     \i \c drag.minimum and \c drag.maximum limit how far the target can be dragged along the corresponding axes.
971     \endlist
972
973     The following example displays a \l Rectangle that can be dragged along the X-axis. The opacity
974     of the rectangle is reduced when it is dragged to the right.
975
976     \snippet doc/src/snippets/declarative/mousearea/mousearea.qml drag
977
978     \note Items cannot be dragged if they are anchored for the requested 
979     \c drag.axis. For example, if \c anchors.left or \c anchors.right was set
980     for \c rect in the above example, it cannot be dragged along the X-axis.
981     This can be avoided by settng the anchor value to \c undefined in 
982     an \l onPressed handler.
983
984     If \c drag.filterChildren is set to true, a drag can override descendant MouseAreas.  This
985     enables a parent MouseArea to handle drags, for example, while descendants handle clicks:
986
987     \snippet doc/src/snippets/declarative/mousearea/mouseareadragfilter.qml dragfilter
988
989 */
990
991 QT_END_NAMESPACE