103void QQuickDragAttachedPrivate::deliverEnterEvent()
105 dragRestarted =
false;
108 window = attachedItem->window();
110 mimeData->m_source = source;
111 if (!overrideActions)
112 mimeData->m_supportedActions = supportedActions;
113 mimeData->m_keys = keys;
116 QPoint scenePos = attachedItem->mapToScene(hotSpot).toPoint();
117 QDragEnterEvent event(scenePos, mimeData->m_supportedActions, mimeData, Qt::NoButton, Qt::NoModifier);
118 QQuickDropEventEx::setProposedAction(&event, proposedAction);
119 deliverEvent(window, &event);
123void QQuickDragAttachedPrivate::deliverMoveEvent()
125 Q_Q(QQuickDragAttached);
129 QPoint scenePos = attachedItem->mapToScene(hotSpot).toPoint();
130 QDragMoveEvent event(scenePos, mimeData->m_supportedActions, mimeData, Qt::NoButton, Qt::NoModifier);
131 QQuickDropEventEx::setProposedAction(&event, proposedAction);
132 deliverEvent(window, &event);
133 if (target != dragGrabber.target()) {
134 target = dragGrabber.target();
135 emit q->targetChanged();
182QQuickDragAttached::QQuickDragAttached(QObject *parent)
183 : QObject(*
new QQuickDragAttachedPrivate, parent)
185 Q_D(QQuickDragAttached);
186 d->attachedItem = qobject_cast<QQuickItem *>(parent);
187 d->source = d->attachedItem;
218void QQuickDragAttached::setActive(
bool active)
220 Q_D(QQuickDragAttached);
221 if (d->active != active) {
223 qmlWarning(
this) <<
"active cannot be changed from within a drag event handler";
225 if (d->dragType == QQuickDrag::Internal) {
226 d->start(d->supportedActions);
229 emit activeChanged();
230 if (d->dragType == QQuickDrag::Automatic) {
233 d->startDrag(d->supportedActions);
385QSize QQuickDragAttached::imageSourceSize()
const
387 Q_D(
const QQuickDragAttached);
388 int width = d->imageSourceSize.width();
389 int height = d->imageSourceSize.height();
393 width = d->pixmapLoader.width();
398 height = d->pixmapLoader.height();
402 return QSize(width, height);
405void QQuickDragAttached::setImageSourceSize(
const QSize &size)
407 Q_D(QQuickDragAttached);
408 if (d->imageSourceSize != size) {
409 d->imageSourceSize = size;
411 if (!d->imageSource.isEmpty())
414 Q_EMIT imageSourceSizeChanged();
557void QQuickDragAttachedPrivate::start(Qt::DropActions supportedActions)
559 Q_Q(QQuickDragAttached);
563 mimeData =
new QQuickDragMimeData;
565 QQuickItemPrivate::get(attachedItem)->addItemChangeListener(
566 this, QQuickItemPrivate::Geometry | QQuickItemPrivate::Parent);
570 mimeData->m_supportedActions = supportedActions;
573 dragRestarted =
false;
577 if (target != dragGrabber.target()) {
578 target = dragGrabber.target();
579 emit q->targetChanged();
582 emit q->activeChanged();
595void QQuickDragAttached::start(QQmlV4FunctionPtr args)
597 Q_D(QQuickDragAttached);
599 qmlWarning(
this) <<
"start() cannot be called from within a drag event handler";
606 d->overrideActions =
false;
607 Qt::DropActions supportedActions = d->supportedActions;
609 if (args->length() >= 1) {
610 QV4::Scope scope(args->v4engine());
611 QV4::ScopedValue v(scope, (*args)[0]);
613 supportedActions = Qt::DropActions(v->integerValue());
614 d->overrideActions =
true;
618 d->start(supportedActions);
637int QQuickDragAttached::drop()
639 Q_D(QQuickDragAttached);
640 Qt::DropAction acceptedAction = Qt::IgnoreAction;
643 qmlWarning(
this) <<
"drop() cannot be called from within a drag event handler";
644 return acceptedAction;
648 d->deliverMoveEvent();
651 return acceptedAction;
654 QObject *target =
nullptr;
657 QPoint scenePos = d->attachedItem->mapToScene(d->hotSpot).toPoint();
660 scenePos, d->mimeData->m_supportedActions, d->mimeData, Qt::NoButton, Qt::NoModifier);
661 QQuickDropEventEx::setProposedAction(&event, d->proposedAction);
662 d->deliverEvent(d->window, &event);
664 if (event.isAccepted()) {
665 acceptedAction = event.dropAction();
666 target = d->dragGrabber.target();
670 if (d->target != target) {
672 emit targetChanged();
675 emit activeChanged();
676 return acceptedAction;
725QMimeData *QQuickDragAttachedPrivate::createMimeData()
const
727 Q_Q(
const QQuickDragAttached);
728 QMimeData *mimeData =
new QMimeData();
730 for (
const auto [mimeType, value] : externalMimeData.asKeyValueRange()) {
731 switch (value.typeId()) {
732 case QMetaType::QByteArray:
734 mimeData->setData(mimeType, value.toByteArray());
736 case QMetaType::QString: {
737 const QString text = value.toString();
738 if (mimeType == u"text/plain"_s) {
739 mimeData->setText(text);
740 }
else if (mimeType == u"text/html"_s) {
741 mimeData->setHtml(text);
742 }
else if (mimeType == u"text/uri-list"_s) {
745 const auto lines = text.split(u"\r\n"_s, Qt::SkipEmptyParts);
746 for (
const auto &line : lines) {
747 const QUrl url(line);
751 qmlWarning(q) << line <<
" is not a valid URI";
754 mimeData->setUrls(urls);
755 }
else if (mimeType.startsWith(u"text/"_s)) {
756 if (qsizetype charsetIdx = mimeType.lastIndexOf(u";charset="_s); charsetIdx != -1) {
757 charsetIdx +=
sizeof(
";charset=") - 1;
758 const QByteArray encoding = mimeType.mid(charsetIdx).toUtf8();
759 QStringEncoder encoder(encoding);
760 if (encoder.isValid())
761 mimeData->setData(mimeType, encoder.encode(text));
763 qmlWarning(q) <<
"Don't know how to encode text as " << mimeType;
765 mimeData->setData(mimeType, text.toUtf8());
768 mimeData->setData(mimeType, text.toUtf8());
772 case QMetaType::QVariantList:
773 case QMetaType::QStringList:
774 if (mimeType == u"text/uri-list"_s) {
775 const QVariantList values = value.toList();
777 urls.reserve(values.size());
779 for (qsizetype index = 0; index < values.size(); ++index) {
780 const QUrl url = values.at(index).value<QUrl>();
785 qmlWarning(q) <<
"Value '" << values.at(index) <<
"' at index " << index
786 <<
" is not a valid URI";
790 mimeData->setUrls(urls);
793 case QMetaType::QColor:
794 if (mimeType == u"application/x-color"_s)
795 mimeData->setColorData(value);
797 case QMetaType::QImage:
798 if (
const QByteArray mimeTypeUtf8 = mimeType.toUtf8();
799 QImageWriter::supportedMimeTypes().contains(mimeTypeUtf8)) {
800 const auto imageFormats = QImageWriter::imageFormatsForMimeType(mimeTypeUtf8);
801 if (imageFormats.isEmpty()) {
802 mimeData->setImageData(value);
805 const QImage image = value.value<QImage>();
808 QBuffer buffer(&bytes);
809 QImageWriter encoder(&buffer, imageFormats.first());
810 encoder.write(image);
812 mimeData->setData(mimeType, bytes);
817 qmlWarning(q) <<
"Don't know how to encode variant of type " << value.metaType()
818 <<
" as mime type " << mimeType;
820 mimeData->setData(mimeType, value.toString().toUtf8());
828void QQuickDragAttachedPrivate::loadPixmap()
830 Q_Q(QQuickDragAttached);
832 QUrl loadUrl = imageSource;
833 const QQmlContext *context = qmlContext(q->parent());
835 loadUrl = context->resolvedUrl(imageSource);
836 pixmapLoader.load(context ? context->engine() :
nullptr, loadUrl, QRect(), q->imageSourceSize());
839Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedActions)
841 Q_Q(QQuickDragAttached);
843 QDrag *drag =
new QDrag(source ? source : q);
845 drag->setMimeData(createMimeData());
846 if (pixmapLoader.isReady())
847 drag->setPixmap(QPixmap::fromImage(pixmapLoader.image()));
849 drag->setHotSpot(hotSpot.toPoint());
850 emit q->dragStarted();
852 Qt::DropAction dropAction = drag->exec(supportedActions);
854 if (!QGuiApplicationPrivate::platformIntegration()->drag()->ownsDragObject())
861 emit q->targetChanged();
864 emit q->dragFinished(dropAction);
867 emit q->activeChanged();
882void QQuickDragAttached::startDrag(QQmlV4FunctionPtr args)
884 Q_D(QQuickDragAttached);
887 qmlWarning(
this) <<
"startDrag() cannot be called from within a drag event handler";
892 qmlWarning(
this) <<
"startDrag() drag must be active";
896 Qt::DropActions supportedActions = d->supportedActions;
899 if (args->length() >= 1) {
900 QV4::Scope scope(args->v4engine());
901 QV4::ScopedValue v(scope, (*args)[0]);
903 supportedActions = Qt::DropActions(v->integerValue());
907 Qt::DropAction dropAction = d->startDrag(supportedActions);
909 args->setReturnValue(QV4::Encode((
int)dropAction));
912QQuickDrag::QQuickDrag(QObject *parent)
913: QObject(parent), _target(
nullptr), _axis(XAndYAxis), _xmin(-FLT_MAX),
914_xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(
false), _filterChildren(
false),
915 _smoothed(
true), _threshold(QGuiApplication::styleHints()->startDragDistance())