ソースを参照

Drag drop works for objects

nordsoft 2 年 前
コミット
8dc0682d81

+ 1 - 1
mapeditor/mainwindow.cpp

@@ -550,7 +550,7 @@ void MainWindow::loadObjectsTree()
 
 	//model
 	objectsModel.setHorizontalHeaderLabels(QStringList() << tr("Type"));
-	objectBrowser = new ObjectBrowser(this);
+	objectBrowser = new ObjectBrowserProxyModel(this);
 	objectBrowser->setSourceModel(&objectsModel);
 	objectBrowser->setDynamicSortFilter(false);
 	objectBrowser->setRecursiveFilteringEnabled(true);

+ 2 - 2
mapeditor/mainwindow.h

@@ -8,7 +8,7 @@
 #include "resourceExtractor/ResourceConverter.h"
 
 class CMap;
-class ObjectBrowser;
+class ObjectBrowserProxyModel;
 class CGObjectInstance;
 
 namespace Ui
@@ -133,7 +133,7 @@ private:
 
 private:
     Ui::MainWindow * ui;
-	ObjectBrowser * objectBrowser = nullptr;
+	ObjectBrowserProxyModel * objectBrowser = nullptr;
 	QGraphicsScene * scenePreview;
 	
 	QString filename;

+ 10 - 2
mapeditor/mainwindow.ui

@@ -303,7 +303,7 @@
           <widget class="QLineEdit" name="filter"/>
          </item>
          <item>
-          <widget class="QTreeView" name="treeView">
+          <widget class="ObjectBrowser" name="treeView">
            <property name="sizePolicy">
             <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
              <horstretch>0</horstretch>
@@ -319,8 +319,11 @@
            <property name="editTriggers">
             <set>QAbstractItemView::NoEditTriggers</set>
            </property>
+           <property name="showDropIndicator" stdset="0">
+            <bool>false</bool>
+           </property>
            <property name="dragDropMode">
-            <enum>QAbstractItemView::NoDragDrop</enum>
+            <enum>QAbstractItemView::DragOnly</enum>
            </property>
            <property name="selectionBehavior">
             <enum>QAbstractItemView::SelectItems</enum>
@@ -1206,6 +1209,11 @@
    <extends>QGraphicsView</extends>
    <header>mapview.h</header>
   </customwidget>
+  <customwidget>
+   <class>ObjectBrowser</class>
+   <extends>QTreeView</extends>
+   <header>objectbrowser.h</header>
+  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>

+ 99 - 10
mapeditor/mapview.cpp

@@ -13,6 +13,7 @@
 #include "mainwindow.h"
 #include <QGraphicsSceneMouseEvent>
 #include "mapcontroller.h"
+#include "../lib/mapObjects/CObjectClassesHandler.h"
 
 MinimapView::MinimapView(QWidget * parent):
 	QGraphicsView(parent)
