浏览代码

Add object lock and zoom functinoality

nordsoft 2 年之前
父节点
当前提交
d85c5189ba

二进制
mapeditor/icons/zoom_base.png


二进制
mapeditor/icons/zoom_minus.png


二进制
mapeditor/icons/zoom_plus.png


二进制
mapeditor/icons/zoom_zero.png


+ 65 - 0
mapeditor/mainwindow.cpp

@@ -222,6 +222,8 @@ MainWindow::MainWindow(QWidget* parent) :
 	scenePreview = new QGraphicsScene(this);
 	ui->objectPreview->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);
+}
+

+ 11 - 0
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<int> catalog;
 

+ 70 - 6
mapeditor/mainwindow.ui

@@ -86,6 +86,8 @@
     <addaction name="actionCopy"/>
     <addaction name="actionPaste"/>
     <addaction name="actionErase"/>
+    <addaction name="actionLock"/>
+    <addaction name="actionUnlock"/>
    </widget>
    <widget class="QMenu" name="menuView">
     <property name="title">
@@ -94,6 +96,10 @@
     <addaction name="actionLevel"/>
     <addaction name="actionGrid"/>
     <addaction name="actionPass"/>
+    <addaction name="separator"/>
+    <addaction name="actionZoom_in"/>
+    <addaction name="actionZoom_out"/>
+    <addaction name="actionZoom_reset"/>
    </widget>
    <widget class="QMenu" name="menuPlayer">
     <property name="title">
@@ -143,6 +149,13 @@
    <addaction name="separator"/>
    <addaction name="actionFill"/>
    <addaction name="actionTranslations"/>
+   <addaction name="separator"/>
+   <addaction name="actionLock"/>
+   <addaction name="actionUnlock"/>
+   <addaction name="separator"/>
+   <addaction name="actionZoom_in"/>
+   <addaction name="actionZoom_out"/>
+   <addaction name="actionZoom_reset"/>
   </widget>
   <widget class="QDockWidget" name="dockWidget_2">
    <property name="sizePolicy">
@@ -804,8 +817,8 @@
          <rect>
           <x>0</x>
           <y>0</y>
-          <width>128</width>
-          <height>192</height>
+          <width>256</width>
+          <height>90</height>
          </rect>
         </property>
         <property name="sizePolicy">
@@ -847,8 +860,8 @@
          <rect>
           <x>0</x>
           <y>0</y>
-          <width>128</width>
-          <height>192</height>
+          <width>256</width>
+          <height>90</height>
          </rect>
         </property>
         <property name="sizePolicy">
@@ -883,8 +896,8 @@
          <rect>
           <x>0</x>
           <y>0</y>
-          <width>128</width>
-          <height>192</height>
+          <width>256</width>
+          <height>90</height>
          </rect>
         </property>
         <property name="sizePolicy">
@@ -1332,6 +1345,57 @@
     <string>h3m converter</string>
    </property>
   </action>
+  <action name="actionLock">
+   <property name="icon">
+    <iconset>
+     <normaloff>icons:lock-closed.png</normaloff>icons:lock-closed.png</iconset>
+   </property>
+   <property name="text">
+    <string>Lock</string>
+   </property>
+   <property name="toolTip">
+    <string>Lock objects on map to avoid unnecessary changes</string>
+   </property>
+  </action>
+  <action name="actionUnlock">
+   <property name="icon">
+    <iconset>
+     <normaloff>icons:lock-open.png</normaloff>icons:lock-open.png</iconset>
+   </property>
+   <property name="text">
+    <string>Unlock</string>
+   </property>
+   <property name="toolTip">
+    <string>Unlock all objects on the map</string>
+   </property>
+  </action>
+  <action name="actionZoom_in">
+   <property name="icon">
+    <iconset>
+     <normaloff>icons:zoom_plus.png</normaloff>icons:zoom_plus.png</iconset>
+   </property>
+   <property name="text">
+    <string>Zoom in</string>
+   </property>
+  </action>
+  <action name="actionZoom_out">
+   <property name="icon">
+    <iconset>
+     <normaloff>icons:zoom_minus.png</normaloff>icons:zoom_minus.png</iconset>
+   </property>
+   <property name="text">
+    <string>Zoom out</string>
+   </property>
+  </action>
+  <action name="actionZoom_reset">
+   <property name="icon">
+    <iconset>
+     <normaloff>icons:zoom_zero.png</normaloff>icons:zoom_zero.png</iconset>
+   </property>
+   <property name="text">
+    <string>Zoom reset</string>
+   </property>
+  </action>
  </widget>
  <customwidgets>
   <customwidget>

+ 13 - 3
mapeditor/maphandler.cpp

@@ -322,8 +322,11 @@ std::vector<TileObject> & 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<const CGObjectInstance *> & 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)

+ 3 - 1
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<int3> 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<const CGObjectInstance *> & locked);
 	void drawObject(QPainter & painter, const TileObject & object);
 	void drawObjectAt(QPainter & painter, const CGObjectInstance * object, int x, int y);
 	std::vector<TileObject> & getObjects(int x, int y, int z);

+ 3 - 10
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)

+ 34 - 8
mapeditor/scenelayer.cpp

@@ -377,8 +377,7 @@ void ObjectsLayer::draw(bool onlyDirty)
 		return;
 	
 	QPainter painter(pixmap.get());
-	std::set<const CGObjectInstance *> 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)
 {
 	

+ 8 - 0
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<const CGObjectInstance *> objDirty;
+	std::set<const CGObjectInstance *> lockedObjects;
 	std::set<int3> dirty;
 };
 
@@ -180,6 +184,9 @@ public:
 	bool isSelected(const CGObjectInstance *) const;
 	std::set<CGObjectInstance*> 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<CGObjectInstance *> selectedObjects;
+	std::set<const CGObjectInstance *> lockedObjects;
 
 	void onSelection();
 };