From d85c5189ba1c018abf950fae2698f9c4d58d60b2 Mon Sep 17 00:00:00 2001 From: nordsoft Date: Fri, 13 Oct 2023 05:21:09 +0200 Subject: [PATCH] Add object lock and zoom functinoality --- mapeditor/icons/zoom_base.png | Bin 0 -> 1490 bytes mapeditor/icons/zoom_minus.png | Bin 0 -> 1509 bytes mapeditor/icons/zoom_plus.png | Bin 0 -> 1528 bytes mapeditor/icons/zoom_zero.png | Bin 0 -> 1520 bytes mapeditor/mainwindow.cpp | 65 ++++++++++++++++++++++++++++ mapeditor/mainwindow.h | 11 +++++ mapeditor/mainwindow.ui | 76 ++++++++++++++++++++++++++++++--- mapeditor/maphandler.cpp | 16 +++++-- mapeditor/maphandler.h | 4 +- mapeditor/mapview.cpp | 13 ++---- mapeditor/scenelayer.cpp | 42 ++++++++++++++---- mapeditor/scenelayer.h | 8 ++++ 12 files changed, 207 insertions(+), 28 deletions(-) create mode 100644 mapeditor/icons/zoom_base.png create mode 100644 mapeditor/icons/zoom_minus.png create mode 100644 mapeditor/icons/zoom_plus.png create mode 100644 mapeditor/icons/zoom_zero.png diff --git a/mapeditor/icons/zoom_base.png b/mapeditor/icons/zoom_base.png new file mode 100644 index 0000000000000000000000000000000000000000..62a5dae81eb77de786020186df676dda4b842908 GIT binary patch literal 1490 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 LNkvXXu0mjfxA49n literal 0 HcmV?d00001 diff --git a/mapeditor/icons/zoom_plus.png b/mapeditor/icons/zoom_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..0d07f5456646c46c241ba20ea1066c8f0b49e657 GIT binary patch literal 1528 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 zB+>_>#+*D&01BXHU9Zykol*IJfRbeuAQobjectPreview->setScene(scenePreview); + initialScale = ui->mapView->viewport()->geometry(); + //loading objects loadObjectsTree(); @@ -296,6 +298,7 @@ void MainWindow::initializeMap(bool isNew) ui->mapView->setScene(controller.scene(mapLevel)); ui->minimapView->setScene(controller.miniScene(mapLevel)); ui->minimapView->dimensions(); + initialScale = ui->mapView->mapToScene(ui->mapView->viewport()->geometry()).boundingRect(); //enable settings ui->actionMapSettings->setEnabled(true); @@ -1281,3 +1284,65 @@ void MainWindow::on_actionh3m_converter_triggered() } } + +void MainWindow::on_actionLock_triggered() +{ + if(controller.map()) + { + if(controller.scene(mapLevel)->selectionObjectsView.getSelection().empty()) + { + for(auto obj : controller.map()->objects) + { + controller.scene(mapLevel)->selectionObjectsView.setLockObject(obj, true); + controller.scene(mapLevel)->objectsView.setLockObject(obj, true); + } + } + else + { + for(auto * obj : controller.scene(mapLevel)->selectionObjectsView.getSelection()) + { + controller.scene(mapLevel)->selectionObjectsView.setLockObject(obj, true); + controller.scene(mapLevel)->objectsView.setLockObject(obj, true); + } + controller.scene(mapLevel)->selectionObjectsView.clear(); + } + controller.scene(mapLevel)->objectsView.update(); + controller.scene(mapLevel)->selectionObjectsView.update(); + } +} + + +void MainWindow::on_actionUnlock_triggered() +{ + if(controller.map()) + { + controller.scene(mapLevel)->selectionObjectsView.unlockAll(); + controller.scene(mapLevel)->objectsView.unlockAll(); + } + controller.scene(mapLevel)->objectsView.update(); +} + + +void MainWindow::on_actionZoom_in_triggered() +{ + auto rect = ui->mapView->mapToScene(ui->mapView->viewport()->geometry()).boundingRect(); + rect -= QMargins{32 + 1, 32 + 1, 32 + 2, 32 + 2}; //compensate bounding box + ui->mapView->fitInView(rect, Qt::KeepAspectRatioByExpanding); +} + + +void MainWindow::on_actionZoom_out_triggered() +{ + auto rect = ui->mapView->mapToScene(ui->mapView->viewport()->geometry()).boundingRect(); + rect += QMargins{32 - 1, 32 - 1, 32 - 2, 32 - 2}; //compensate bounding box + ui->mapView->fitInView(rect, Qt::KeepAspectRatioByExpanding); +} + + +void MainWindow::on_actionZoom_reset_triggered() +{ + auto center = ui->mapView->mapToScene(ui->mapView->viewport()->geometry().center()); + ui->mapView->fitInView(initialScale, Qt::KeepAspectRatioByExpanding); + ui->mapView->centerOn(center); +} + diff --git a/mapeditor/mainwindow.h b/mapeditor/mainwindow.h index 77c2c14f3..3d127b857 100644 --- a/mapeditor/mainwindow.h +++ b/mapeditor/mainwindow.h @@ -124,6 +124,16 @@ private slots: void on_actionh3m_converter_triggered(); + void on_actionLock_triggered(); + + void on_actionUnlock_triggered(); + + void on_actionZoom_in_triggered(); + + void on_actionZoom_out_triggered(); + + void on_actionZoom_reset_triggered(); + public slots: void treeViewSelected(const QModelIndex &selected, const QModelIndex &deselected); @@ -166,6 +176,7 @@ private: QStandardItemModel objectsModel; int mapLevel = 0; + QRectF initialScale; std::set catalog; diff --git a/mapeditor/mainwindow.ui b/mapeditor/mainwindow.ui index 0cd4f9318..b1942db80 100644 --- a/mapeditor/mainwindow.ui +++ b/mapeditor/mainwindow.ui @@ -86,6 +86,8 @@ + + @@ -94,6 +96,10 @@ + + + + @@ -143,6 +149,13 @@ + + + + + + + @@ -804,8 +817,8 @@ 0 0 - 128 - 192 + 256 + 90 @@ -847,8 +860,8 @@ 0 0 - 128 - 192 + 256 + 90 @@ -883,8 +896,8 @@ 0 0 - 128 - 192 + 256 + 90 @@ -1332,6 +1345,57 @@ h3m converter + + + + icons:lock-closed.pngicons:lock-closed.png + + + Lock + + + Lock objects on map to avoid unnecessary changes + + + + + + icons:lock-open.pngicons:lock-open.png + + + Unlock + + + Unlock all objects on the map + + + + + + icons:zoom_plus.pngicons:zoom_plus.png + + + Zoom in + + + + + + icons:zoom_minus.pngicons:zoom_minus.png + + + Zoom out + + + + + + icons:zoom_zero.pngicons:zoom_zero.png + + + Zoom reset + + diff --git a/mapeditor/maphandler.cpp b/mapeditor/maphandler.cpp index 891d83901..922e38345 100644 --- a/mapeditor/maphandler.cpp +++ b/mapeditor/maphandler.cpp @@ -322,8 +322,11 @@ std::vector & MapHandler::getObjects(int x, int y, int z) return ttiles[index(x, y, z)]; } -void MapHandler::drawObjects(QPainter & painter, int x, int y, int z) +void MapHandler::drawObjects(QPainter & painter, int x, int y, int z, const std::set & locked) { + painter.setRenderHint(QPainter::Antialiasing, false); + painter.setRenderHint(QPainter::SmoothPixmapTransform, false); + for(auto & object : getObjects(x, y, z)) { const CGObjectInstance * obj = object.obj; @@ -343,8 +346,15 @@ void MapHandler::drawObjects(QPainter & painter, int x, int y, int z) { auto pos = obj->getPosition(); - painter.drawImage(QPoint(x * tileSize, y * tileSize), *objData.objBitmap, object.rect); - + painter.drawImage(QPoint(x * tileSize, y * tileSize), *objData.objBitmap, object.rect, Qt::AutoColor | Qt::NoOpaqueDetection); + + if(locked.count(obj)) + { + painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); + painter.fillRect(x * tileSize, y * tileSize, object.rect.width(), object.rect.height(), Qt::Dense4Pattern); + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + } + if(objData.flagBitmap) { if(x == pos.x && y == pos.y) diff --git a/mapeditor/maphandler.h b/mapeditor/maphandler.h index 2372f29f1..27b0518e8 100644 --- a/mapeditor/maphandler.h +++ b/mapeditor/maphandler.h @@ -88,6 +88,8 @@ private: void initObjectRects(); void initTerrainGraphics(); QRgb getTileColor(int x, int y, int z); + + QPolygon lockBitMask; public: MapHandler(); @@ -110,7 +112,7 @@ public: std::vector getTilesUnderObject(CGObjectInstance *) const; /// draws all objects on current tile (higher-level logic, unlike other draw*** methods) - void drawObjects(QPainter & painter, int x, int y, int z); + void drawObjects(QPainter & painter, int x, int y, int z, const std::set & locked); void drawObject(QPainter & painter, const TileObject & object); void drawObjectAt(QPainter & painter, const CGObjectInstance * object, int x, int y); std::vector & getObjects(int x, int y, int z); diff --git a/mapeditor/mapview.cpp b/mapeditor/mapview.cpp index 3f0fa299b..5013d206c 100644 --- a/mapeditor/mapview.cpp +++ b/mapeditor/mapview.cpp @@ -44,15 +44,9 @@ void MinimapView::mouseMoveEvent(QMouseEvent *mouseEvent) if(!sc) return; - int w = sc->viewport.viewportWidth(); - int h = sc->viewport.viewportHeight(); auto pos = mapToScene(mouseEvent->pos()); - pos.setX(pos.x() - w / 2); - pos.setY(pos.y() - h / 2); - - QPointF point = pos * 32; - - emit cameraPositionChanged(point); + pos *= 32; + emit cameraPositionChanged(pos); } void MinimapView::mousePressEvent(QMouseEvent* event) @@ -68,8 +62,7 @@ MapView::MapView(QWidget * parent): void MapView::cameraChanged(const QPointF & pos) { - horizontalScrollBar()->setValue(pos.x()); - verticalScrollBar()->setValue(pos.y()); + centerOn(pos); } void MapView::setController(MapController * ctrl) diff --git a/mapeditor/scenelayer.cpp b/mapeditor/scenelayer.cpp index 6e05bfe09..6d49c3f25 100644 --- a/mapeditor/scenelayer.cpp +++ b/mapeditor/scenelayer.cpp @@ -377,8 +377,7 @@ void ObjectsLayer::draw(bool onlyDirty) return; QPainter painter(pixmap.get()); - std::set drawen; - + if(onlyDirty) { //objects could be modified @@ -392,7 +391,7 @@ void ObjectsLayer::draw(bool onlyDirty) painter.setCompositionMode(QPainter::CompositionMode_SourceOver); for(auto & p : dirty) - handler->drawObjects(painter, p.x, p.y, p.z); + handler->drawObjects(painter, p.x, p.y, p.z, lockedObjects); } else { @@ -401,7 +400,7 @@ void ObjectsLayer::draw(bool onlyDirty) { for(int i = 0; i < map->width; ++i) { - handler->drawObjects(painter, i, j, scene->level); + handler->drawObjects(painter, i, j, scene->level, lockedObjects); } } } @@ -430,6 +429,19 @@ void ObjectsLayer::setDirty(const CGObjectInstance * object) } } +void ObjectsLayer::setLockObject(const CGObjectInstance * object, bool lock) +{ + if(lock) + lockedObjects.insert(object); + else + lockedObjects.erase(object); +} + +void ObjectsLayer::unlockAll() +{ + lockedObjects.clear(); +} + SelectionObjectsLayer::SelectionObjectsLayer(MapSceneBase * s): AbstractLayer(s), newObject(nullptr) { } @@ -501,7 +513,7 @@ CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y, const CGO //visitable is most important for(auto & object : objects) { - if(!object.obj || object.obj == ignore) + if(!object.obj || object.obj == ignore || lockedObjects.count(object.obj)) continue; if(object.obj->visitableAt(x, y)) @@ -513,7 +525,7 @@ CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y, const CGO //if not visitable tile - try to get blocked for(auto & object : objects) { - if(!object.obj || object.obj == ignore) + if(!object.obj || object.obj == ignore || lockedObjects.count(object.obj)) continue; if(object.obj->blockingAt(x, y)) @@ -525,7 +537,7 @@ CGObjectInstance * SelectionObjectsLayer::selectObjectAt(int x, int y, const CGO //finally, we can take any object for(auto & object : objects) { - if(!object.obj || object.obj == ignore) + if(!object.obj || object.obj == ignore || lockedObjects.count(object.obj)) continue; if(object.obj->coveringAt(x, y)) @@ -555,7 +567,8 @@ void SelectionObjectsLayer::selectObjects(int x1, int y1, int x2, int y2) if(map->isInTheMap(int3(i, j, scene->level))) { for(auto & o : handler->getObjects(i, j, scene->level)) - selectObject(o.obj, false); //do not inform about each object added + if(!lockedObjects.count(o.obj)) + selectObject(o.obj, false); //do not inform about each object added } } } @@ -599,6 +612,19 @@ void SelectionObjectsLayer::onSelection() emit selectionMade(!selectedObjects.empty()); } +void SelectionObjectsLayer::setLockObject(const CGObjectInstance * object, bool lock) +{ + if(lock) + lockedObjects.insert(object); + else + lockedObjects.erase(object); +} + +void SelectionObjectsLayer::unlockAll() +{ + lockedObjects.clear(); +} + MinimapLayer::MinimapLayer(MapSceneBase * s): AbstractLayer(s) { diff --git a/mapeditor/scenelayer.h b/mapeditor/scenelayer.h index 2b0a127fd..92add8ede 100644 --- a/mapeditor/scenelayer.h +++ b/mapeditor/scenelayer.h @@ -120,9 +120,13 @@ public: void setDirty(int x, int y); void setDirty(const CGObjectInstance * object); + + void setLockObject(const CGObjectInstance * object, bool lock); + void unlockAll(); private: std::set objDirty; + std::set lockedObjects; std::set dirty; }; @@ -180,6 +184,9 @@ public: bool isSelected(const CGObjectInstance *) const; std::set getSelection() const; void clear(); + + void setLockObject(const CGObjectInstance * object, bool lock); + void unlockAll(); QPoint shift; CGObjectInstance * newObject; @@ -191,6 +198,7 @@ signals: private: std::set selectedObjects; + std::set lockedObjects; void onSelection(); };