1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-11-24 08:32:34 +02:00

Merge pull request #1195 from Nordsoft91/editor-drapndrop

This commit is contained in:
Nordsoft91 2022-12-09 12:05:56 +04:00 committed by GitHub
commit be6b5fc0e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 217 additions and 62 deletions

View File

@ -550,7 +550,7 @@ void MainWindow::loadObjectsTree()
//model //model
objectsModel.setHorizontalHeaderLabels(QStringList() << tr("Type")); objectsModel.setHorizontalHeaderLabels(QStringList() << tr("Type"));
objectBrowser = new ObjectBrowser(this); objectBrowser = new ObjectBrowserProxyModel(this);
objectBrowser->setSourceModel(&objectsModel); objectBrowser->setSourceModel(&objectsModel);
objectBrowser->setDynamicSortFilter(false); objectBrowser->setDynamicSortFilter(false);
objectBrowser->setRecursiveFilteringEnabled(true); objectBrowser->setRecursiveFilteringEnabled(true);
@ -853,12 +853,11 @@ void MainWindow::on_toolErase_clicked()
ui->tabWidget->setCurrentIndex(0); ui->tabWidget->setCurrentIndex(0);
} }
void MainWindow::preparePreview(const QModelIndex &index, bool createNew) void MainWindow::preparePreview(const QModelIndex &index)
{ {
scenePreview->clear(); scenePreview->clear();
auto data = objectsModel.itemFromIndex(objectBrowser->mapToSource(index))->data().toJsonObject(); auto data = objectsModel.itemFromIndex(objectBrowser->mapToSource(index))->data().toJsonObject();
if(!data.empty()) if(!data.empty())
{ {
auto preview = data["preview"]; auto preview = data["preview"];
@ -866,29 +865,12 @@ void MainWindow::preparePreview(const QModelIndex &index, bool createNew)
{ {
QPixmap objPreview = pixmapFromJson(preview); QPixmap objPreview = pixmapFromJson(preview);
scenePreview->addPixmap(objPreview); 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) 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->toolBrush->setChecked(false);
ui->toolBrush2->setChecked(false); ui->toolBrush2->setChecked(false);
@ -896,11 +878,10 @@ void MainWindow::on_treeView_activated(const QModelIndex &index)
ui->toolArea->setChecked(false); ui->toolArea->setChecked(false);
ui->toolLasso->setChecked(false); ui->toolLasso->setChecked(false);
ui->mapView->selectionTool = MapView::SelectionTool::None; ui->mapView->selectionTool = MapView::SelectionTool::None;
preparePreview(index, true); preparePreview(index);
} }
void MainWindow::on_terrainFilterCombo_currentTextChanged(const QString &arg1) void MainWindow::on_terrainFilterCombo_currentTextChanged(const QString &arg1)
{ {
if(!objectBrowser) if(!objectBrowser)

View File

@ -8,7 +8,7 @@
#include "resourceExtractor/ResourceConverter.h" #include "resourceExtractor/ResourceConverter.h"
class CMap; class CMap;
class ObjectBrowser; class ObjectBrowserProxyModel;
class CGObjectInstance; class CGObjectInstance;
namespace Ui namespace Ui
@ -74,8 +74,6 @@ private slots:
void on_toolErase_clicked(); void on_toolErase_clicked();
void on_treeView_activated(const QModelIndex &index);
void on_terrainFilterCombo_currentTextChanged(const QString &arg1); void on_terrainFilterCombo_currentTextChanged(const QString &arg1);
void on_filter_textChanged(const QString &arg1); void on_filter_textChanged(const QString &arg1);
@ -113,7 +111,7 @@ public slots:
void displayStatus(const QString& message, int timeout = 2000); void displayStatus(const QString& message, int timeout = 2000);
private: 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 staticOnly);
void addGroupIntoCatalog(const std::string & groupName, bool useCustomName, bool staticOnly, int ID); void addGroupIntoCatalog(const std::string & groupName, bool useCustomName, bool staticOnly, int ID);
@ -133,7 +131,7 @@ private:
private: private:
Ui::MainWindow * ui; Ui::MainWindow * ui;
ObjectBrowser * objectBrowser = nullptr; ObjectBrowserProxyModel * objectBrowser = nullptr;
QGraphicsScene * scenePreview; QGraphicsScene * scenePreview;
QString filename; QString filename;

View File

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

View File

@ -13,6 +13,7 @@
#include "mainwindow.h" #include "mainwindow.h"
#include <QGraphicsSceneMouseEvent> #include <QGraphicsSceneMouseEvent>
#include "mapcontroller.h" #include "mapcontroller.h"
#include "../lib/mapObjects/CObjectClassesHandler.h"
MinimapView::MinimapView(QWidget * parent): MinimapView::MinimapView(QWidget * parent):
QGraphicsView(parent) QGraphicsView(parent)
@ -64,12 +65,10 @@ MapView::MapView(QWidget * parent):
void MapView::cameraChanged(const QPointF & pos) void MapView::cameraChanged(const QPointF & pos)
{ {
//ui->mapView->translate(pos.x(), pos.y());
horizontalScrollBar()->setValue(pos.x()); horizontalScrollBar()->setValue(pos.x());
verticalScrollBar()->setValue(pos.y()); verticalScrollBar()->setValue(pos.y());
} }
void MapView::setController(MapController * ctrl) void MapView::setController(MapController * ctrl)
{ {
controller = ctrl; controller = ctrl;
@ -85,7 +84,12 @@ void MapView::mouseMoveEvent(QMouseEvent *mouseEvent)
auto pos = mapToScene(mouseEvent->pos()); //TODO: do we need to check size? auto pos = mapToScene(mouseEvent->pos()); //TODO: do we need to check size?
int3 tile(pos.x() / 32, pos.y() / 32, sc->level); 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 if(tile == tilePrev) //do not redraw
return; return;
@ -161,13 +165,7 @@ void MapView::mouseMoveEvent(QMouseEvent *mouseEvent)
if(sh.x || sh.y) if(sh.x || sh.y)
{ {
if(sc->selectionObjectsView.newObject) if(!sc->selectionObjectsView.newObject && (mouseEvent->buttons() & Qt::LeftButton))
{
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.selectionMode == SelectionObjectsLayer::SELECTION) if(sc->selectionObjectsView.selectionMode == SelectionObjectsLayer::SELECTION)
{ {
@ -296,6 +294,11 @@ void MapView::mousePressEvent(QMouseEvent *event)
{ {
sc->selectionObjectsView.clear(); sc->selectionObjectsView.clear();
sc->selectionObjectsView.selectionMode = SelectionObjectsLayer::SELECTION; 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); sc->selectionObjectsView.shift = QPoint(0, 0);
@ -314,6 +317,9 @@ void MapView::mouseReleaseEvent(QMouseEvent *event)
auto * sc = static_cast<MapScene*>(scene()); auto * sc = static_cast<MapScene*>(scene());
if(!sc || !controller->map()) if(!sc || !controller->map())
return; return;
if(rubberBand)
rubberBand->hide();
switch(selectionTool) switch(selectionTool)
{ {
@ -324,19 +330,7 @@ void MapView::mouseReleaseEvent(QMouseEvent *event)
bool tab = false; bool tab = false;
if(sc->selectionObjectsView.selectionMode == SelectionObjectsLayer::MOVEMENT) if(sc->selectionObjectsView.selectionMode == SelectionObjectsLayer::MOVEMENT)
{ {
if(sc->selectionObjectsView.newObject) controller->commitObjectShift(sc->level);
{
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);
} }
else else
{ {
@ -355,11 +349,105 @@ 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);
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<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) bool MapView::viewportEvent(QEvent *event)
{ {
if(auto * sc = static_cast<MapScene*>(scene())) if(auto * sc = static_cast<MapScene*>(scene()))
{ {
//auto rect = sceneRect();
auto rect = mapToScene(viewport()->geometry()).boundingRect(); auto rect = mapToScene(viewport()->geometry()).boundingRect();
controller->miniScene(sc->level)->viewport.setViewport(rect.x() / 32, rect.y() / 32, rect.width() / 32, rect.height() / 32); controller->miniScene(sc->level)->viewport.setViewport(rect.x() / 32, rect.y() / 32, rect.width() / 32, rect.height() / 32);
} }

View File

@ -98,6 +98,10 @@ public slots:
void mouseMoveEvent(QMouseEvent * mouseEvent) override; void mouseMoveEvent(QMouseEvent * mouseEvent) override;
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(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); void cameraChanged(const QPointF & pos);
@ -110,6 +114,7 @@ protected:
private: private:
MapController * controller = nullptr; MapController * controller = nullptr;
QRubberBand * rubberBand = nullptr;
QPointF mouseStart; QPointF mouseStart;
int3 tileStart; int3 tileStart;
int3 tilePrev; int3 tilePrev;
@ -127,7 +132,7 @@ public:
public slots: public slots:
void mouseMoveEvent(QMouseEvent * mouseEvent) override; void mouseMoveEvent(QMouseEvent * mouseEvent) override;
void mousePressEvent(QMouseEvent* event) override; void mousePressEvent(QMouseEvent * event) override;
signals: signals:
void cameraPositionChanged(const QPointF & newPosition); void cameraPositionChanged(const QPointF & newPosition);

View File

@ -12,12 +12,12 @@
#include "objectbrowser.h" #include "objectbrowser.h"
#include "../lib/mapObjects/CObjectClassesHandler.h" #include "../lib/mapObjects/CObjectClassesHandler.h"
ObjectBrowser::ObjectBrowser(QObject *parent) ObjectBrowserProxyModel::ObjectBrowserProxyModel(QObject *parent)
: QSortFilterProxyModel{parent}, terrain(Terrain::ANY_TERRAIN) : 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); bool result = QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
@ -57,7 +57,7 @@ bool ObjectBrowser::filterAcceptsRow(int source_row, const QModelIndex & source_
return result; 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()) 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)); 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();
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();
}

View File

@ -13,10 +13,16 @@
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include "../lib/Terrain.h" #include "../lib/Terrain.h"
class ObjectBrowser : public QSortFilterProxyModel class ObjectBrowserProxyModel : public QSortFilterProxyModel
{ {
public: 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; TerrainId terrain;
QString filter; QString filter;
@ -25,3 +31,12 @@ protected:
bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override; bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override;
bool filterAcceptsRowText(int source_row, const QModelIndex &source_parent) const; 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;
};

View File

@ -390,7 +390,7 @@ void SelectionObjectsLayer::draw()
//show translation //show translation
if(selectionMode == SelectionMode::MOVEMENT && (shift.x() || shift.y())) 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; auto newPos = QPoint(obj->getPosition().x, obj->getPosition().y) + shift;
handler->drawObjectAt(painter, obj, newPos.x(), newPos.y()); handler->drawObjectAt(painter, obj, newPos.x(), newPos.y());
} }

View File

@ -144,7 +144,6 @@ public:
void deselectObject(CGObjectInstance *); void deselectObject(CGObjectInstance *);
bool isSelected(const CGObjectInstance *) const; bool isSelected(const CGObjectInstance *) const;
std::set<CGObjectInstance*> getSelection() const; std::set<CGObjectInstance*> getSelection() const;
void moveSelection(int x, int y);
void clear(); void clear();
QPoint shift; QPoint shift;