From 89afccbb04d72ae8e633326277d64df4de4d1dfc Mon Sep 17 00:00:00 2001 From: leonardooyama Date: Tue, 4 Jun 2024 19:19:38 -0300 Subject: [PATCH] Support for drag and drop (#54) Added support for drag and drop --------- Co-authored-by: Leonardo Seiji Oyama --- CMakeLists.txt | 1 + QGeoView.pro | 3 +- lib/include/QGeoView/QGVMap.h | 3 + lib/include/QGeoView/QGVMapQGView.h | 13 +++ lib/src/QGVMap.cpp | 8 ++ lib/src/QGVMapQGView.cpp | 27 +++++ samples/drag-and-drop/CMakeLists.txt | 37 ++++++ samples/drag-and-drop/drag-and-drop.pro | 15 +++ samples/drag-and-drop/main.cpp | 37 ++++++ samples/drag-and-drop/mainwindow.cpp | 143 ++++++++++++++++++++++++ samples/drag-and-drop/mainwindow.h | 43 +++++++ 11 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 samples/drag-and-drop/CMakeLists.txt create mode 100644 samples/drag-and-drop/drag-and-drop.pro create mode 100644 samples/drag-and-drop/main.cpp create mode 100644 samples/drag-and-drop/mainwindow.cpp create mode 100644 samples/drag-and-drop/mainwindow.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 22510a1..dcf99eb 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ if (${BUILD_EXAMPLES}) add_subdirectory(samples/moving-objects) add_subdirectory(samples/mouse-actions) add_subdirectory(samples/camera-actions) + add_subdirectory(samples/drag-and-drop) else () message(STATUS "Disabled building of examples") endif () diff --git a/QGeoView.pro b/QGeoView.pro index b311b6c..561beb8 100644 --- a/QGeoView.pro +++ b/QGeoView.pro @@ -16,4 +16,5 @@ SUBDIRS = \ samples/custom-tiles \ samples/moving-objects \ samples/mouse-actions \ - samples/camera-actions + samples/camera-actions \ + samples/drag-and-drop diff --git a/lib/include/QGeoView/QGVMap.h b/lib/include/QGeoView/QGVMap.h index 3d97aca..bd5eb8b 100644 --- a/lib/include/QGeoView/QGVMap.h +++ b/lib/include/QGeoView/QGVMap.h @@ -18,6 +18,7 @@ #pragma once +#include #include #include "QGVCamera.h" @@ -104,6 +105,7 @@ class QGV_LIB_DECL QGVMap : public QWidget void mapMouseMove(QPointF projPos); void mapMousePress(QPointF projPos); void mapMouseDoubleClicked(QPointF projPos); + void dropOnMap(QGV::GeoPos pos, const QMimeData* data); private: QScopedPointer mProjection; @@ -111,4 +113,5 @@ class QGV_LIB_DECL QGVMap : public QWidget QScopedPointer mRootItem; QList mWidgets; QSet mSelections; + void handleDropDataOnQGVMapQGView(QPointF position, const QMimeData* dropData); }; diff --git a/lib/include/QGeoView/QGVMapQGView.h b/lib/include/QGeoView/QGVMapQGView.h index 0e390e8..5b7139b 100644 --- a/lib/include/QGeoView/QGVMapQGView.h +++ b/lib/include/QGeoView/QGVMapQGView.h @@ -23,8 +23,14 @@ #include "QGVMapQGItem.h" #include "QGVMapRubberBand.h" + +#include +#include +#include +#include #include #include +#include class QGVMap; @@ -45,6 +51,9 @@ class QGV_LIB_DECL QGVMapQGView : public QGraphicsView void setScaleLimits(double minScale, double maxScale); void cleanState(); +Q_SIGNALS: + void dropData(QPointF position, const QMimeData* dropData); + private: QRectF viewRect() const; void changeState(QGV::MapState state); @@ -83,6 +92,10 @@ class QGV_LIB_DECL QGVMapQGView : public QGraphicsView void resizeEvent(QResizeEvent* event) override final; void showEvent(QShowEvent* event) override final; void keyPressEvent(QKeyEvent* event) override final; + void dragEnterEvent(QDragEnterEvent* event) override final; + void dragMoveEvent(QDragMoveEvent* event) override final; + void dropEvent(QDropEvent* event) override final; + void dragLeaveEvent(QDragLeaveEvent* event) override final; private: QGVMap* mGeoMap; diff --git a/lib/src/QGVMap.cpp b/lib/src/QGVMap.cpp index bac1db2..4d5a4f8 100644 --- a/lib/src/QGVMap.cpp +++ b/lib/src/QGVMap.cpp @@ -55,6 +55,7 @@ QGVMap::QGVMap(QWidget* parent) layout()->addWidget(mQGView.data()); layout()->setContentsMargins(0, 0, 0, 0); refreshProjection(); + connect(mQGView.data(), &QGVMapQGView::dropData, this, &QGVMap::handleDropDataOnQGVMapQGView); } QGVMap::~QGVMap() @@ -381,6 +382,13 @@ void QGVMap::mousePressEvent(QMouseEvent* event) QWidget::mousePressEvent(event); } +void QGVMap::handleDropDataOnQGVMapQGView(QPointF position, const QMimeData* dropData) +{ + const auto mapToProjectionPos = mapToProj(QPoint(position.rx(), position.ry())); + auto geoPos = getProjection()->projToGeo(mapToProjectionPos); + Q_EMIT dropOnMap(geoPos, dropData); +} + void QGVMap::mouseDoubleClickEvent(QMouseEvent* event) { if (hasMouseTracking()) { diff --git a/lib/src/QGVMapQGView.cpp b/lib/src/QGVMapQGView.cpp index 5d00c2b..ee2bd7c 100644 --- a/lib/src/QGVMapQGView.cpp +++ b/lib/src/QGVMapQGView.cpp @@ -66,6 +66,7 @@ QGVMapQGView::QGVMapQGView(QGVMap* geoMap) setCacheMode(QGraphicsView::CacheBackground); setMouseTracking(true); setBackgroundBrush(QBrush(Qt::lightGray)); + setAcceptDrops(true); } void QGVMapQGView::setMouseActions(QGV::MouseActions actions) @@ -599,3 +600,29 @@ void QGVMapQGView::keyPressEvent(QKeyEvent* event) { QWidget::keyPressEvent(event); } + +void QGVMapQGView::dragEnterEvent(QDragEnterEvent* event) +{ + event->accept(); +} + +void QGVMapQGView::dragMoveEvent(QDragMoveEvent* event) +{ + event->accept(); +} + +void QGVMapQGView::dropEvent(QDropEvent* event) +{ +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + Q_EMIT dropData(event->position(), event->mimeData()); +#else + QPointF dropPoint = event->posF(); + Q_EMIT dropData(dropPoint, event->mimeData()); +#endif + event->accept(); +} + +void QGVMapQGView::dragLeaveEvent(QDragLeaveEvent* event) +{ + event->accept(); +} diff --git a/samples/drag-and-drop/CMakeLists.txt b/samples/drag-and-drop/CMakeLists.txt new file mode 100644 index 0000000..b50b775 --- /dev/null +++ b/samples/drag-and-drop/CMakeLists.txt @@ -0,0 +1,37 @@ +set(CMAKE_CXX_STANDARD 11) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +# Set the QT version +find_package(Qt6 COMPONENTS Core QUIET) +if (NOT Qt6_FOUND) + set(QT_VERSION 5 CACHE STRING "Qt version for QGeoView") +else() + set(QT_VERSION 6 CACHE STRING "Qt version for QGeoView") +endif() + +find_package(Qt${QT_VERSION} REQUIRED COMPONENTS + Core + Gui + Widgets + Network +) + +add_executable(qgeoview-samples-drag-and-drop + main.cpp + mainwindow.h + mainwindow.cpp +) + +target_link_libraries(qgeoview-samples-drag-and-drop + PRIVATE + Qt${QT_VERSION}::Core + Qt${QT_VERSION}::Network + Qt${QT_VERSION}::Gui + Qt${QT_VERSION}::Widgets + QGeoView + qgeoview-samples-shared +) diff --git a/samples/drag-and-drop/drag-and-drop.pro b/samples/drag-and-drop/drag-and-drop.pro new file mode 100644 index 0000000..22debf1 --- /dev/null +++ b/samples/drag-and-drop/drag-and-drop.pro @@ -0,0 +1,15 @@ +TARGET = qgeoview-samples-drag-and-drop +TEMPLATE = app +CONFIG-= console + +QT += gui widgets network + +include(../lib.pri) +include(../shared.pri) + +SOURCES += \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h diff --git a/samples/drag-and-drop/main.cpp b/samples/drag-and-drop/main.cpp new file mode 100644 index 0000000..6c72f24 --- /dev/null +++ b/samples/drag-and-drop/main.cpp @@ -0,0 +1,37 @@ +/*************************************************************************** + * QGeoView is a Qt / C ++ widget for visualizing geographic data. + * Copyright (C) 2018-2023 Andrey Yaroshenko. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see https://www.gnu.org/licenses. + ****************************************************************************/ + +#include +#include + +#include "mainwindow.h" + +int main(int argc, char* argv[]) +{ + QApplication app(argc, argv); + app.setApplicationName("QGeoView Samples"); + + QCommandLineParser parser; + parser.addHelpOption(); + parser.addVersionOption(); + parser.process(app); + + MainWindow window; + window.show(); + return app.exec(); +} diff --git a/samples/drag-and-drop/mainwindow.cpp b/samples/drag-and-drop/mainwindow.cpp new file mode 100644 index 0000000..5a5f131 --- /dev/null +++ b/samples/drag-and-drop/mainwindow.cpp @@ -0,0 +1,143 @@ +/*************************************************************************** + * QGeoView is a Qt / C ++ widget for visualizing geographic data. + * Copyright (C) 2018-2023 Andrey Yaroshenko. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see https://www.gnu.org/licenses. + ****************************************************************************/ + +#include "mainwindow.h" + +#include +#include +#include +#include +#include +#include + +//#include +#include +#include +#include + +MainWindow::MainWindow(QWidget* parent) + : QMainWindow(parent) +{ + setWindowTitle("QGeoView Samples - drag and drop"); + setCentralWidget(new QWidget()); + centralWidget()->setLayout(new QHBoxLayout()); + + // setup tree widget + sampleTree = new QTreeWidget(this); + sampleTree->setDragEnabled(true); // enable dragging items from the tree + sampleTree->setMinimumWidth(200); + sampleTree->setMaximumWidth(250); + + // setup data into the tree widget + sampleTree->setColumnCount(1); + sampleTree->setHeaderLabel("Sample Tree Items with Icons"); + + QTreeWidgetItem* itemArrowUp = new QTreeWidgetItem; + QIcon arrowUp_icon = QApplication::style()->standardIcon(QStyle::SP_ArrowUp); + itemArrowUp->setData(0, Qt::DisplayRole, "Arrow Up"); + itemArrowUp->setData(0, Qt::DecorationRole, arrowUp_icon); + sampleTree->addTopLevelItem(itemArrowUp); + + QTreeWidgetItem* itemArrowDown = new QTreeWidgetItem; + QIcon arrowDown_icon = QApplication::style()->standardIcon(QStyle::SP_ArrowDown); + itemArrowDown->setData(0, Qt::DisplayRole, "Arrow Down"); + itemArrowDown->setData(0, Qt::DecorationRole, arrowDown_icon); + sampleTree->addTopLevelItem(itemArrowDown); + + QTreeWidgetItem* itemArrowRight = new QTreeWidgetItem; + QIcon arrowRight_icon = QApplication::style()->standardIcon(QStyle::SP_ArrowRight); + itemArrowRight->setData(0, Qt::DisplayRole, "Arrow Right"); + itemArrowRight->setData(0, Qt::DecorationRole, arrowRight_icon); + sampleTree->addTopLevelItem(itemArrowRight); + + QTreeWidgetItem* itemArrowLeft = new QTreeWidgetItem; + QIcon arrowLeft_icon = QApplication::style()->standardIcon(QStyle::SP_ArrowLeft); + itemArrowLeft->setData(0, Qt::DisplayRole, "Arrow Left"); + itemArrowLeft->setData(0, Qt::DecorationRole, arrowLeft_icon); + sampleTree->addTopLevelItem(itemArrowLeft); + + centralWidget()->layout()->addWidget(sampleTree); + + // QGeoView setup + Helpers::setupCachedNetworkAccessManager(this); + mMap = new QGVMap(this); + + // Background layer + // QGVLayer * layerBDGExCTM250 = new QGVLayerBDGEx(QGV::BDGExLayer::ctm250); + // layerBDGExCTM250->setName("BDGEx CTM250"); + // mMap->addItem(layerBDGExCTM250); + + QGVLayer* layerGoogleSchema = new QGVLayerGoogle(QGV::TilesType::Schema); + layerGoogleSchema->setName("Google Schema"); + mMap->addItem(layerGoogleSchema); + + // initial area to show + QTimer::singleShot(500, this, &MainWindow::targetArea); + centralWidget()->layout()->addWidget(mMap); // add map to central widget + + // handle drop of itens on map + connect(mMap, &QGVMap::dropOnMap, this, &MainWindow::handleDropOnMap); + iconsLayer = new QGVLayer(); + mMap->addItem(iconsLayer); +} + +MainWindow::~MainWindow() +{ +} + +void MainWindow::targetArea() +{ + QGV::GeoPos geoPos(-23.55651916354534, -46.61844717963553); + auto scaleRect = QGV::GeoRect{ + geoPos.latitude() - 0.33, geoPos.longitude() - 0.33, geoPos.latitude() + 0.33, geoPos.longitude() + 0.33 + }; + mMap->cameraTo(QGVCameraActions(mMap).scaleTo(scaleRect)); + return; +} + +void MainWindow::handleDropOnMap(QGV::GeoPos pos, const QMimeData* data) +{ + QByteArray encoded = data->data("application/x-qabstractitemmodeldatalist"); + QDataStream stream(&encoded, QIODevice::ReadOnly); + QIcon iconDropped; + QString strDropped; + while (!stream.atEnd()) { + int row, col; + QMap roleDataMap; + stream >> row >> col >> roleDataMap; + for (auto i = 0; i < roleDataMap.size(); i++) { + std::string typeName = roleDataMap[i].typeName(); + auto variant = roleDataMap[i]; + if (typeName == "QString") { + strDropped = qvariant_cast(variant); + } + if (typeName == "QIcon") { + iconDropped = qvariant_cast(variant); + } + } + } + qDebug() << strDropped << "(lat, lon):" << pos.latToString() << pos.lonToString(); + if (!iconDropped.isNull() && !strDropped.isEmpty()) { + auto* mIcon = new QGVIcon(); + auto pixmap = iconDropped.pixmap(QSize(32, 32)); + auto image = pixmap.toImage(); + mIcon->loadImage(image); + mIcon->setGeometry(pos, QSizeF(32, 32)); + iconsLayer->addItem(mIcon); + } +} diff --git a/samples/drag-and-drop/mainwindow.h b/samples/drag-and-drop/mainwindow.h new file mode 100644 index 0000000..d3ed637 --- /dev/null +++ b/samples/drag-and-drop/mainwindow.h @@ -0,0 +1,43 @@ +/*************************************************************************** + * QGeoView is a Qt / C ++ widget for visualizing geographic data. + * Copyright (C) 2018-2023 Andrey Yaroshenko. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, see https://www.gnu.org/licenses. + ****************************************************************************/ + +#pragma once + +#include + +#include +#include + +#include +#include + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + MainWindow(QWidget* parent = nullptr); + ~MainWindow(); + +private: + QTreeWidget* sampleTree; + QGVMap* mMap; + QGVLayer* iconsLayer; + void targetArea(); + void handleDropOnMap(QGV::GeoPos pos, const QMimeData* data); +};