1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qquickdrag_p.h"
41
42#include <private/qguiapplication_p.h>
43#include <qpa/qplatformintegration.h>
44#include <private/qquickitem_p.h>
45#include <QtQuick/private/qquickevents_p_p.h>
46#include <private/qquickitemchangelistener_p.h>
47#include <private/qquickpixmapcache_p.h>
48#include <private/qv4scopedvalue_p.h>
49#include <QtCore/qmimedata.h>
50#include <QtQml/qqmlinfo.h>
51#include <QtGui/qevent.h>
52#include <QtGui/qstylehints.h>
53#include <QtGui/qguiapplication.h>
54
55#include <qpa/qplatformdrag.h>
56#include <QtGui/qdrag.h>
57
58QT_BEGIN_NAMESPACE
59
60class QQuickDragAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener
61{
62 Q_DECLARE_PUBLIC(QQuickDragAttached)
63 QML_ANONYMOUS
64
65public:
66 static QQuickDragAttachedPrivate *get(QQuickDragAttached *attached) {
67 return static_cast<QQuickDragAttachedPrivate *>(QObjectPrivate::get(o: attached)); }
68
69 QQuickDragAttachedPrivate()
70 : attachedItem(nullptr)
71 , mimeData(nullptr)
72 , proposedAction(Qt::MoveAction)
73 , supportedActions(Qt::MoveAction | Qt::CopyAction | Qt::LinkAction)
74 , active(false)
75 , listening(false)
76 , inEvent(false)
77 , dragRestarted(false)
78 , itemMoved(false)
79 , eventQueued(false)
80 , overrideActions(false)
81 , dragType(QQuickDrag::Internal)
82 {
83 }
84
85 void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &) override;
86 void itemParentChanged(QQuickItem *, QQuickItem *parent) override;
87 void updatePosition();
88 void restartDrag();
89 void deliverEnterEvent();
90 void deliverMoveEvent();
91 void deliverLeaveEvent();
92 void deliverEvent(QQuickWindow *window, QEvent *event);
93 void start(Qt::DropActions supportedActions);
94 Qt::DropAction startDrag(Qt::DropActions supportedActions);
95 void setTarget(QQuickItem *item);
96
97 QQuickDragGrabber dragGrabber;
98
99 QPointer<QObject> source;
100 QPointer<QObject> target;
101 QPointer<QQuickWindow> window;
102 QQuickItem *attachedItem;
103 QQuickDragMimeData *mimeData;
104 Qt::DropAction proposedAction;
105 Qt::DropActions supportedActions;
106 bool active : 1;
107 bool listening : 1;
108 bool inEvent : 1;
109 bool dragRestarted : 1;
110 bool itemMoved : 1;
111 bool eventQueued : 1;
112 bool overrideActions : 1;
113 QPointF hotSpot;
114 QUrl imageSource;
115 QQuickPixmap pixmapLoader;
116 QStringList keys;
117 QVariantMap externalMimeData;
118 QQuickDrag::DragType dragType;
119};
120
121/*!
122 \qmltype Drag
123 \instantiates QQuickDrag
124 \inqmlmodule QtQuick
125 \ingroup qtquick-input
126 \brief For specifying drag and drop events for moved Items.
127
128 Using the Drag attached property, any Item can be made a source of drag and drop
129 events within a scene.
130
131 When a drag is \l active on an item, any change in that item's position will
132 generate a drag event that will be sent to any DropArea that intersects
133 with the new position of the item. Other items which implement drag and
134 drop event handlers can also receive these events.
135
136 The following snippet shows how an item can be dragged with a MouseArea.
137 However, dragging is not limited to mouse drags; anything that can move an item
138 can generate drag events, including touch events, animations and bindings.
139
140 \snippet qml/drag.qml 0
141
142 A drag can be terminated either by canceling it with Drag.cancel() or setting
143 Drag.active to false, or it can be terminated with a drop event by calling
144 Drag.drop(). If the drop event is accepted, Drag.drop() will return the
145 \l {supportedActions}{drop action} chosen by the recipient of the event,
146 otherwise it will return Qt.IgnoreAction.
147
148 \sa {Qt Quick Examples - Drag and Drop}, {Qt Quick Examples - externaldraganddrop}
149*/
150
151void QQuickDragAttachedPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange change,
152 const QRectF &)
153{
154 if (!change.positionChange() || !active || itemMoved)
155 return;
156 updatePosition();
157}
158
159void QQuickDragAttachedPrivate::itemParentChanged(QQuickItem *, QQuickItem *)
160{
161 if (!active || dragRestarted)
162 return;
163
164 QQuickWindow *newWindow = attachedItem->window();
165
166 if (window != newWindow)
167 restartDrag();
168 else if (window)
169 updatePosition();
170}
171
172void QQuickDragAttachedPrivate::updatePosition()
173{
174 Q_Q(QQuickDragAttached);
175 itemMoved = true;
176 if (!eventQueued) {
177 eventQueued = true;
178 QCoreApplication::postEvent(receiver: q, event: new QEvent(QEvent::User));
179 }
180}
181
182void QQuickDragAttachedPrivate::restartDrag()
183{
184 Q_Q(QQuickDragAttached);
185 dragRestarted = true;
186 if (!eventQueued) {
187 eventQueued = true;
188 QCoreApplication::postEvent(receiver: q, event: new QEvent(QEvent::User));
189 }
190}
191
192void QQuickDragAttachedPrivate::deliverEnterEvent()
193{
194 dragRestarted = false;
195 itemMoved = false;
196
197 window = attachedItem->window();
198
199 mimeData->m_source = source;
200 if (!overrideActions)
201 mimeData->m_supportedActions = supportedActions;
202 mimeData->m_keys = keys;
203
204 if (window) {
205 QPoint scenePos = attachedItem->mapToScene(point: hotSpot).toPoint();
206 QDragEnterEvent event(scenePos, mimeData->m_supportedActions, mimeData, Qt::NoButton, Qt::NoModifier);
207 QQuickDropEventEx::setProposedAction(event: &event, action: proposedAction);
208 deliverEvent(window, event: &event);
209 }
210}
211
212void QQuickDragAttachedPrivate::deliverMoveEvent()
213{
214 Q_Q(QQuickDragAttached);
215
216 itemMoved = false;
217 if (window) {
218 QPoint scenePos = attachedItem->mapToScene(point: hotSpot).toPoint();
219 QDragMoveEvent event(scenePos, mimeData->m_supportedActions, mimeData, Qt::NoButton, Qt::NoModifier);
220 QQuickDropEventEx::setProposedAction(event: &event, action: proposedAction);
221 deliverEvent(window, event: &event);
222 if (target != dragGrabber.target()) {
223 target = dragGrabber.target();
224 emit q->targetChanged();
225 }
226 }
227}
228
229void QQuickDragAttachedPrivate::deliverLeaveEvent()
230{
231 if (window) {
232 QDragLeaveEvent event;
233 deliverEvent(window, event: &event);
234 window = nullptr;
235 }
236}
237
238void QQuickDragAttachedPrivate::deliverEvent(QQuickWindow *window, QEvent *event)
239{
240 Q_ASSERT(!inEvent);
241 inEvent = true;
242 QQuickWindowPrivate::get(c: window)->deliverDragEvent(&dragGrabber, event);
243 inEvent = false;
244}
245
246bool QQuickDragAttached::event(QEvent *event)
247{
248 Q_D(QQuickDragAttached);
249
250 if (event->type() == QEvent::User) {
251 d->eventQueued = false;
252 if (d->dragRestarted) {
253 d->deliverLeaveEvent();
254 if (!d->mimeData)
255 d->mimeData = new QQuickDragMimeData;
256 d->deliverEnterEvent();
257
258 if (d->target != d->dragGrabber.target()) {
259 d->target = d->dragGrabber.target();
260 emit targetChanged();
261 }
262 } else if (d->itemMoved) {
263 d->deliverMoveEvent();
264 }
265 return true;
266 } else {
267 return QObject::event(event);
268 }
269}
270
271QQuickDragAttached::QQuickDragAttached(QObject *parent)
272 : QObject(*new QQuickDragAttachedPrivate, parent)
273{
274 Q_D(QQuickDragAttached);
275 d->attachedItem = qobject_cast<QQuickItem *>(object: parent);
276 d->source = d->attachedItem;
277}
278
279QQuickDragAttached::~QQuickDragAttached()
280{
281 Q_D(QQuickDragAttached);
282 delete d->mimeData;
283}
284
285/*!
286 \qmlattachedproperty bool QtQuick::Drag::active
287
288 This property holds whether a drag event sequence is currently active.
289
290 Binding this property to the active property of \l MouseArea::drag will
291 cause \l startDrag to be called when the user starts dragging.
292
293 Setting this property to true will also send a QDragEnter event to the scene
294 with the item's current position. Setting it to false will send a
295 QDragLeave event.
296
297 While a drag is active any change in an item's position will send a QDragMove
298 event with item's new position to the scene.
299*/
300
301bool QQuickDragAttached::isActive() const
302{
303 Q_D(const QQuickDragAttached);
304 return d->active;
305}
306
307void QQuickDragAttached::setActive(bool active)
308{
309 Q_D(QQuickDragAttached);
310 if (d->active != active) {
311 if (d->inEvent)
312 qmlWarning(me: this) << "active cannot be changed from within a drag event handler";
313 else if (active) {
314 if (d->dragType == QQuickDrag::Internal) {
315 d->start(supportedActions: d->supportedActions);
316 } else {
317 d->active = true;
318 emit activeChanged();
319 if (d->dragType == QQuickDrag::Automatic) {
320 // There are different semantics than start() since startDrag()
321 // may be called after an internal drag is already started.
322 d->startDrag(supportedActions: d->supportedActions);
323 }
324 }
325 }
326 else
327 cancel();
328 }
329}
330
331/*!
332 \qmlattachedproperty Object QtQuick::Drag::source
333
334 This property holds an object that is identified to recipients of drag events as
335 the source of the events. By default this is the item that the Drag
336 property is attached to.
337
338 Changing the source while a drag is active will reset the sequence of drag events by
339 sending a drag leave event followed by a drag enter event with the new source.
340*/
341
342QObject *QQuickDragAttached::source() const
343{
344 Q_D(const QQuickDragAttached);
345 return d->source;
346}
347
348void QQuickDragAttached::setSource(QObject *item)
349{
350 Q_D(QQuickDragAttached);
351 if (d->source != item) {
352 d->source = item;
353 if (d->active)
354 d->restartDrag();
355 emit sourceChanged();
356 }
357}
358
359void QQuickDragAttached::resetSource()
360{
361 Q_D(QQuickDragAttached);
362 if (d->source != d->attachedItem) {
363 d->source = d->attachedItem;
364 if (d->active)
365 d->restartDrag();
366 emit sourceChanged();
367 }
368}
369
370/*!
371 \qmlattachedproperty Object QtQuick::Drag::target
372
373 While a drag is active this property holds the last object to accept an
374 enter event from the dragged item, if the current drag position doesn't
375 intersect any accepting targets it is null.
376
377 When a drag is not active this property holds the object that accepted
378 the drop event that ended the drag, if no object accepted the drop or
379 the drag was canceled the target will then be null.
380*/
381
382QObject *QQuickDragAttached::target() const
383{
384 Q_D(const QQuickDragAttached);
385 return d->target;
386}
387
388/*!
389 \qmlattachedproperty QPointF QtQuick::Drag::hotSpot
390
391 This property holds the drag position relative to the top left of the item.
392
393 By default this is (0, 0).
394
395 Changes to hotSpot trigger a new drag move with the updated position.
396*/
397
398QPointF QQuickDragAttached::hotSpot() const
399{
400 Q_D(const QQuickDragAttached);
401 return d->hotSpot;
402}
403
404void QQuickDragAttached::setHotSpot(const QPointF &hotSpot)
405{
406 Q_D(QQuickDragAttached);
407 if (d->hotSpot != hotSpot) {
408 d->hotSpot = hotSpot;
409
410 if (d->active)
411 d->updatePosition();
412
413 emit hotSpotChanged();
414 }
415}
416
417/*!
418 \qmlattachedproperty QUrl QtQuick::Drag::imageSource
419 \since 5.8
420
421 This property holds the URL of the image which will be used to represent
422 the data during the drag and drop operation. Changing this property after
423 the drag operation has started will have no effect.
424
425 The example below uses an item's contents as a drag image:
426
427 \snippet qml/externaldrag.qml 0
428
429 \sa Item::grabToImage()
430*/
431
432QUrl QQuickDragAttached::imageSource() const
433{
434 Q_D(const QQuickDragAttached);
435 return d->imageSource;
436}
437
438void QQuickDragAttached::setImageSource(const QUrl &url)
439{
440 Q_D(QQuickDragAttached);
441 if (d->imageSource != url) {
442 d->imageSource = url;
443
444 if (url.isEmpty()) {
445 d->pixmapLoader.clear();
446 } else {
447 d->pixmapLoader.load(qmlEngine(parent()), url);
448 }
449
450 Q_EMIT imageSourceChanged();
451 }
452}
453
454/*!
455 \qmlattachedproperty stringlist QtQuick::Drag::keys
456
457 This property holds a list of keys that can be used by a DropArea to filter drag events.
458
459 Changing the keys while a drag is active will reset the sequence of drag events by
460 sending a drag leave event followed by a drag enter event with the new source.
461*/
462
463QStringList QQuickDragAttached::keys() const
464{
465 Q_D(const QQuickDragAttached);
466 return d->keys;
467}
468
469void QQuickDragAttached::setKeys(const QStringList &keys)
470{
471 Q_D(QQuickDragAttached);
472 if (d->keys != keys) {
473 d->keys = keys;
474 if (d->active)
475 d->restartDrag();
476 emit keysChanged();
477 }
478}
479
480/*!
481 \qmlattachedproperty stringlist QtQuick::Drag::mimeData
482 \since 5.2
483
484 This property holds a map of mimeData that is used during startDrag.
485*/
486
487QVariantMap QQuickDragAttached::mimeData() const
488{
489 Q_D(const QQuickDragAttached);
490 return d->externalMimeData;
491}
492
493void QQuickDragAttached::setMimeData(const QVariantMap &mimeData)
494{
495 Q_D(QQuickDragAttached);
496 if (d->externalMimeData != mimeData) {
497 d->externalMimeData = mimeData;
498 emit mimeDataChanged();
499 }
500}
501
502/*!
503 \qmlattachedproperty flags QtQuick::Drag::supportedActions
504
505 This property holds return values of Drag.drop() supported by the drag source.
506
507 Changing the supportedActions while a drag is active will reset the sequence of drag
508 events by sending a drag leave event followed by a drag enter event with the new source.
509*/
510
511Qt::DropActions QQuickDragAttached::supportedActions() const
512{
513 Q_D(const QQuickDragAttached);
514 return d->supportedActions;
515}
516
517void QQuickDragAttached::setSupportedActions(Qt::DropActions actions)
518{
519 Q_D(QQuickDragAttached);
520 if (d->supportedActions != actions) {
521 d->supportedActions = actions;
522 if (d->active)
523 d->restartDrag();
524 emit supportedActionsChanged();
525 }
526}
527
528/*!
529 \qmlattachedproperty enumeration QtQuick::Drag::proposedAction
530
531 This property holds an action that is recommended by the drag source as a
532 return value from Drag.drop().
533
534 Changes to proposedAction will trigger a move event with the updated proposal.
535*/
536
537Qt::DropAction QQuickDragAttached::proposedAction() const
538{
539 Q_D(const QQuickDragAttached);
540 return d->proposedAction;
541}
542
543void QQuickDragAttached::setProposedAction(Qt::DropAction action)
544{
545 Q_D(QQuickDragAttached);
546 if (d->proposedAction != action) {
547 d->proposedAction = action;
548 // The proposed action shouldn't affect whether a drag is accepted
549 // so leave/enter events are excessive, but the target should still
550 // updated.
551 if (d->active)
552 d->updatePosition();
553 emit proposedActionChanged();
554 }
555}
556
557/*!
558 \qmlattachedproperty enumeration QtQuick::Drag::dragType
559 \since 5.2
560
561 This property indicates whether to automatically start drags, do nothing, or
562 to use backwards compatible internal drags. The default is to use backwards
563 compatible internal drags.
564
565 A drag can also be started manually using \l startDrag.
566
567 \list
568 \li Drag.None - do not start drags automatically
569 \li Drag.Automatic - start drags automatically
570 \li Drag.Internal (default) - start backwards compatible drags automatically
571 \endlist
572
573 When using \c Drag.Automatic you should also define \l mimeData and bind the
574 \l active property to the active property of MouseArea : \l {MouseArea::drag.active}
575*/
576
577QQuickDrag::DragType QQuickDragAttached::dragType() const
578{
579 Q_D(const QQuickDragAttached);
580 return d->dragType;
581}
582
583void QQuickDragAttached::setDragType(QQuickDrag::DragType dragType)
584{
585 Q_D(QQuickDragAttached);
586 if (d->dragType != dragType) {
587 d->dragType = dragType;
588 emit dragTypeChanged();
589 }
590}
591
592void QQuickDragAttachedPrivate::start(Qt::DropActions supportedActions)
593{
594 Q_Q(QQuickDragAttached);
595 Q_ASSERT(!active);
596
597 if (!mimeData)
598 mimeData = new QQuickDragMimeData;
599 if (!listening) {
600 QQuickItemPrivate::get(item: attachedItem)->addItemChangeListener(
601 listener: this, types: QQuickItemPrivate::Geometry | QQuickItemPrivate::Parent);
602 listening = true;
603 }
604
605 mimeData->m_supportedActions = supportedActions;
606 active = true;
607 itemMoved = false;
608 dragRestarted = false;
609
610 deliverEnterEvent();
611
612 if (target != dragGrabber.target()) {
613 target = dragGrabber.target();
614 emit q->targetChanged();
615 }
616
617 emit q->activeChanged();
618}
619
620/*!
621 \qmlattachedmethod void QtQuick::Drag::start(flags supportedActions)
622
623 Starts sending drag events. Used for starting old-style internal drags. \l startDrag is the
624 new-style, preferred method of starting drags.
625
626 The optional \a supportedActions argument can be used to override the \l supportedActions
627 property for the started sequence.
628*/
629
630void QQuickDragAttached::start(QQmlV4Function *args)
631{
632 Q_D(QQuickDragAttached);
633 if (d->inEvent) {
634 qmlWarning(me: this) << "start() cannot be called from within a drag event handler";
635 return;
636 }
637
638 if (d->active)
639 cancel();
640
641 d->overrideActions = false;
642 Qt::DropActions supportedActions = d->supportedActions;
643 // check arguments for supportedActions, maybe data?
644 if (args->length() >= 1) {
645 QV4::Scope scope(args->v4engine());
646 QV4::ScopedValue v(scope, (*args)[0]);
647 if (v->isInt32()) {
648 supportedActions = Qt::DropActions(v->integerValue());
649 d->overrideActions = true;
650 }
651 }
652
653 d->start(supportedActions);
654}
655
656/*!
657 \qmlattachedmethod enumeration QtQuick::Drag::drop()
658
659 Ends a drag sequence by sending a drop event to the target item.
660
661 Returns the action accepted by the target item. If the target item or a parent doesn't accept
662 the drop event then Qt.IgnoreAction will be returned.
663
664 The returned drop action may be one of:
665
666 \list
667 \li Qt.CopyAction Copy the data to the target
668 \li Qt.MoveAction Move the data from the source to the target
669 \li Qt.LinkAction Create a link from the source to the target.
670 \li Qt.IgnoreAction Ignore the action (do nothing with the data).
671 \endlist
672*/
673
674int QQuickDragAttached::drop()
675{
676 Q_D(QQuickDragAttached);
677 Qt::DropAction acceptedAction = Qt::IgnoreAction;
678
679 if (d->inEvent) {
680 qmlWarning(me: this) << "drop() cannot be called from within a drag event handler";
681 return acceptedAction;
682 }
683
684 if (d->itemMoved)
685 d->deliverMoveEvent();
686
687 if (!d->active)
688 return acceptedAction;
689 d->active = false;
690
691 QObject *target = nullptr;
692
693 if (d->window) {
694 QPoint scenePos = d->attachedItem->mapToScene(point: d->hotSpot).toPoint();
695
696 QDropEvent event(
697 scenePos, d->mimeData->m_supportedActions, d->mimeData, Qt::NoButton, Qt::NoModifier);
698 QQuickDropEventEx::setProposedAction(event: &event, action: d->proposedAction);
699 d->deliverEvent(window: d->window, event: &event);
700
701 if (event.isAccepted()) {
702 acceptedAction = event.dropAction();
703 target = d->dragGrabber.target();
704 }
705 }
706
707 if (d->target != target) {
708 d->target = target;
709 emit targetChanged();
710 }
711
712 emit activeChanged();
713 return acceptedAction;
714}
715
716/*!
717 \qmlattachedmethod void QtQuick::Drag::cancel()
718
719 Ends a drag sequence.
720*/
721
722void QQuickDragAttached::cancel()
723{
724 Q_D(QQuickDragAttached);
725
726 if (d->inEvent) {
727 qmlWarning(me: this) << "cancel() cannot be called from within a drag event handler";
728 return;
729 }
730
731 if (!d->active)
732 return;
733 d->active = false;
734 d->deliverLeaveEvent();
735
736 if (d->target) {
737 d->target = nullptr;
738 emit targetChanged();
739 }
740
741 emit activeChanged();
742}
743
744/*!
745 \qmlattachedsignal QtQuick::Drag::dragStarted()
746
747 This signal is emitted when a drag is started with the \l startDrag() method
748 or when it is started automatically using the \l dragType property.
749 */
750
751/*!
752 \qmlattachedsignal QtQuick::Drag::dragFinished(DropAction dropAction)
753
754 This signal is emitted when a drag finishes and the drag was started with the
755 \l startDrag() method or started automatically using the \l dragType property.
756
757 \a dropAction holds the action accepted by the target item.
758
759 \sa drop()
760 */
761
762Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedActions)
763{
764 Q_Q(QQuickDragAttached);
765
766 QDrag *drag = new QDrag(source ? source : q);
767 QMimeData *mimeData = new QMimeData();
768
769 for (auto it = externalMimeData.cbegin(), end = externalMimeData.cend(); it != end; ++it)
770 mimeData->setData(mimetype: it.key(), data: it.value().toString().toUtf8());
771
772 drag->setMimeData(mimeData);
773 if (pixmapLoader.isReady()) {
774 drag->setPixmap(QPixmap::fromImage(image: pixmapLoader.image()));
775 }
776
777 drag->setHotSpot(hotSpot.toPoint());
778 emit q->dragStarted();
779
780 Qt::DropAction dropAction = drag->exec(supportedActions);
781
782 if (!QGuiApplicationPrivate::platformIntegration()->drag()->ownsDragObject())
783 drag->deleteLater();
784
785 deliverLeaveEvent();
786
787 if (target) {
788 target = nullptr;
789 emit q->targetChanged();
790 }
791
792 emit q->dragFinished(dropAction);
793
794 active = false;
795 emit q->activeChanged();
796
797 return dropAction;
798}
799
800
801/*!
802 \qmlattachedmethod void QtQuick::Drag::startDrag(flags supportedActions)
803
804 Starts sending drag events.
805
806 The optional \a supportedActions argument can be used to override the \l supportedActions
807 property for the started sequence.
808*/
809
810void QQuickDragAttached::startDrag(QQmlV4Function *args)
811{
812 Q_D(QQuickDragAttached);
813
814 if (d->inEvent) {
815 qmlWarning(me: this) << "startDrag() cannot be called from within a drag event handler";
816 return;
817 }
818
819 if (!d->active) {
820 qmlWarning(me: this) << "startDrag() drag must be active";
821 return;
822 }
823
824 Qt::DropActions supportedActions = d->supportedActions;
825
826 // check arguments for supportedActions
827 if (args->length() >= 1) {
828 QV4::Scope scope(args->v4engine());
829 QV4::ScopedValue v(scope, (*args)[0]);
830 if (v->isInt32()) {
831 supportedActions = Qt::DropActions(v->integerValue());
832 }
833 }
834
835 Qt::DropAction dropAction = d->startDrag(supportedActions);
836
837 args->setReturnValue(QV4::Encode((int)dropAction));
838}
839
840QQuickDrag::QQuickDrag(QObject *parent)
841: QObject(parent), _target(nullptr), _axis(XAndYAxis), _xmin(-FLT_MAX),
842_xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false),
843 _smoothed(true), _threshold(QGuiApplication::styleHints()->startDragDistance())
844{
845}
846
847QQuickDrag::~QQuickDrag()
848{
849}
850
851QQuickItem *QQuickDrag::target() const
852{
853 return _target;
854}
855
856void QQuickDrag::setTarget(QQuickItem *t)
857{
858 if (_target == t)
859 return;
860 _target = t;
861 emit targetChanged();
862}
863
864void QQuickDrag::resetTarget()
865{
866 if (_target == nullptr)
867 return;
868 _target = nullptr;
869 emit targetChanged();
870}
871
872QQuickDrag::Axis QQuickDrag::axis() const
873{
874 return _axis;
875}
876
877void QQuickDrag::setAxis(QQuickDrag::Axis a)
878{
879 if (_axis == a)
880 return;
881 _axis = a;
882 emit axisChanged();
883}
884
885qreal QQuickDrag::xmin() const
886{
887 return _xmin;
888}
889
890void QQuickDrag::setXmin(qreal m)
891{
892 if (_xmin == m)
893 return;
894 _xmin = m;
895 emit minimumXChanged();
896}
897
898qreal QQuickDrag::xmax() const
899{
900 return _xmax;
901}
902
903void QQuickDrag::setXmax(qreal m)
904{
905 if (_xmax == m)
906 return;
907 _xmax = m;
908 emit maximumXChanged();
909}
910
911qreal QQuickDrag::ymin() const
912{
913 return _ymin;
914}
915
916void QQuickDrag::setYmin(qreal m)
917{
918 if (_ymin == m)
919 return;
920 _ymin = m;
921 emit minimumYChanged();
922}
923
924qreal QQuickDrag::ymax() const
925{
926 return _ymax;
927}
928
929void QQuickDrag::setYmax(qreal m)
930{
931 if (_ymax == m)
932 return;
933 _ymax = m;
934 emit maximumYChanged();
935}
936
937bool QQuickDrag::smoothed() const
938{
939 return _smoothed;
940}
941
942void QQuickDrag::setSmoothed(bool smooth)
943{
944 if (_smoothed != smooth) {
945 _smoothed = smooth;
946 emit smoothedChanged();
947 }
948}
949
950qreal QQuickDrag::threshold() const
951{
952 return _threshold;
953}
954
955void QQuickDrag::setThreshold(qreal value)
956{
957 if (_threshold != value) {
958 _threshold = value;
959 emit thresholdChanged();
960 }
961}
962
963void QQuickDrag::resetThreshold()
964{
965 setThreshold(QGuiApplication::styleHints()->startDragDistance());
966}
967
968bool QQuickDrag::active() const
969{
970 return _active;
971}
972
973void QQuickDrag::setActive(bool drag)
974{
975 if (_active == drag)
976 return;
977 _active = drag;
978 emit activeChanged();
979}
980
981bool QQuickDrag::filterChildren() const
982{
983 return _filterChildren;
984}
985
986void QQuickDrag::setFilterChildren(bool filter)
987{
988 if (_filterChildren == filter)
989 return;
990 _filterChildren = filter;
991 emit filterChildrenChanged();
992}
993
994QQuickDragAttached *QQuickDrag::qmlAttachedProperties(QObject *obj)
995{
996 return new QQuickDragAttached(obj);
997}
998
999QT_END_NAMESPACE
1000
1001#include "moc_qquickdrag_p.cpp"
1002

source code of qtdeclarative/src/quick/items/qquickdrag.cpp