@@ -161,13 +162,7 @@ void MapView::mouseMoveEvent(QMouseEvent *mouseEvent)
 
 		if(sh.x || sh.y)
 		{
-			if(sc->selectionObjectsView.newObject)
-			{
-				sc->selectionObjectsView.shift = QPoint(tile.x, tile.y);
-				sc->selectionObjectsView.selectObject(sc->selectionObjectsView.newObject);
-				sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::MOVEMENT;
-			}
-			else if(mouseEvent->buttons() & Qt::LeftButton)
+			if(sc->selectionObjectsView.newObject && (mouseEvent->buttons() & Qt::LeftButton))
 			{
 				if(sc->selectionObjectsView.selectionMode == SelectionObjectsLayer::SELECTION)
 				{
@@ -324,7 +319,7 @@ void MapView::mouseReleaseEvent(QMouseEvent *event)
 		bool tab = false;
 		if(sc->selectionObjectsView.selectionMode == SelectionObjectsLayer::MOVEMENT)
 		{
-			if(sc->selectionObjectsView.newObject)
+			/*if(sc->selectionObjectsView.newObject)
 			{
 				QString errorMsg;
 				if(controller->canPlaceObject(sc->level, sc->selectionObjectsView.newObject, errorMsg))
@@ -335,8 +330,8 @@ void MapView::mouseReleaseEvent(QMouseEvent *event)
 					break;
 				}
 			}
-			else
-				controller->commitObjectShift(sc->level);
+			else*/
+			controller->commitObjectShift(sc->level);
 		}
 		else
 		{
@@ -355,6 +350,100 @@ void MapView::mouseReleaseEvent(QMouseEvent *event)
 	}
 }
 
+void MapView::dragEnterEvent(QDragEnterEvent * event)
+{
+	if(!controller || !controller->map())
+		return;
+	
+	auto * sc = static_cast<MapScene*>(scene());
+	if(!sc)
+		return;
+	
+	if(event->mimeData()->hasFormat("application/vcmi.object"))
+	{
+		auto encodedData = event->mimeData()->data("application/vcmi.object");
+		QDataStream stream(&encodedData, QIODevice::ReadOnly);
+		QJsonObject data;
+		stream >> data;
+		if(!data.empty())
+		{
+			auto preview = data["preview"];
+			if(preview != QJsonValue::Undefined)
+			{
+				auto objId = data["id"].toInt();
+				auto objSubId = data["subid"].toInt();
+				auto templateId = data["template"].toInt();
+				auto factory = VLC->objtypeh->getHandlerFor(objId, objSubId);
+				auto templ = factory->getTemplates()[templateId];
+				controller->discardObject(sc->level);
+				controller->createObject(sc->level, factory->create(templ));
+			}
+		}
+		
+		event->acceptProposedAction();
+	}
+}
+
+void MapView::dropEvent(QDropEvent * event)
+{
+	if(!controller || !controller->map())
+		return;
+	
+	auto * sc = static_cast<MapScene*>(scene());
+	if(!sc)
+		return;
+	
+	if(sc->selectionObjectsView.newObject)
+	{
+		QString errorMsg;
+		if(controller->canPlaceObject(sc->level, sc->selectionObjectsView.newObject, errorMsg))
+		{
+			controller->commitObjectCreate(sc->level);
+		}
+		else
+		{
+			controller->discardObject(sc->level);
+			QMessageBox::information(this, "Can't place object", errorMsg);
+		}
+	}
+
+	event->acceptProposedAction();
+}
+
+void MapView::dragMoveEvent(QDragMoveEvent * event)
+{
+	auto * sc = static_cast<MapScene*>(scene());
+	if(!sc)
+		return;
+	
+	auto rect = event->answerRect();
+	auto pos = mapToScene(rect.bottomRight()); //TODO: do we need to check size?
+	int3 tile(pos.x() / 32 + 1, pos.y() / 32 + 1, sc->level);
+	
+	if(sc->selectionObjectsView.newObject)
+	{
+		sc->selectionObjectsView.shift = QPoint(tile.x, tile.y);
+		sc->selectionObjectsView.selectObject(sc->selectionObjectsView.newObject);
+		sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::MOVEMENT;
+		sc->selectionObjectsView.draw();
+	}
+	
+	event->acceptProposedAction();
+}
+
+void MapView::dragLeaveEvent(QDragLeaveEvent * event)
+{
+	if(!controller || !controller->map())
+		return;
+	
+	auto * sc = static_cast<MapScene*>(scene());
+	if(!sc)
+		return;
+	
+	controller->discardObject(sc->level);
+}
+
+
 bool MapView::viewportEvent(QEvent *event)
 {
 	if(auto * sc = static_cast<MapScene*>(scene()))

+ 5 - 1
mapeditor/mapview.h

@@ -98,6 +98,10 @@ public slots:
 	void mouseMoveEvent(QMouseEvent * mouseEvent) override;
 	void mousePressEvent(QMouseEvent *event) override;
 	void mouseReleaseEvent(QMouseEvent *event) override;
+	void dragEnterEvent(QDragEnterEvent * event) override;
+	void dragMoveEvent(QDragMoveEvent *event) override;
+	void dragLeaveEvent(QDragLeaveEvent *event) override;
+	void dropEvent(QDropEvent * event) override;
 	
 	void cameraChanged(const QPointF & pos);
 	
@@ -127,7 +131,7 @@ public:
 	
 public slots:
 	void mouseMoveEvent(QMouseEvent * mouseEvent) override;
-	void mousePressEvent(QMouseEvent* event) override;
+	void mousePressEvent(QMouseEvent * event) override;
 	
 signals:
 	void cameraPositionChanged(const QPointF & newPosition);

+ 48 - 3
mapeditor/objectbrowser.cpp

@@ -12,12 +12,12 @@
 #include "objectbrowser.h"
 #include "../lib/mapObjects/CObjectClassesHandler.h"
 
-ObjectBrowser::ObjectBrowser(QObject *parent)
+ObjectBrowserProxyModel::ObjectBrowserProxyModel(QObject *parent)
 	: QSortFilterProxyModel{parent}, terrain(Terrain::ANY_TERRAIN)
 {
 }
 
-bool ObjectBrowser::filterAcceptsRow(int source_row, const QModelIndex & source_parent) const
+bool ObjectBrowserProxyModel::filterAcceptsRow(int source_row, const QModelIndex & source_parent) const
 {
 	bool result = QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
 
@@ -57,7 +57,7 @@ bool ObjectBrowser::filterAcceptsRow(int source_row, const QModelIndex & source_
 	return result;
 }
 
-bool ObjectBrowser::filterAcceptsRowText(int source_row, const QModelIndex &source_parent) const
+bool ObjectBrowserProxyModel::filterAcceptsRowText(int source_row, const QModelIndex &source_parent) const
 {
 	if(source_parent.isValid())
 	{
@@ -76,3 +76,48 @@ bool ObjectBrowser::filterAcceptsRowText(int source_row, const QModelIndex &sour
 	return (filter.isNull() || filter.isEmpty() || item->text().contains(filter, Qt::CaseInsensitive));
 }
 
+Qt::ItemFlags ObjectBrowserProxyModel::flags(const QModelIndex & index) const
+{
+	Qt::ItemFlags defaultFlags = QSortFilterProxyModel::flags(index);
+
+	if (index.isValid())
+		return Qt::ItemIsDragEnabled | defaultFlags;
+	
+	return defaultFlags;
+}
+
+QStringList ObjectBrowserProxyModel::mimeTypes() const
+{
+	QStringList types;
+	types << "application/vcmi.object";
+	return types;
+}
+
+QMimeData * ObjectBrowserProxyModel::mimeData(const QModelIndexList & indexes) const
+{
+	assert(indexes.size() == 1);
+	
+	auto * standardModel = qobject_cast<QStandardItemModel*>(sourceModel());
+	assert(standardModel);
+	
+	QModelIndex index = indexes.front();
+	QMimeData * mimeData = new QMimeData;
+	QByteArray encodedData;
+
+	QDataStream stream(&encodedData, QIODevice::WriteOnly);
+	
+	if(index.isValid())
+	{
+		auto text = standardModel->itemFromIndex(mapToSource(index))->data().toJsonObject();
+		stream << text;
+	}
+
+	mimeData->setData("application/vcmi.object", encodedData);
+	return mimeData;
+}
+
+ObjectBrowser::ObjectBrowser(QWidget * parent):
+	QTreeView(parent)
+{
+	
+}

+ 14 - 2
mapeditor/objectbrowser.h

@@ -13,10 +13,16 @@
 #include <QSortFilterProxyModel>
 #include "../lib/Terrain.h"
 
-class ObjectBrowser : public QSortFilterProxyModel
+class ObjectBrowserProxyModel : public QSortFilterProxyModel
 {
 public:
-	explicit ObjectBrowser(QObject *parent = nullptr);
+	explicit ObjectBrowserProxyModel(QObject *parent = nullptr);
+	
+	Qt::ItemFlags flags(const QModelIndex &index) const override;
+	
+	QStringList mimeTypes() const override;
+	
+	QMimeData * mimeData(const QModelIndexList & indexes) const override;
 
 	TerrainId terrain;
 	QString filter;
@@ -25,3 +31,9 @@ protected:
 	bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override;
 	bool filterAcceptsRowText(int source_row, const QModelIndex &source_parent) const;
 };
+
+class ObjectBrowser : public QTreeView
+{
+public:
+	ObjectBrowser(QWidget * parent);
+};