From c17b1f909d51308d493e507e179bda954733e29b Mon Sep 17 00:00:00 2001 From: nordsoft Date: Sat, 3 Sep 2022 01:04:28 +0400 Subject: [PATCH] Show objects preview --- lib/mapping/CMap.cpp | 21 +++++ lib/mapping/CMap.h | 3 + lib/mapping/CMapEditManager.cpp | 62 +++++++++++++++ lib/mapping/CMapEditManager.h | 33 ++++++++ mapeditor/mainwindow.cpp | 113 +++++++++++++++++++++----- mapeditor/mainwindow.h | 9 +++ mapeditor/mainwindow.ui | 135 +++++++++++++++++++++++++++----- mapeditor/maphandler.cpp | 2 +- mapeditor/mapview.cpp | 46 +++++++++-- mapeditor/mapview.h | 3 + 10 files changed, 384 insertions(+), 43 deletions(-) diff --git a/lib/mapping/CMap.cpp b/lib/mapping/CMap.cpp index 749a2e5b0..b3cff891a 100644 --- a/lib/mapping/CMap.cpp +++ b/lib/mapping/CMap.cpp @@ -622,6 +622,27 @@ void CMap::addNewObject(CGObjectInstance * obj) obj->afterAddToMap(this); } +void CMap::moveObject(CGObjectInstance * obj, const int3 & pos) +{ + removeBlockVisTiles(obj); + obj->pos = pos; + addBlockVisTiles(obj); +} + +void CMap::removeObject(CGObjectInstance * obj) +{ + removeBlockVisTiles(obj); + instanceNames.erase(obj->instanceName); + + //update indeces + auto iter = std::next(objects.begin(), obj->id.getNum()); + iter = objects.erase(iter); + for(int i = obj->id.getNum(); iter != objects.end(); ++i, ++iter) + { + (*iter)->id = ObjectInstanceID(i); + } +} + void CMap::initTerrain() { int level = twoLevel ? 2 : 1; diff --git a/lib/mapping/CMap.h b/lib/mapping/CMap.h index c13bb4e93..d15ed8b24 100644 --- a/lib/mapping/CMap.h +++ b/lib/mapping/CMap.h @@ -364,6 +364,9 @@ public: ///Use only this method when creating new map object instances void addNewObject(CGObjectInstance * obj); + void moveObject(CGObjectInstance * obj, const int3 & dst); + void removeObject(CGObjectInstance * obj); + /// Gets object of specified type on requested position const CGObjectInstance * getObjectiveObjectFrom(int3 pos, Obj::EObj type); diff --git a/lib/mapping/CMapEditManager.cpp b/lib/mapping/CMapEditManager.cpp index d45c4241e..d2ad1fd3b 100644 --- a/lib/mapping/CMapEditManager.cpp +++ b/lib/mapping/CMapEditManager.cpp @@ -268,6 +268,16 @@ void CMapEditManager::insertObject(CGObjectInstance * obj) execute(make_unique(map, obj)); } +void CMapEditManager::moveObject(CGObjectInstance * obj, const int3 & pos) +{ + execute(make_unique(map, obj, pos)); +} + +void CMapEditManager::removeObject(CGObjectInstance * obj) +{ + execute(make_unique(map, obj)); +} + void CMapEditManager::execute(std::unique_ptr && operation) { operation->execute(); @@ -1072,3 +1082,55 @@ std::string CInsertObjectOperation::getLabel() const { return "Insert Object"; } + +CMoveObjectOperation::CMoveObjectOperation(CMap * map, CGObjectInstance * obj, const int3 & position) + : CMapOperation(map), obj(obj), pos(position) +{ + +} + +void CMoveObjectOperation::execute() +{ + map->moveObject(obj, pos); +} + +void CMoveObjectOperation::undo() +{ + //TODO +} + +void CMoveObjectOperation::redo() +{ + execute(); +} + +std::string CMoveObjectOperation::getLabel() const +{ + return "Move Object"; +} + +CRemoveObjectOperation::CRemoveObjectOperation(CMap * map, CGObjectInstance * obj) + : CMapOperation(map), obj(obj) +{ + +} + +void CRemoveObjectOperation::execute() +{ + map->removeObject(obj); +} + +void CRemoveObjectOperation::undo() +{ + //TODO +} + +void CRemoveObjectOperation::redo() +{ + execute(); +} + +std::string CRemoveObjectOperation::getLabel() const +{ + return "Remove Object"; +} diff --git a/lib/mapping/CMapEditManager.h b/lib/mapping/CMapEditManager.h index cd296b0e0..a500c413e 100644 --- a/lib/mapping/CMapEditManager.h +++ b/lib/mapping/CMapEditManager.h @@ -178,6 +178,8 @@ public: void drawRiver(const std::string & riverType, CRandomGenerator * gen = nullptr); void insertObject(CGObjectInstance * obj); + void moveObject(CGObjectInstance * obj, const int3 & pos); + void removeObject(CGObjectInstance * obj); CTerrainSelection & getTerrainSelection(); CObjectSelection & getObjectSelection(); @@ -418,3 +420,34 @@ public: private: CGObjectInstance * obj; }; + +/// The CMoveObjectOperation class moves object to another position +class CMoveObjectOperation : public CMapOperation +{ +public: + CMoveObjectOperation(CMap * map, CGObjectInstance * obj, const int3 & position); + + void execute() override; + void undo() override; + void redo() override; + std::string getLabel() const override; + +private: + CGObjectInstance * obj; + int3 pos; +}; + +/// The CRemoveObjectOperation class removes object from the map +class CRemoveObjectOperation : public CMapOperation +{ +public: + CRemoveObjectOperation(CMap * map, CGObjectInstance * obj); + + void execute() override; + void undo() override; + void redo() override; + std::string getLabel() const override; + +private: + CGObjectInstance * obj; +}; diff --git a/mapeditor/mainwindow.cpp b/mapeditor/mainwindow.cpp index c5add76f7..0dc6beed8 100644 --- a/mapeditor/mainwindow.cpp +++ b/mapeditor/mainwindow.cpp @@ -37,7 +37,8 @@ void init() MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), - ui(new Ui::MainWindow) + ui(new Ui::MainWindow), + objPreview(128, 128) { ui->setupUi(this); @@ -99,6 +100,9 @@ MainWindow::MainWindow(QWidget *parent) : sceneMini = new QGraphicsScene(this); ui->minimapView->setScene(sceneMini); + scenePreview = new QGraphicsScene(this); + ui->objectPreview->setScene(scenePreview); + scenes[0]->addPixmap(QPixmap(QString::fromStdString(resPath.native()))); //loading objects @@ -147,6 +151,11 @@ MapHandler * MainWindow::getMapHandler() return mapHandler.get(); } +void MainWindow::resetMapHandler() +{ + mapHandler.reset(new MapHandler(map.get())); +} + void MainWindow::setMapRaw(std::unique_ptr cmap) { map = std::move(cmap); @@ -285,13 +294,42 @@ void MainWindow::terrainButtonClicked(Terrain terrain) void MainWindow::loadObjectsTree() { + //adding terrains for(auto & terrain : Terrain::Manager::terrains()) { QPushButton *b = new QPushButton(QString::fromStdString(terrain)); ui->terrainLayout->addWidget(b); connect(b, &QPushButton::clicked, this, [this, terrain]{ terrainButtonClicked(terrain); }); } + + //add spacer to keep terrain button on the top ui->terrainLayout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding)); + + //model + objectsModel.setHorizontalHeaderLabels(QStringList() << QStringLiteral("Type")); + + //adding towns + auto * itemGroup = new QStandardItem("TOWNS"); + for(auto secondaryID : VLC->objtypeh->knownSubObjects(Obj::TOWN)) + { + auto factory = VLC->objtypeh->getHandlerFor(Obj::TOWN, secondaryID); + auto * itemType = new QStandardItem(QString::fromStdString(factory->subTypeName)); + for(int templateId = 0; templateId < factory->getTemplates().size(); ++templateId) + { + auto templ = factory->getTemplates()[templateId]; + auto * item = new QStandardItem(QString::fromStdString(templ.stringID)); + QJsonObject data{{"id", QJsonValue(Obj::TOWN)}, + {"subid", QJsonValue(secondaryID)}, + {"animationEditor", QString::fromStdString(templ.editorAnimationFile)}, + {"animation", QString::fromStdString(templ.animationFile)}}; + item->setData(data); + itemType->appendRow(item); + } + itemGroup->appendRow(itemType); + } + objectsModel.appendRow(itemGroup); + + /* createHandler(bth, "Bonus type", pomtime); createHandler(generaltexth, "General text", pomtime); @@ -309,16 +347,14 @@ void MainWindow::loadObjectsTree() createHandler(battlefieldsHandler, "Battlefields", pomtime); createHandler(obstacleHandler, "Obstacles", pomtime);*/ - std::map> identifiers; - - for(auto primaryID : VLC->objtypeh->knownObjects()) + //for(auto primaryID : VLC->objtypeh->knownObjects()) { //QList objTypes; - for(auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID)) + //for(auto secondaryID : VLC->objtypeh->knownSubObjects(primaryID)) { //QList objSubTypes; - auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID); + //auto handler = VLC->objtypeh->getHandlerFor(primaryID, secondaryID); /*if(handler->isStaticObject()) { @@ -328,22 +364,14 @@ void MainWindow::loadObjectsTree() } }*/ - identifiers[handler->typeName].push_back(handler->subTypeName); + //identifiers[handler->typeName].push_back(handler->subTypeName); } } - objectsModel.setHorizontalHeaderLabels(QStringList() << QStringLiteral("Type")); - QList objTypes; - for(auto & el1 : identifiers) - { - auto * objTypei = new QStandardItem(QString::fromStdString(el1.first)); - for(auto & el2 : el1.second) - { - objTypei->appendRow(new QStandardItem(QString::fromStdString(el2))); - } - objectsModel.appendRow(objTypei); - } ui->treeView->setModel(&objectsModel); + ui->treeView->setSelectionBehavior(QAbstractItemView::SelectItems); + ui->treeView->setSelectionMode(QAbstractItemView::SingleSelection); + connect(ui->treeView->selectionModel(), SIGNAL(currentChanged(const QModelIndex &, const QModelIndex &)), this, SLOT(treeViewSelected(const QModelIndex &, const QModelIndex &))); } void MainWindow::on_actionLevel_triggered() @@ -372,6 +400,8 @@ void MainWindow::on_actionGrid_triggered(bool checked) scenes[0]->gridView.show(checked); scenes[1]->gridView.show(checked); } + + auto idx = ui->treeView->selectionModel()->currentIndex(); } @@ -412,3 +442,50 @@ void MainWindow::on_toolArea_clicked(bool checked) } } + +void MainWindow::on_toolErase_clicked() +{ + if(map && scenes[mapLevel]) + { + scenes[mapLevel]->selectionObjectsView.deleteSelection(); + resetMapHandler(); + scenes[mapLevel]->updateViews(); + } +} + + +void MainWindow::treeViewSelected(const QModelIndex & index, const QModelIndex & deselected) +{ + objPreview.fill(QColor(255, 255, 255)); + auto * item = objectsModel.itemFromIndex(index); + if(item) + { + auto data = item->data().toJsonObject(); + + if(!data.empty()) + { + auto animfile = data["animationEditor"]; + if(animfile != QJsonValue::Undefined) + { + if(animfile.toString().isEmpty()) + animfile = data["animation"]; + + QPainter painter(&objPreview); + Animation animation(animfile.toString().toStdString()); + animation.preload(); + auto picture = animation.getImage(0); + if(picture && picture->width() && picture->height()) + { + qreal xscale = qreal(128) / qreal(picture->width()), yscale = qreal(128) / qreal(picture->height()); + qreal scale = std::min(xscale, yscale); + painter.scale(scale, scale); + painter.drawImage(QPoint(0, 0), *picture); + } + } + } + } + + scenePreview->clear(); + scenePreview->addPixmap(objPreview); +} + diff --git a/mapeditor/mainwindow.h b/mapeditor/mainwindow.h index f389d269c..7b1f16ddf 100644 --- a/mapeditor/mainwindow.h +++ b/mapeditor/mainwindow.h @@ -30,6 +30,7 @@ public: CMap * getMap(); MapHandler * getMapHandler(); + void resetMapHandler(); void loadObjectsTree(); @@ -58,13 +59,21 @@ private slots: void terrainButtonClicked(Terrain terrain); + void on_toolErase_clicked(); + +public slots: + + void treeViewSelected(const QModelIndex &selected, const QModelIndex &deselected); + private: Ui::MainWindow *ui; std::unique_ptr mapHandler; std::array scenes; QGraphicsScene * sceneMini; + QGraphicsScene * scenePreview; QPixmap minimap; + QPixmap objPreview; std::unique_ptr map; QString filename; diff --git a/mapeditor/mainwindow.ui b/mapeditor/mainwindow.ui index e23b4d5e4..7ae0a53db 100644 --- a/mapeditor/mainwindow.ui +++ b/mapeditor/mainwindow.ui @@ -15,6 +15,18 @@ + + 2 + + + 2 + + + 2 + + + 2 + @@ -83,14 +95,14 @@ - 0 - 0 + 192 + 214 - 524287 - 524287 + 192 + 214 @@ -104,6 +116,18 @@ + + 0 + + + 0 + + + 0 + + + 0 + @@ -137,20 +161,20 @@ - + 0 0 - 292 + 192 183 - 524287 + 192 524287 @@ -165,6 +189,18 @@ + + 0 + + + 0 + + + 0 + + + 0 + @@ -200,7 +236,14 @@ 0 - + + + + 0 + 0 + + + @@ -210,6 +253,15 @@ 0 + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SelectItems + + + true + @@ -222,15 +274,15 @@ - + 0 0 - 118 - 372 + 128 + 496 @@ -251,7 +303,7 @@ - 118 + 16777215 16777215 @@ -271,11 +323,17 @@ - + 0 0 + + + 16777215 + 16777215 + + Brush @@ -313,6 +371,9 @@ + + false + 0 @@ -344,6 +405,9 @@ + + false + 0 @@ -406,6 +470,9 @@ + + false + 0 @@ -472,21 +539,27 @@ - + 0 0 + + + 16777215 + 16777215 + + - 1 + 0 0 0 - 118 - 395 + 128 + 271 @@ -521,8 +594,8 @@ 0 0 - 118 - 395 + 128 + 271 @@ -536,6 +609,14 @@ + + + 0 + 0 + 128 + 271 + + 0 @@ -548,6 +629,22 @@ + + + + + 128 + 128 + + + + + 128 + 128 + + + + diff --git a/mapeditor/maphandler.cpp b/mapeditor/maphandler.cpp index 0cb86a55b..f3bc2035b 100644 --- a/mapeditor/maphandler.cpp +++ b/mapeditor/maphandler.cpp @@ -427,7 +427,7 @@ void MapHandler::drawObjectAt(QPainter & painter, const CGObjectInstance * obj, auto objData = findObjectBitmap(obj, animationFrame); if (objData.objBitmap) { - painter.drawImage(QPoint((x - obj->getWidth()) * 32, (y - obj->getHeight()) * 32), *objData.objBitmap); + painter.drawImage(QPoint((x + 1) * 32 - objData.objBitmap->width(), (y + 1) * 32 - objData.objBitmap->height()), *objData.objBitmap); //drawObject(targetSurf, objData.objBitmap, &srcRect, objData.isMoving); if (objData.flagBitmap) diff --git a/mapeditor/mapview.cpp b/mapeditor/mapview.cpp index 1dfe6e22f..7a6aaea16 100644 --- a/mapeditor/mapview.cpp +++ b/mapeditor/mapview.cpp @@ -3,6 +3,8 @@ #include "mainwindow.h" #include +#include "../lib/mapping/CMapEditManager.h" + MapView::MapView(QWidget *parent): QGraphicsView(parent), selectionTool(MapView::SelectionTool::None) @@ -120,8 +122,17 @@ void MapView::mouseReleaseEvent(QMouseEvent *event) switch(selectionTool) { case MapView::SelectionTool::None: - sc->selectionObjectsView.shift = QPoint(0, 0); - sc->selectionObjectsView.draw(); + //switch position + if(sc->selectionObjectsView.applyShift()) + { + main->resetMapHandler(); + sc->updateViews(); + } + else + { + sc->selectionObjectsView.shift = QPoint(0, 0); + sc->selectionObjectsView.draw(); + } break; } } @@ -489,6 +500,7 @@ void SelectionObjectsView::update() return; selectedObjects.clear(); + shift = QPoint(); pixmap.reset(new QPixmap(map->width * 32, map->height * 32)); //pixmap->fill(QColor(0, 0, 0, 0)); @@ -548,7 +560,7 @@ CGObjectInstance * SelectionObjectsView::selectObjectAt(int x, int y) if(object.obj->visitableAt(x, y)) { - selectedObjects.insert(objects.back().obj); + selectedObjects.insert(object.obj); return object.obj; } } @@ -561,7 +573,7 @@ CGObjectInstance * SelectionObjectsView::selectObjectAt(int x, int y) if(object.obj->blockingAt(x, y)) { - selectedObjects.insert(objects.back().obj); + selectedObjects.insert(object.obj); return object.obj; } } @@ -574,7 +586,7 @@ CGObjectInstance * SelectionObjectsView::selectObjectAt(int x, int y) if(object.obj->coveringAt(x, y)) { - selectedObjects.insert(objects.back().obj); + selectedObjects.insert(object.obj); return object.obj; } } @@ -582,6 +594,30 @@ CGObjectInstance * SelectionObjectsView::selectObjectAt(int x, int y) return nullptr; } +bool SelectionObjectsView::applyShift() +{ + if(shift.x() || shift.y()) + { + for(auto * obj : selectedObjects) + { + int3 pos = obj->pos; + pos.x += shift.x(); pos.y += shift.y(); + main->getMap()->getEditManager()->moveObject(obj, pos); + } + return true; + } + return false; +} + +void SelectionObjectsView::deleteSelection() +{ + for(auto * obj : selectedObjects) + { + main->getMap()->getEditManager()->removeObject(obj); + } + clear(); +} + std::set SelectionObjectsView::selectObjects(int x1, int y1, int x2, int y2) { std::set result; diff --git a/mapeditor/mapview.h b/mapeditor/mapview.h index ae1423d25..ba206a833 100644 --- a/mapeditor/mapview.h +++ b/mapeditor/mapview.h @@ -139,6 +139,9 @@ public: void moveSelection(int x, int y); void clear(); + bool applyShift(); + void deleteSelection(); + QPoint shift; private: