diff --git a/mapeditor/mainwindow.cpp b/mapeditor/mainwindow.cpp
index 3acf2d678..73b6d1524 100644
--- a/mapeditor/mainwindow.cpp
+++ b/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);
@@ -853,12 +853,11 @@ void MainWindow::on_toolErase_clicked()
ui->tabWidget->setCurrentIndex(0);
}
-void MainWindow::preparePreview(const QModelIndex &index, bool createNew)
+void MainWindow::preparePreview(const QModelIndex &index)
{
scenePreview->clear();
auto data = objectsModel.itemFromIndex(objectBrowser->mapToSource(index))->data().toJsonObject();
-
if(!data.empty())
{
auto preview = data["preview"];
@@ -866,29 +865,12 @@ void MainWindow::preparePreview(const QModelIndex &index, bool createNew)
{
QPixmap objPreview = pixmapFromJson(preview);
scenePreview->addPixmap(objPreview);
-
- auto objId = data["id"].toInt();
- auto objSubId = data["subid"].toInt();
- auto templateId = data["template"].toInt();
-
- if(controller.discardObject(mapLevel) || createNew)
- {
- auto factory = VLC->objtypeh->getHandlerFor(objId, objSubId);
- auto templ = factory->getTemplates()[templateId];
- controller.createObject(mapLevel, factory->create(templ));
- }
}
}
}
void MainWindow::treeViewSelected(const QModelIndex & index, const QModelIndex & deselected)
-{
- preparePreview(index, false);
-}
-
-
-void MainWindow::on_treeView_activated(const QModelIndex &index)
{
ui->toolBrush->setChecked(false);
ui->toolBrush2->setChecked(false);
@@ -896,11 +878,10 @@ void MainWindow::on_treeView_activated(const QModelIndex &index)
ui->toolArea->setChecked(false);
ui->toolLasso->setChecked(false);
ui->mapView->selectionTool = MapView::SelectionTool::None;
-
- preparePreview(index, true);
+
+ preparePreview(index);
}
-
void MainWindow::on_terrainFilterCombo_currentTextChanged(const QString &arg1)
{
if(!objectBrowser)
diff --git a/mapeditor/mainwindow.h b/mapeditor/mainwindow.h
index 3028c6b25..a728c87dc 100644
--- a/mapeditor/mainwindow.h
+++ b/mapeditor/mainwindow.h
@@ -8,7 +8,7 @@
#include "resourceExtractor/ResourceConverter.h"
class CMap;
-class ObjectBrowser;
+class ObjectBrowserProxyModel;
class CGObjectInstance;
namespace Ui
@@ -74,8 +74,6 @@ private slots:
void on_toolErase_clicked();
- void on_treeView_activated(const QModelIndex &index);
-
void on_terrainFilterCombo_currentTextChanged(const QString &arg1);
void on_filter_textChanged(const QString &arg1);
@@ -113,7 +111,7 @@ public slots:
void displayStatus(const QString& message, int timeout = 2000);
private:
- void preparePreview(const QModelIndex &index, bool createNew);
+ void preparePreview(const QModelIndex & index);
void addGroupIntoCatalog(const std::string & groupName, bool staticOnly);
void addGroupIntoCatalog(const std::string & groupName, bool useCustomName, bool staticOnly, int ID);
@@ -133,7 +131,7 @@ private:
private:
Ui::MainWindow * ui;
- ObjectBrowser * objectBrowser = nullptr;
+ ObjectBrowserProxyModel * objectBrowser = nullptr;
QGraphicsScene * scenePreview;
QString filename;
diff --git a/mapeditor/mainwindow.ui b/mapeditor/mainwindow.ui
index 1b266eaec..6da92787e 100644
--- a/mapeditor/mainwindow.ui
+++ b/mapeditor/mainwindow.ui
@@ -303,7 +303,7 @@
-
-
+
0
@@ -319,8 +319,11 @@
QAbstractItemView::NoEditTriggers
+
+ false
+
- QAbstractItemView::NoDragDrop
+ QAbstractItemView::DragOnly
QAbstractItemView::SelectItems
@@ -1206,6 +1209,11 @@
QGraphicsView
+
+ ObjectBrowser
+ QTreeView
+
+
diff --git a/mapeditor/mapview.cpp b/mapeditor/mapview.cpp
index d9460d7a4..c719b80f1 100644
--- a/mapeditor/mapview.cpp
+++ b/mapeditor/mapview.cpp
@@ -13,6 +13,7 @@
#include "mainwindow.h"
#include
#include "mapcontroller.h"
+#include "../lib/mapObjects/CObjectClassesHandler.h"
MinimapView::MinimapView(QWidget * parent):
QGraphicsView(parent)
@@ -64,12 +65,10 @@ MapView::MapView(QWidget * parent):
void MapView::cameraChanged(const QPointF & pos)
{
- //ui->mapView->translate(pos.x(), pos.y());
horizontalScrollBar()->setValue(pos.x());
verticalScrollBar()->setValue(pos.y());
}
-
void MapView::setController(MapController * ctrl)
{
controller = ctrl;
@@ -85,7 +84,12 @@ void MapView::mouseMoveEvent(QMouseEvent *mouseEvent)
auto pos = mapToScene(mouseEvent->pos()); //TODO: do we need to check size?
int3 tile(pos.x() / 32, pos.y() / 32, sc->level);
-
+
+ //if scene will be scrolled without mouse movement, selection, object moving and rubber band will not be updated
+ //to change this behavior, all this logic should be placed in viewportEvent
+ if(rubberBand)
+ rubberBand->setGeometry(QRect(mapFromScene(mouseStart), mouseEvent->pos()).normalized());
+
if(tile == tilePrev) //do not redraw
return;
@@ -161,13 +165,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)
{
@@ -296,6 +294,11 @@ void MapView::mousePressEvent(QMouseEvent *event)
{
sc->selectionObjectsView.clear();
sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::SELECTION;
+
+ if(!rubberBand)
+ rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
+ rubberBand->setGeometry(QRect(mapFromScene(mouseStart), QSize()));
+ rubberBand->show();
}
}
sc->selectionObjectsView.shift = QPoint(0, 0);
@@ -314,6 +317,9 @@ void MapView::mouseReleaseEvent(QMouseEvent *event)
auto * sc = static_cast(scene());
if(!sc || !controller->map())
return;
+
+ if(rubberBand)
+ rubberBand->hide();
switch(selectionTool)
{
@@ -324,19 +330,7 @@ void MapView::mouseReleaseEvent(QMouseEvent *event)
bool tab = false;
if(sc->selectionObjectsView.selectionMode == SelectionObjectsLayer::MOVEMENT)
{
- if(sc->selectionObjectsView.newObject)
- {
- QString errorMsg;
- if(controller->canPlaceObject(sc->level, sc->selectionObjectsView.newObject, errorMsg))
- controller->commitObjectCreate(sc->level);
- else
- {
- QMessageBox::information(this, "Can't place object", errorMsg);
- break;
- }
- }
- else
- controller->commitObjectShift(sc->level);
+ controller->commitObjectShift(sc->level);
}
else
{
@@ -355,11 +349,105 @@ void MapView::mouseReleaseEvent(QMouseEvent *event)
}
}
+void MapView::dragEnterEvent(QDragEnterEvent * event)
+{
+ if(!controller || !controller->map())
+ return;
+
+ auto * sc = static_cast(scene());
+ if(!sc)
+ return;
+
+ if(event->mimeData()->hasFormat("application/vcmi.object"))
+ {
+ auto encodedData = event->mimeData()->data("application/vcmi.object");
+ QDataStream stream(&encodedData, QIODevice::ReadOnly);
+ QVariant vdata;
+ stream >> vdata;
+ auto data = vdata.toJsonObject();
+ 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(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(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(scene());
+ if(!sc)
+ return;
+
+ controller->discardObject(sc->level);
+}
+
+
bool MapView::viewportEvent(QEvent *event)
{
if(auto * sc = static_cast(scene()))
{
- //auto rect = sceneRect();
auto rect = mapToScene(viewport()->geometry()).boundingRect();
controller->miniScene(sc->level)->viewport.setViewport(rect.x() / 32, rect.y() / 32, rect.width() / 32, rect.height() / 32);
}
diff --git a/mapeditor/mapview.h b/mapeditor/mapview.h
index 13caabb97..427271a29 100644
--- a/mapeditor/mapview.h
+++ b/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);
@@ -110,6 +114,7 @@ protected:
private:
MapController * controller = nullptr;
+ QRubberBand * rubberBand = nullptr;
QPointF mouseStart;
int3 tileStart;
int3 tilePrev;
@@ -127,7 +132,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);
diff --git a/mapeditor/objectbrowser.cpp b/mapeditor/objectbrowser.cpp
index 416b8abfa..b0cc1f707 100644
--- a/mapeditor/objectbrowser.cpp
+++ b/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,64 @@ 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(sourceModel());
+ assert(standardModel);
+
+ QModelIndex index = indexes.front();
+ QByteArray encodedData;
+
+ QDataStream stream(&encodedData, QIODevice::WriteOnly);
+
+ if(!index.isValid())
+ return nullptr;
+
+ auto text = standardModel->itemFromIndex(mapToSource(index))->data();
+ stream << text;
+
+ QMimeData * mimeData = new QMimeData;
+ mimeData->setData("application/vcmi.object", encodedData);
+ return mimeData;
+}
+
+ObjectBrowser::ObjectBrowser(QWidget * parent):
+ QTreeView(parent)
+{
+ setDropIndicatorShown(false);
+}
+
+void ObjectBrowser::startDrag(Qt::DropActions supportedActions)
+{
+ QDrag *drag = new QDrag(this);
+ auto indexes = selectedIndexes();
+ if(indexes.isEmpty())
+ return;
+
+ QMimeData * mimeData = model()->mimeData(indexes);
+ if(!mimeData)
+ return;
+
+ drag->setMimeData(mimeData);
+
+ Qt::DropAction dropAction = drag->exec();
+}
diff --git a/mapeditor/objectbrowser.h b/mapeditor/objectbrowser.h
index 6c700ae62..2282cf695 100644
--- a/mapeditor/objectbrowser.h
+++ b/mapeditor/objectbrowser.h
@@ -13,10 +13,16 @@
#include
#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,12 @@ 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);
+
+protected:
+ void startDrag(Qt::DropActions supportedActions) override;
+};
diff --git a/mapeditor/scenelayer.cpp b/mapeditor/scenelayer.cpp
index e9d39eb97..8edcaa665 100644
--- a/mapeditor/scenelayer.cpp
+++ b/mapeditor/scenelayer.cpp
@@ -390,7 +390,7 @@ void SelectionObjectsLayer::draw()
//show translation
if(selectionMode == SelectionMode::MOVEMENT && (shift.x() || shift.y()))
{
- painter.setOpacity(0.5);
+ painter.setOpacity(0.7);
auto newPos = QPoint(obj->getPosition().x, obj->getPosition().y) + shift;
handler->drawObjectAt(painter, obj, newPos.x(), newPos.y());
}
diff --git a/mapeditor/scenelayer.h b/mapeditor/scenelayer.h
index 49d1ff083..7b99b4df1 100644
--- a/mapeditor/scenelayer.h
+++ b/mapeditor/scenelayer.h
@@ -144,7 +144,6 @@ public:
void deselectObject(CGObjectInstance *);
bool isSelected(const CGObjectInstance *) const;
std::set getSelection() const;
- void moveSelection(int x, int y);
void clear();
QPoint shift;