def svg(self, filename, rect=None, resolution=72.0, paperColor=None): """Create a SVG file for the selected rect or the whole page. The filename may be a string or a QIODevice object. The rectangle is relative to our top-left position. Normally vector graphics are rendered, but in cases where that is not possible, the resolution will be used to determine the DPI for the generated rendering. """ # map to the original page source = self.pageRect() if rect is None else self.mapFromPage().rect( rect) # scale to target size w = source.width() * self.scaleX h = source.height() * self.scaleY if self.computedRotation & 1: w, h = h, w targetSize = QSizeF(w, h) * resolution / self.dpi svg = QSvgGenerator() if isinstance(filename, str): svg.setFileName(filename) else: svg.setOutputDevice(filename) svg.setResolution(int(resolution)) svg.setSize(targetSize.toSize()) svg.setViewBox(QRectF(0, 0, targetSize.width(), targetSize.height())) return self.output(svg, source, paperColor)
def max_size(self): size = QSizeF(0, 0) for cluster in self.__clusters: for obj in cluster.objects: if obj.x() > size.width(): size.setWidth(obj.x()) if obj.y() > size.height(): size.setHeight(obj.y()) return size
def boundingRect(self, arg): tp = type(arg) if tp == QRect: rect = arg tileWidth = self.map().tileWidth() tileHeight = self.map().tileHeight() return QRect(rect.x() * tileWidth, rect.y() * tileHeight, rect.width() * tileWidth, rect.height() * tileHeight) elif tp == MapObject: object = arg bounds = object.bounds() boundingRect = QRectF() if (not object.cell().isEmpty()): bottomLeft = bounds.topLeft() tile = object.cell().tile imgSize = tile.image().size() tileOffset = tile.offset() objectSize = object.size() scale = QSizeF(objectSize.width() / imgSize.width(), objectSize.height() / imgSize.height()) boundingRect = QRectF( bottomLeft.x() + (tileOffset.x() * scale.width()), bottomLeft.y() + (tileOffset.y() * scale.height() - objectSize.height()), objectSize.width(), objectSize.height()).adjusted(-1, -1, 1, 1) else: extraSpace = max(self.objectLineWidth(), 1.0) x = object.shape() if x == MapObject.Ellipse or x == MapObject.Rectangle: if (bounds.isNull()): boundingRect = bounds.adjusted(-10 - extraSpace, -10 - extraSpace, 10 + extraSpace + 1, 10 + extraSpace + 1) else: boundingRect = bounds.adjusted(-extraSpace, -extraSpace, extraSpace + 1, extraSpace + 1) elif x == MapObject.Polygon or x == MapObject.Polyline: # Make some more room for the starting dot extraSpace += self.objectLineWidth() * 4 pos = object.position() polygon = object.polygon().translated(pos) screenPolygon = self.pixelToScreenCoords_(polygon) boundingRect = screenPolygon.boundingRect().adjusted( -extraSpace, -extraSpace, extraSpace + 1, extraSpace + 1) return boundingRect
def boundingRect(self, arg): tp = type(arg) if tp==QRect: rect = arg tileWidth = self.map().tileWidth() tileHeight = self.map().tileHeight() return QRect(rect.x() * tileWidth, rect.y() * tileHeight, rect.width() * tileWidth, rect.height() * tileHeight) elif tp==MapObject: object = arg bounds = object.bounds() boundingRect = QRectF() if (not object.cell().isEmpty()): bottomLeft = bounds.topLeft() tile = object.cell().tile imgSize = tile.image().size() tileOffset = tile.offset() objectSize = object.size() scale = QSizeF(objectSize.width() / imgSize.width(), objectSize.height() / imgSize.height()) boundingRect = QRectF(bottomLeft.x() + (tileOffset.x() * scale.width()), bottomLeft.y() + (tileOffset.y() * scale.height() - objectSize.height()), objectSize.width(), objectSize.height()).adjusted(-1, -1, 1, 1) else: extraSpace = max(self.objectLineWidth(), 1.0) x = object.shape() if x==MapObject.Ellipse or x==MapObject.Rectangle: if (bounds.isNull()): boundingRect = bounds.adjusted(-10 - extraSpace, -10 - extraSpace, 10 + extraSpace + 1, 10 + extraSpace + 1) else: boundingRect = bounds.adjusted(-extraSpace, -extraSpace, extraSpace + 1, extraSpace + 1) elif x==MapObject.Polygon or x==MapObject.Polyline: # Make some more room for the starting dot extraSpace += self.objectLineWidth() * 4 pos = object.position() polygon = object.polygon().translated(pos) screenPolygon = self.pixelToScreenCoords_(polygon) boundingRect = screenPolygon.boundingRect().adjusted(-extraSpace, -extraSpace, extraSpace + 1, extraSpace + 1) return boundingRect
def boundingRect(self, arg): tp = type(arg) if tp == QRect: rect = arg tileWidth = self.map().tileWidth() tileHeight = self.map().tileHeight() originX = int(self.map().height() * tileWidth / 2) pos = QPoint( (rect.x() - (rect.y() + rect.height())) * tileWidth / 2 + originX, (rect.x() + rect.y()) * tileHeight / 2) side = rect.height() + rect.width() size = QSize(side * tileWidth / 2, side * tileHeight / 2) return QRect(pos, size) elif tp == MapObject: object = arg if (not object.cell().isEmpty()): bottomCenter = self.pixelToScreenCoords_(object.position()) tile = object.cell().tile imgSize = tile.image().size() tileOffset = tile.offset() objectSize = object.size() scale = QSizeF(objectSize.width() / imgSize.width(), objectSize.height() / imgSize.height()) return QRectF( bottomCenter.x() + (tileOffset.x() * scale.width()) - objectSize.width() / 2, bottomCenter.y() + (tileOffset.y() * scale.height()) - objectSize.height(), objectSize.width(), objectSize.height()).adjusted(-1, -1, 1, 1) elif (not object.polygon().isEmpty()): extraSpace = max(self.objectLineWidth(), 1.0) # Make some more room for the starting dot extraSpace += self.objectLineWidth() * 4 pos = object.position() polygon = object.polygon().translated(pos) screenPolygon = self.pixelToScreenCoords_(polygon) return screenPolygon.boundingRect().adjusted( -extraSpace, -extraSpace - 1, extraSpace, extraSpace) else: # Take the bounding rect of the projected object, and then add a few # pixels on all sides to correct for the line width. base = self.pixelRectToScreenPolygon( object.bounds()).boundingRect() extraSpace = max(self.objectLineWidth() / 2, 1.0) return base.adjusted(-extraSpace, -extraSpace - 1, extraSpace, extraSpace)
def paint_screenshot_image( painter: QPainter, scene: QGraphicsScene, image_size: QSize, scene_rect: QRectF = QRectF(), transparent_background=False, ) -> QImage: # with elapsed_timer() as elapsed: painter.fillRect(QRect(QPoint(0, 0), image_size), painter.background().color()) scene_items = scene.items(scene_rect, Qt.IntersectsItemBoundingRect) only_leaf_items = [ item for item in scene_items if len(item.childItems()) == 0 ] item_parents = {} item_groups = {} for item in only_leaf_items: if item.group(): item_groups[item] = item.group() item.group().setVisible(False) elif item.parentItem(): item_parents[item] = item.parentItem() item.parentItem().setVisible(False) group_for_screenshot = QGraphicsItemGroup() for item in only_leaf_items: group_for_screenshot.addToGroup(item) scene.addItem(group_for_screenshot) group_for_screenshot.setVisible(True) # scene_items2 = scene.items(scene_rect, Qt.IntersectsItemBoundingRect) # print(scene_items2) # print("before render==========================================") rendered_size = scene_rect.size().scaled(QSizeF(image_size), Qt.KeepAspectRatio) dsize = QSizeF(image_size) - rendered_size top_left = QPointF(dsize.width() / 2, dsize.height() / 2) scene.render(painter, QRectF(top_left, rendered_size), scene_rect, Qt.KeepAspectRatio) scene.destroyItemGroup(group_for_screenshot) for item in item_parents: parent = item_parents[item] item.setParentItem(parent) parent.setVisible(True) for item in item_groups: group = item_groups[item] group.addToGroup(item) group.setVisible(True)
def boundingRect(self, arg): tp = type(arg) if tp == QRect: rect = arg tileWidth = self.map().tileWidth() tileHeight = self.map().tileHeight() originX = int(self.map().height() * tileWidth / 2) pos = QPoint((rect.x() - (rect.y() + rect.height())) * tileWidth / 2 + originX, (rect.x() + rect.y()) * tileHeight / 2) side = rect.height() + rect.width() size = QSize(side * tileWidth / 2, side * tileHeight / 2) return QRect(pos, size) elif tp == MapObject: object = arg if (not object.cell().isEmpty()): bottomCenter = self.pixelToScreenCoords_(object.position()) tile = object.cell().tile imgSize = tile.image().size() tileOffset = tile.offset() objectSize = object.size() scale = QSizeF(objectSize.width() / imgSize.width(), objectSize.height() / imgSize.height()) return QRectF(bottomCenter.x() + (tileOffset.x() * scale.width()) - objectSize.width() / 2, bottomCenter.y() + (tileOffset.y() * scale.height()) - objectSize.height(), objectSize.width(), objectSize.height()).adjusted(-1, -1, 1, 1) elif (not object.polygon().isEmpty()): extraSpace = max(self.objectLineWidth(), 1.0) # Make some more room for the starting dot extraSpace += self.objectLineWidth() * 4 pos = object.position() polygon = object.polygon().translated(pos) screenPolygon = self.pixelToScreenCoords_(polygon) return screenPolygon.boundingRect().adjusted(-extraSpace, -extraSpace - 1, extraSpace, extraSpace) else: # Take the bounding rect of the projected object, and then add a few # pixels on all sides to correct for the line width. base = self.pixelRectToScreenPolygon(object.bounds()).boundingRect() extraSpace = max(self.objectLineWidth() / 2, 1.0) return base.adjusted(-extraSpace, -extraSpace - 1, extraSpace, extraSpace)
class PandaWidget(QWidget): def __init__(self, panda3DWorld, label_info, parent=None, FPS=60, debug=False): QWidget.__init__(self, parent) # set fixed geometry self.panda3DWorld = panda3DWorld self.panda3DWorld.set_parent(self) self.label_info = label_info self.setFocusPolicy(Qt.StrongFocus) self.paintSurface = QPainter() self.rotate = QTransform() self.rotate.rotate(180) self.out_image = QImage() size = self.panda3DWorld.cam.node().get_lens().get_film_size() self.initial_film_size = QSizeF(size.x, size.y) self.initial_size = self.size() self.synchronizer = QPanda3DSynchronizer(self, FPS) self.synchronizer.start() self.debug = debug self.update_sgam() def get_scene_graph_analyzer_meter(self): return self.panda3DWorld.get_scene_graph_analyzer_meter() def update_sgam(self): text = sceneGraphAnalyzerMeterParser( self.get_scene_graph_analyzer_meter()).toText() self.label_info.setText(text) def mousePressEvent(self, event): self.panda3DWorld.camera_controller.mouse_press( event.button(), event.x(), event.y()) def mouseReleaseEvent(self, event): self.panda3DWorld.camera_controller.mouse_release( event.button(), event.x(), event.y()) def mouseMoveEvent(self, event): self.panda3DWorld.camera_controller.mouse_move(event.button(), event.x(), event.y()) def wheelEvent(self, evt): delta = -evt.angleDelta().y() self.panda3DWorld.camera_controller.zoom_event(delta) def keyPressEvent(self, evt): key = evt.key() try: k = "{}{}".format(get_panda_key_modifiers_prefix(evt), QPanda3D_Key_translation[key]) if self.debug: print(k) messenger.send(k) except: print( "Unimplemented key. Please send an issue on github to fix this problem" ) def keyReleaseEvent(self, evt): key = evt.key() try: k = "{}{}-up".format(get_panda_key_modifiers_prefix(evt), QPanda3D_Key_translation[key]) if self.debug: print(k) messenger.send(k) except: print( "Unimplemented key. Please send an issue on github to fix this problem" ) def resizeEvent(self, evt): lens = self.panda3DWorld.cam.node().get_lens() lens.set_film_size( self.initial_film_size.width() * evt.size().width() / self.initial_size.width(), self.initial_film_size.height() * evt.size().height() / self.initial_size.height()) self.panda3DWorld.buff.setSize(evt.size().width(), evt.size().height()) def minimumSizeHint(self): return QSize(400, 300) # Use the paint event to pull the contents of the panda texture to the widget def paintEvent(self, event): if self.panda3DWorld.screenTexture.mightHaveRamImage(): self.panda3DWorld.screenTexture.setFormat(Texture.FRgba32) data = self.panda3DWorld.screenTexture.getRamImage().getData() img = QImage(data, self.panda3DWorld.screenTexture.getXSize(), self.panda3DWorld.screenTexture.getYSize(), QImage.Format_ARGB32).mirrored() self.paintSurface.begin(self) self.paintSurface.drawImage(0, 0, img) self.paintSurface.end() def rotateX(self, value): self.panda3DWorld.camera_controller.rotateTheta(value) def rotateY(self, value): self.panda3DWorld.camera_controller.rotatePhi(value)
def render(self, cell, pos, cellSize, origin): if (self.mTile != cell.tile): self.flush() image = cell.tile.currentFrameImage() size = image.size() if cellSize == QSizeF(0, 0): objectSize = size else: objectSize = cellSize scale = QSizeF(objectSize.width() / size.width(), objectSize.height() / size.height()) offset = cell.tile.offset() sizeHalf = QPointF(objectSize.width() / 2, objectSize.height() / 2) fragment = QPainter.PixmapFragment() fragment.x = pos.x() + (offset.x() * scale.width()) + sizeHalf.x() fragment.y = pos.y() + ( offset.y() * scale.height()) + sizeHalf.y() - objectSize.height() fragment.sourceLeft = 0 fragment.sourceTop = 0 fragment.width = size.width() fragment.height = size.height() if cell.flippedHorizontally: fragment.scaleX = -1 else: fragment.scaleX = 1 if cell.flippedVertically: fragment.scaleY = -1 else: fragment.scaleY = 1 fragment.rotation = 0 fragment.opacity = 1 flippedHorizontally = cell.flippedHorizontally flippedVertically = cell.flippedVertically if (origin == CellRenderer.BottomCenter): fragment.x -= sizeHalf.x() if (cell.flippedAntiDiagonally): fragment.rotation = 90 flippedHorizontally = cell.flippedVertically flippedVertically = not cell.flippedHorizontally # Compensate for the swap of image dimensions halfDiff = sizeHalf.y() - sizeHalf.x() fragment.y += halfDiff if (origin != CellRenderer.BottomCenter): fragment.x += halfDiff if flippedHorizontally: x = -1 else: x = 1 fragment.scaleX = scale.width() * x if flippedVertically: x = -1 else: x = 1 fragment.scaleY = scale.height() * x if (self.mIsOpenGL or (fragment.scaleX > 0 and fragment.scaleY > 0)): self.mTile = cell.tile self.mFragments.append(fragment) return # The Raster paint engine as of Qt 4.8.4 / 5.0.2 does not support # drawing fragments with a negative scaling factor. self.flush() # make sure we drew all tiles so far oldTransform = self.mPainter.transform() transform = oldTransform transform.translate(fragment.x, fragment.y) transform.rotate(fragment.rotation) transform.scale(fragment.scaleX, fragment.scaleY) target = QRectF(fragment.width * -0.5, fragment.height * -0.5, fragment.width, fragment.height) source = QRectF(0, 0, fragment.width, fragment.height) self.mPainter.setTransform(transform) self.mPainter.drawPixmap(target, image, source) self.mPainter.setTransform(oldTransform)
def updateResizingSingleItem(self, resizingOrigin, screenPos, modifiers): renderer = self.mapDocument().renderer() object = self.mMovingObjects.first() mapObject = object.item.mapObject() ## The resizingOrigin, screenPos and mStart are affected by the ObjectGroup # offset. We will un-apply it to these variables since the resize for # single items happens in local coordinate space. ## offset = mapObject.objectGroup().offset() ## These transformations undo and redo the object rotation, which is always # applied in screen space. ## unrotate = rotateAt(object.oldItemPosition, -object.oldRotation) rotate = rotateAt(object.oldItemPosition, object.oldRotation) origin = (resizingOrigin - offset) * unrotate pos = (screenPos - offset) * unrotate start = (self.mStart - offset) * unrotate oldPos = object.oldItemPosition ## In order for the resizing to work somewhat sanely in isometric mode, # the resizing is performed in pixel space except for tile objects, which # are not affected by isometric projection apart from their position. ## pixelSpace = resizeInPixelSpace(mapObject) preserveAspect = modifiers & Qt.ControlModifier if (pixelSpace): origin = renderer.screenToPixelCoords_(origin) pos = renderer.screenToPixelCoords_(pos) start = renderer.screenToPixelCoords_(start) oldPos = object.oldPosition newPos = oldPos newSize = object.oldSize ## In case one of the anchors was used as-is, the desired size can be # derived directly from the distance from the origin for rectangle # and ellipse objects. This allows scaling up a 0-sized object without # dealing with infinite scaling factor issues. # # For obvious reasons this can't work on polygons or polylines, nor when # preserving the aspect ratio. ## if (self.mClickedResizeHandle.resizingOrigin() == resizingOrigin and (mapObject.shape() == MapObject.Rectangle or mapObject.shape() == MapObject.Ellipse) and not preserveAspect): newBounds = QRectF(newPos, newSize) newBounds = align(newBounds, mapObject.alignment()) x = self.mClickedResizeHandle.anchorPosition() if x==AnchorPosition.LeftAnchor or x==AnchorPosition.TopLeftAnchor or x==AnchorPosition.BottomLeftAnchor: newBounds.setLeft(min(pos.x(), origin.x())) elif x==AnchorPosition.RightAnchor or x==AnchorPosition.TopRightAnchor or x==AnchorPosition.BottomRightAnchor: newBounds.setRight(max(pos.x(), origin.x())) else: # nothing to do on this axis pass x = self.mClickedResizeHandle.anchorPosition() if x==AnchorPosition.TopAnchor or x==AnchorPosition.TopLeftAnchor or x==AnchorPosition.TopRightAnchor: newBounds.setTop(min(pos.y(), origin.y())) elif x==AnchorPosition.BottomAnchor or x==AnchorPosition.BottomLeftAnchor or x==AnchorPosition.BottomRightAnchor: newBounds.setBottom(max(pos.y(), origin.y())) else: # nothing to do on this axis pass newBounds = unalign(newBounds, mapObject.alignment()) newSize = newBounds.size() newPos = newBounds.topLeft() else: relPos = pos - origin startDiff = start - origin try: newx = relPos.x() / startDiff.x() except: newx = 0 try: newy = relPos.y() / startDiff.y() except: newy = 0 scalingFactor = QSizeF(max(0.01, newx), max(0.01, newy)) if not math.isfinite(scalingFactor.width()): scalingFactor.setWidth(1) if not math.isfinite(scalingFactor.height()): scalingFactor.setHeight(1) if (self.mResizingLimitHorizontal): if preserveAspect: scalingFactor.setWidth(scalingFactor.height()) else: scalingFactor.setWidth(1) elif (self.mResizingLimitVertical): if preserveAspect: scalingFactor.setHeight(scalingFactor.width()) else: scalingFactor.setHeight(1) elif (preserveAspect): scale = min(scalingFactor.width(), scalingFactor.height()) scalingFactor.setWidth(scale) scalingFactor.setHeight(scale) oldRelPos = oldPos - origin newPos = origin + QPointF(oldRelPos.x() * scalingFactor.width(), oldRelPos.y() * scalingFactor.height()) newSize.setWidth(newSize.width() * scalingFactor.width()) newSize.setHeight(newSize.height() * scalingFactor.height()) if (not object.oldPolygon.isEmpty()): newPolygon = QPolygonF(object.oldPolygon.size()) for n in range(object.oldPolygon.size()): point = object.oldPolygon[n] newPolygon[n] = QPointF(point.x() * scalingFactor.width(), point.y() * scalingFactor.height()) mapObject.setPolygon(newPolygon) if (pixelSpace): newPos = renderer.pixelToScreenCoords_(newPos) newPos = renderer.screenToPixelCoords_(newPos * rotate) mapObject.setSize(newSize) mapObject.setPosition(newPos) self.mapDocument().mapObjectModel().emitObjectsChanged(self.changingObjects())
class MapObject(Object): ## # Enumerates the different object shapes. Rectangle is the default shape. # When a polygon is set, the shape determines whether it should be # interpreted as a filled polygon or a line. ## Rectangle, Polygon, Polyline, Ellipse = range(4) def __init__(self, *args): super().__init__(Object.MapObjectType) self.mPolygon = QPolygonF() self.mName = QString() self.mPos = QPointF() self.mCell = Cell() self.mType = QString() self.mId = 0 self.mShape = MapObject.Rectangle self.mObjectGroup = None self.mRotation = 0.0 self.mVisible = True l = len(args) if l == 0: self.mSize = QSizeF(0, 0) elif l == 4: name, _type, pos, size = args self.mName = name self.mType = _type self.mPos = pos self.mSize = QSizeF(size) ## # Returns the id of this object. Each object gets an id assigned that is # unique for the map the object is on. ## def id(self): return self.mId ## # Sets the id of this object. ## def setId(self, id): self.mId = id ## # Returns the name of this object. The name is usually just used for # identification of the object in the editor. ## def name(self): return self.mName ## # Sets the name of this object. ## def setName(self, name): self.mName = name ## # Returns the type of this object. The type usually says something about # how the object is meant to be interpreted by the engine. ## def type(self): return self.mType ## # Sets the type of this object. ## def setType(self, type): self.mType = type ## # Returns the position of this object. ## def position(self): return QPointF(self.mPos) ## # Sets the position of this object. ## def setPosition(self, pos): self.mPos = pos ## # Returns the x position of this object. ## def x(self): return self.mPos.x() ## # Sets the x position of this object. ## def setX(self, x): self.mPos.setX(x) ## # Returns the y position of this object. ## def y(self): return self.mPos.y() ## # Sets the x position of this object. ## def setY(self, y): self.mPos.setY(y) ## # Returns the size of this object. ## def size(self): return self.mSize ## # Sets the size of this object. ## def setSize(self, *args): l = len(args) if l == 1: size = args[0] self.mSize = QSizeF(size) elif l == 2: width, height = args self.setSize(QSizeF(width, height)) ## # Returns the width of this object. ## def width(self): return self.mSize.width() ## # Sets the width of this object. ## def setWidth(self, width): self.mSize.setWidth(width) ## # Returns the height of this object. ## def height(self): return self.mSize.height() ## # Sets the height of this object. ## def setHeight(self, height): self.mSize.setHeight(height) ## # Sets the polygon associated with this object. The polygon is only used # when the object shape is set to either Polygon or Polyline. # # \sa setShape() ## def setPolygon(self, polygon): self.mPolygon = polygon ## # Returns the polygon associated with this object. Returns an empty # polygon when no polygon is associated with this object. ## def polygon(self): return QPolygonF(self.mPolygon) ## # Sets the shape of the object. ## def setShape(self, shape): self.mShape = shape ## # Returns the shape of the object. ## def shape(self): return self.mShape ## # Shortcut to getting a QRectF from position() and size(). ## def bounds(self): return QRectF(self.mPos, self.mSize) ## # Shortcut to getting a QRectF from position() and size() that uses cell tile if present. ## def boundsUseTile(self): if (self.mCell.isEmpty()): # No tile so just use regular bounds return self.bounds() # Using the tile for determing boundary # Note the position given is the bottom-left corner so correct for that return QRectF( QPointF(self.mPos.x(), self.mPos.y() - self.mCell.tile.height()), self.mCell.tile.size()) ## # Sets the tile that is associated with this object. The object will # display as the tile image. # # \warning The object shape is ignored for tile objects! ## def setCell(self, cell): self.mCell = cell ## # Returns the tile associated with this object. ## def cell(self): return self.mCell ## # Returns the object group this object belongs to. ## def objectGroup(self): return self.mObjectGroup ## # Sets the object group this object belongs to. Should only be called # from the ObjectGroup class. ## def setObjectGroup(self, objectGroup): self.mObjectGroup = objectGroup ## # Returns the rotation of the object in degrees. ## def rotation(self): return self.mRotation ## # Sets the rotation of the object in degrees. ## def setRotation(self, rotation): self.mRotation = rotation ## # This is somewhat of a workaround for dealing with the ways different objects # align. # # Traditional rectangle objects have top-left alignment. # Tile objects have bottom-left alignment on orthogonal maps, but # bottom-center alignment on isometric maps. # # Eventually, the object alignment should probably be configurable. For # backwards compatibility, it will need to be configurable on a per-object # level. ## def alignment(self): if (self.mCell.isEmpty()): return Alignment.TopLeft elif (self.mObjectGroup): map = self.mObjectGroup.map() if map: if (map.orientation() == Map.Orientation.Isometric): return Alignment.Bottom return Alignment.BottomLeft def isVisible(self): return self.mVisible def setVisible(self, visible): self.mVisible = visible ## # Flip this object in the given \a direction. This doesn't change the size # of the object. ## def flip(self, direction): if (not self.mCell.isEmpty()): if (direction == FlipDirection.FlipHorizontally): self.mCell.flippedHorizontally = not self.mCell.flippedHorizontally elif (direction == FlipDirection.FlipVertically): self.mCell.flippedVertically = not self.mCell.flippedVertically if (not self.mPolygon.isEmpty()): center2 = self.mPolygon.boundingRect().center() * 2 if (direction == FlipDirection.FlipHorizontally): for i in range(self.mPolygon.size()): # oh, QPointF mPolygon returned is a copy of internal object self.mPolygon[i] = QPointF( center2.x() - self.mPolygon[i].x(), self.mPolygon[i].y()) elif (direction == FlipDirection.FlipVertically): for i in range(self.mPolygon.size()): self.mPolygon[i] = QPointF( self.mPolygon[i].x(), center2.y() - self.mPolygon[i].y()) ## # Returns a duplicate of this object. The caller is responsible for the # ownership of this newly created object. ## def clone(self): o = MapObject(self.mName, self.mType, self.mPos, self.mSize) o.setProperties(self.properties()) o.setPolygon(self.mPolygon) o.setShape(self.mShape) o.setCell(self.mCell) o.setRotation(self.mRotation) return o
def updateResizingSingleItem(self, resizingOrigin, screenPos, modifiers): renderer = self.mapDocument().renderer() object = self.mMovingObjects.first() mapObject = object.item.mapObject() ## The resizingOrigin, screenPos and mStart are affected by the ObjectGroup # offset. We will un-apply it to these variables since the resize for # single items happens in local coordinate space. ## offset = mapObject.objectGroup().offset() ## These transformations undo and redo the object rotation, which is always # applied in screen space. ## unrotate = rotateAt(object.oldItemPosition, -object.oldRotation) rotate = rotateAt(object.oldItemPosition, object.oldRotation) origin = (resizingOrigin - offset) * unrotate pos = (screenPos - offset) * unrotate start = (self.mStart - offset) * unrotate oldPos = object.oldItemPosition ## In order for the resizing to work somewhat sanely in isometric mode, # the resizing is performed in pixel space except for tile objects, which # are not affected by isometric projection apart from their position. ## pixelSpace = resizeInPixelSpace(mapObject) preserveAspect = modifiers & Qt.ControlModifier if (pixelSpace): origin = renderer.screenToPixelCoords_(origin) pos = renderer.screenToPixelCoords_(pos) start = renderer.screenToPixelCoords_(start) oldPos = object.oldPosition newPos = oldPos newSize = object.oldSize ## In case one of the anchors was used as-is, the desired size can be # derived directly from the distance from the origin for rectangle # and ellipse objects. This allows scaling up a 0-sized object without # dealing with infinite scaling factor issues. # # For obvious reasons this can't work on polygons or polylines, nor when # preserving the aspect ratio. ## if (self.mClickedResizeHandle.resizingOrigin() == resizingOrigin and (mapObject.shape() == MapObject.Rectangle or mapObject.shape() == MapObject.Ellipse) and not preserveAspect): newBounds = QRectF(newPos, newSize) newBounds = align(newBounds, mapObject.alignment()) x = self.mClickedResizeHandle.anchorPosition() if x == AnchorPosition.LeftAnchor or x == AnchorPosition.TopLeftAnchor or x == AnchorPosition.BottomLeftAnchor: newBounds.setLeft(min(pos.x(), origin.x())) elif x == AnchorPosition.RightAnchor or x == AnchorPosition.TopRightAnchor or x == AnchorPosition.BottomRightAnchor: newBounds.setRight(max(pos.x(), origin.x())) else: # nothing to do on this axis pass x = self.mClickedResizeHandle.anchorPosition() if x == AnchorPosition.TopAnchor or x == AnchorPosition.TopLeftAnchor or x == AnchorPosition.TopRightAnchor: newBounds.setTop(min(pos.y(), origin.y())) elif x == AnchorPosition.BottomAnchor or x == AnchorPosition.BottomLeftAnchor or x == AnchorPosition.BottomRightAnchor: newBounds.setBottom(max(pos.y(), origin.y())) else: # nothing to do on this axis pass newBounds = unalign(newBounds, mapObject.alignment()) newSize = newBounds.size() newPos = newBounds.topLeft() else: relPos = pos - origin startDiff = start - origin try: newx = relPos.x() / startDiff.x() except: newx = 0 try: newy = relPos.y() / startDiff.y() except: newy = 0 scalingFactor = QSizeF(max(0.01, newx), max(0.01, newy)) if not math.isfinite(scalingFactor.width()): scalingFactor.setWidth(1) if not math.isfinite(scalingFactor.height()): scalingFactor.setHeight(1) if (self.mResizingLimitHorizontal): if preserveAspect: scalingFactor.setWidth(scalingFactor.height()) else: scalingFactor.setWidth(1) elif (self.mResizingLimitVertical): if preserveAspect: scalingFactor.setHeight(scalingFactor.width()) else: scalingFactor.setHeight(1) elif (preserveAspect): scale = min(scalingFactor.width(), scalingFactor.height()) scalingFactor.setWidth(scale) scalingFactor.setHeight(scale) oldRelPos = oldPos - origin newPos = origin + QPointF(oldRelPos.x() * scalingFactor.width(), oldRelPos.y() * scalingFactor.height()) newSize.setWidth(newSize.width() * scalingFactor.width()) newSize.setHeight(newSize.height() * scalingFactor.height()) if (not object.oldPolygon.isEmpty()): newPolygon = QPolygonF(object.oldPolygon.size()) for n in range(object.oldPolygon.size()): point = object.oldPolygon[n] newPolygon[n] = QPointF(point.x() * scalingFactor.width(), point.y() * scalingFactor.height()) mapObject.setPolygon(newPolygon) if (pixelSpace): newPos = renderer.pixelToScreenCoords_(newPos) newPos = renderer.screenToPixelCoords_(newPos * rotate) mapObject.setSize(newSize) mapObject.setPosition(newPos) self.mapDocument().mapObjectModel().emitObjectsChanged( self.changingObjects())
def denormalize_rect(area: QSizeF, rect: QRectF) -> QRectF: return QRectF(rect.x() * area.width(), rect.y() * area.height(), rect.width() * area.width(), rect.height() * area.height())
def paint(self, painter): painter.setRenderHint(QPainter.Antialiasing) pixelRatio = self.devicePixelRatioF() rect = QRectF(0, 0, self.width() * pixelRatio, self.height() * pixelRatio) sz = QSizeF(self.width() * pixelRatio, self.height() * pixelRatio).toSize() self.resizePixmap(sz) yOffset = rect.toRect().topLeft().y() + (100 - self.value() - 10) * sz.height() / 100 # draw water waterImage = QImage(sz, QImage.Format_ARGB32_Premultiplied) waterPainter = QPainter() waterPainter.begin(waterImage) waterPainter.setRenderHint(QPainter.Antialiasing) waterPainter.setCompositionMode(QPainter.CompositionMode_Source) pointStart = QPointF(sz.width() / 2, 0) pointEnd = QPointF(sz.width() / 2, sz.height()) linear = QLinearGradient(pointStart, pointEnd) startColor = QColor('#1F08FF') startColor.setAlphaF(1) endColor = QColor('#50FFF7') endColor.setAlphaF(0.28) linear.setColorAt(0, startColor) linear.setColorAt(1, endColor) linear.setSpread(QGradient.PadSpread) waterPainter.setPen(Qt.NoPen) waterPainter.setBrush(linear) waterPainter.drawEllipse(waterImage.rect().center(), sz.width() / 2 + 1, sz.height() / 2 + 1) waterPainter.setCompositionMode(QPainter.CompositionMode_SourceOver) waterPainter.drawImage(int(self.backXOffset), yOffset, self.waterBackImage) waterPainter.drawImage( int(self.backXOffset) - self.waterBackImage.width(), yOffset, self.waterBackImage) waterPainter.drawImage(int(self.frontXOffset), yOffset, self.waterFrontImage) waterPainter.drawImage( int(self.frontXOffset) - self.waterFrontImage.width(), yOffset, self.waterFrontImage) # draw pop if self.value() > 30: for pop in self.pops: popPath = QPainterPath() popPath.addEllipse(pop.xOffset * sz.width() / 100, (100 - pop.yOffset) * sz.height() / 100, pop.size * sz.width() / 100, pop.size * sz.height() / 100) waterPainter.fillPath(popPath, QColor(255, 255, 255, 255 * 0.3)) if self.isTextVisible(): font = waterPainter.font() rectValue = QRect() progressText = self.text().strip('%') if progressText == '100': font.setPixelSize(sz.height() * 35 / 100) waterPainter.setFont(font) rectValue.setWidth(sz.width() * 60 / 100) rectValue.setHeight(sz.height() * 35 / 100) rectValue.moveCenter(rect.center().toPoint()) waterPainter.setPen(Qt.white) waterPainter.drawText(rectValue, Qt.AlignCenter, progressText) else: font.setPixelSize(sz.height() * 40 / 100) waterPainter.setFont(font) rectValue.setWidth(sz.width() * 45 / 100) rectValue.setHeight(sz.height() * 40 / 100) rectValue.moveCenter(rect.center().toPoint()) rectValue.moveLeft(rect.left() + rect.width() * 0.45 * 0.5) waterPainter.setPen(Qt.white) waterPainter.drawText(rectValue, Qt.AlignCenter, progressText) font.setPixelSize(font.pixelSize() / 2) waterPainter.setFont(font) rectPerent = QRect( QPoint(rectValue.right(), rectValue.bottom() - rect.height() * 20 / 100), QPoint(rectValue.right() + rect.width() * 20 / 100, rectValue.bottom())) waterPainter.drawText(rectPerent, Qt.AlignCenter, '%') waterPainter.end() maskPixmap = QPixmap(sz) maskPixmap.fill(Qt.transparent) path = QPainterPath() path.addEllipse(QRectF(0, 0, sz.width(), sz.height())) maskPainter = QPainter() maskPainter.begin(maskPixmap) maskPainter.setRenderHint(QPainter.Antialiasing) maskPainter.setPen(QPen(Qt.white, 1)) maskPainter.fillPath(path, QBrush(Qt.white)) maskPainter.end() mode = QPainter.CompositionMode_SourceIn contentImage = QImage(sz, QImage.Format_ARGB32_Premultiplied) contentPainter = QPainter() contentPainter.begin(contentImage) contentPainter.setCompositionMode(QPainter.CompositionMode_Source) contentPainter.fillRect(contentImage.rect(), Qt.transparent) contentPainter.setCompositionMode(QPainter.CompositionMode_SourceOver) contentPainter.drawImage(0, 0, maskPixmap.toImage()) contentPainter.setCompositionMode(mode) contentPainter.drawImage(0, 0, waterImage) contentPainter.setCompositionMode( QPainter.CompositionMode_DestinationOver) contentPainter.end() contentImage.setDevicePixelRatio(pixelRatio) painter.drawImage(self.rect(), contentImage)
def drawMapObject(self, painter, object, color): painter.save() pen = QPen(Qt.black) pen.setCosmetic(True) cell = object.cell() if (not cell.isEmpty()): tile = cell.tile imgSize = tile.size() pos = self.pixelToScreenCoords_(object.position()) tileOffset = tile.offset() CellRenderer(painter).render(cell, pos, object.size(), CellRenderer.BottomCenter) if (self.testFlag(RenderFlag.ShowTileObjectOutlines)): rect = QRectF(QPointF(pos.x() - imgSize.width() / 2 + tileOffset.x(), pos.y() - imgSize.height() + tileOffset.y()), QSizeF(imgSize)) pen.setStyle(Qt.SolidLine) painter.setPen(pen) painter.drawRect(rect) pen.setStyle(Qt.DotLine) pen.setColor(color) painter.setPen(pen) painter.drawRect(rect) else: lineWidth = self.objectLineWidth() scale = self.painterScale() x = 1 if lineWidth != 0: x = lineWidth shadowOffset = x / scale brushColor = QColor(color) brushColor.setAlpha(50) brush = QBrush(brushColor) pen.setJoinStyle(Qt.RoundJoin) pen.setCapStyle(Qt.RoundCap) pen.setWidth(lineWidth) colorPen = QPen(pen) colorPen.setColor(color) painter.setPen(pen) painter.setRenderHint(QPainter.Antialiasing) # TODO: Do something sensible to make null-sized objects usable x = object.shape() if x==MapObject.Ellipse: polygon = self.pixelRectToScreenPolygon(object.bounds()) tw = self.map().tileWidth() th = self.map().tileHeight() transformScale = QPointF(1, 1) if (tw > th): transformScale = QPointF(1, th/tw) else: transformScale = QPointF(tw/th, 1) l1 = polygon.at(1) - polygon.at(0) l2 = polygon.at(3) - polygon.at(0) trans = QTransform() trans.scale(transformScale.x(), transformScale.y()) trans.rotate(45) iTrans, ok = trans.inverted() l1x = iTrans.map(l1) l2x = iTrans.map(l2) ellipseSize = QSizeF(l1x.manhattanLength(), l2x.manhattanLength()) if (ellipseSize.width() > 0 and ellipseSize.height() > 0): painter.save() painter.setPen(pen) painter.translate(polygon.at(0)) painter.scale(transformScale.x(), transformScale.y()) painter.rotate(45) painter.drawEllipse(QRectF(QPointF(0, 0), ellipseSize)) painter.restore() painter.setBrush(Qt.NoBrush) painter.drawPolygon(polygon) painter.setPen(colorPen) painter.setBrush(Qt.NoBrush) painter.translate(QPointF(0, -shadowOffset)) painter.drawPolygon(polygon) painter.setBrush(brush) if (ellipseSize.width() > 0 and ellipseSize.height() > 0): painter.save() painter.translate(polygon.at(0)) painter.scale(transformScale.x(), transformScale.y()) painter.rotate(45) painter.drawEllipse(QRectF(QPointF(0, 0), ellipseSize)) painter.restore() elif x==MapObject.Rectangle: polygon = self.pixelRectToScreenPolygon(object.bounds()) painter.drawPolygon(polygon) painter.setPen(colorPen) painter.setBrush(brush) polygon.translate(0, -shadowOffset) painter.drawPolygon(polygon) elif x==MapObject.Polygon: pos = object.position() polygon = object.polygon().translated(pos) screenPolygon = self.pixelToScreenCoords_(polygon) thickPen = QPen(pen) thickColorPen = QPen(colorPen) thickPen.setWidthF(thickPen.widthF() * 4) thickColorPen.setWidthF(thickColorPen.widthF() * 4) painter.drawPolygon(screenPolygon) painter.setPen(thickPen) painter.drawPoint(screenPolygon.first()) painter.setPen(colorPen) painter.setBrush(brush) screenPolygon.translate(0, -shadowOffset) painter.drawPolygon(screenPolygon) painter.setPen(thickColorPen) painter.drawPoint(screenPolygon.first()) elif x==MapObject.Polyline: pos = object.position() polygon = object.polygon().translated(pos) screenPolygon = self.pixelToScreenCoords_(polygon) thickPen = QPen(pen) thickColorPen = QPen(colorPen) thickPen.setWidthF(thickPen.widthF() * 4) thickColorPen.setWidthF(thickColorPen.widthF() * 4) painter.drawPolyline(screenPolygon) painter.setPen(thickPen) painter.drawPoint(screenPolygon.first()) painter.setPen(colorPen) screenPolygon.translate(0, -shadowOffset) painter.drawPolyline(screenPolygon) painter.setPen(thickColorPen) painter.drawPoint(screenPolygon.first()) painter.restore()
def drawMapObject(self, painter, object, color): painter.save() pen = QPen(Qt.black) pen.setCosmetic(True) cell = object.cell() if (not cell.isEmpty()): tile = cell.tile imgSize = tile.size() pos = self.pixelToScreenCoords_(object.position()) tileOffset = tile.offset() CellRenderer(painter).render(cell, pos, object.size(), CellRenderer.BottomCenter) if (self.testFlag(RenderFlag.ShowTileObjectOutlines)): rect = QRectF( QPointF(pos.x() - imgSize.width() / 2 + tileOffset.x(), pos.y() - imgSize.height() + tileOffset.y()), QSizeF(imgSize)) pen.setStyle(Qt.SolidLine) painter.setPen(pen) painter.drawRect(rect) pen.setStyle(Qt.DotLine) pen.setColor(color) painter.setPen(pen) painter.drawRect(rect) else: lineWidth = self.objectLineWidth() scale = self.painterScale() x = 1 if lineWidth != 0: x = lineWidth shadowOffset = x / scale brushColor = QColor(color) brushColor.setAlpha(50) brush = QBrush(brushColor) pen.setJoinStyle(Qt.RoundJoin) pen.setCapStyle(Qt.RoundCap) pen.setWidth(lineWidth) colorPen = QPen(pen) colorPen.setColor(color) painter.setPen(pen) painter.setRenderHint(QPainter.Antialiasing) # TODO: Do something sensible to make null-sized objects usable x = object.shape() if x == MapObject.Ellipse: polygon = self.pixelRectToScreenPolygon(object.bounds()) tw = self.map().tileWidth() th = self.map().tileHeight() transformScale = QPointF(1, 1) if (tw > th): transformScale = QPointF(1, th / tw) else: transformScale = QPointF(tw / th, 1) l1 = polygon.at(1) - polygon.at(0) l2 = polygon.at(3) - polygon.at(0) trans = QTransform() trans.scale(transformScale.x(), transformScale.y()) trans.rotate(45) iTrans, ok = trans.inverted() l1x = iTrans.map(l1) l2x = iTrans.map(l2) ellipseSize = QSizeF(l1x.manhattanLength(), l2x.manhattanLength()) if (ellipseSize.width() > 0 and ellipseSize.height() > 0): painter.save() painter.setPen(pen) painter.translate(polygon.at(0)) painter.scale(transformScale.x(), transformScale.y()) painter.rotate(45) painter.drawEllipse(QRectF(QPointF(0, 0), ellipseSize)) painter.restore() painter.setBrush(Qt.NoBrush) painter.drawPolygon(polygon) painter.setPen(colorPen) painter.setBrush(Qt.NoBrush) painter.translate(QPointF(0, -shadowOffset)) painter.drawPolygon(polygon) painter.setBrush(brush) if (ellipseSize.width() > 0 and ellipseSize.height() > 0): painter.save() painter.translate(polygon.at(0)) painter.scale(transformScale.x(), transformScale.y()) painter.rotate(45) painter.drawEllipse(QRectF(QPointF(0, 0), ellipseSize)) painter.restore() elif x == MapObject.Rectangle: polygon = self.pixelRectToScreenPolygon(object.bounds()) painter.drawPolygon(polygon) painter.setPen(colorPen) painter.setBrush(brush) polygon.translate(0, -shadowOffset) painter.drawPolygon(polygon) elif x == MapObject.Polygon: pos = object.position() polygon = object.polygon().translated(pos) screenPolygon = self.pixelToScreenCoords_(polygon) thickPen = QPen(pen) thickColorPen = QPen(colorPen) thickPen.setWidthF(thickPen.widthF() * 4) thickColorPen.setWidthF(thickColorPen.widthF() * 4) painter.drawPolygon(screenPolygon) painter.setPen(thickPen) painter.drawPoint(screenPolygon.first()) painter.setPen(colorPen) painter.setBrush(brush) screenPolygon.translate(0, -shadowOffset) painter.drawPolygon(screenPolygon) painter.setPen(thickColorPen) painter.drawPoint(screenPolygon.first()) elif x == MapObject.Polyline: pos = object.position() polygon = object.polygon().translated(pos) screenPolygon = self.pixelToScreenCoords_(polygon) thickPen = QPen(pen) thickColorPen = QPen(colorPen) thickPen.setWidthF(thickPen.widthF() * 4) thickColorPen.setWidthF(thickColorPen.widthF() * 4) painter.drawPolyline(screenPolygon) painter.setPen(thickPen) painter.drawPoint(screenPolygon.first()) painter.setPen(colorPen) screenPolygon.translate(0, -shadowOffset) painter.drawPolyline(screenPolygon) painter.setPen(thickColorPen) painter.drawPoint(screenPolygon.first()) painter.restore()
def chgRowHeight(self, index: QModelIndex, size: QSizeF): if not index.isValid(): return row = index.row() self.table.setRowHeight(row, size.height())
class MapObject(Object): ## # Enumerates the different object shapes. Rectangle is the default shape. # When a polygon is set, the shape determines whether it should be # interpreted as a filled polygon or a line. ## Rectangle, Polygon, Polyline, Ellipse = range(4) def __init__(self, *args): super().__init__(Object.MapObjectType) self.mPolygon = QPolygonF() self.mName = QString() self.mPos = QPointF() self.mCell = Cell() self.mType = QString() self.mId = 0 self.mShape = MapObject.Rectangle self.mObjectGroup = None self.mRotation = 0.0 self.mVisible = True l = len(args) if l==0: self.mSize = QSizeF(0, 0) elif l==4: name, _type, pos, size = args self.mName = name self.mType = _type self.mPos = pos self.mSize = QSizeF(size) ## # Returns the id of this object. Each object gets an id assigned that is # unique for the map the object is on. ## def id(self): return self.mId ## # Sets the id of this object. ## def setId(self, id): self.mId = id ## # Returns the name of this object. The name is usually just used for # identification of the object in the editor. ## def name(self): return self.mName ## # Sets the name of this object. ## def setName(self, name): self.mName = name ## # Returns the type of this object. The type usually says something about # how the object is meant to be interpreted by the engine. ## def type(self): return self.mType ## # Sets the type of this object. ## def setType(self, type): self.mType = type ## # Returns the position of this object. ## def position(self): return QPointF(self.mPos) ## # Sets the position of this object. ## def setPosition(self, pos): self.mPos = pos ## # Returns the x position of this object. ## def x(self): return self.mPos.x() ## # Sets the x position of this object. ## def setX(self, x): self.mPos.setX(x) ## # Returns the y position of this object. ## def y(self): return self.mPos.y() ## # Sets the x position of this object. ## def setY(self, y): self.mPos.setY(y) ## # Returns the size of this object. ## def size(self): return self.mSize ## # Sets the size of this object. ## def setSize(self, *args): l = len(args) if l==1: size = args[0] self.mSize = QSizeF(size) elif l==2: width, height = args self.setSize(QSizeF(width, height)) ## # Returns the width of this object. ## def width(self): return self.mSize.width() ## # Sets the width of this object. ## def setWidth(self, width): self.mSize.setWidth(width) ## # Returns the height of this object. ## def height(self): return self.mSize.height() ## # Sets the height of this object. ## def setHeight(self, height): self.mSize.setHeight(height) ## # Sets the polygon associated with this object. The polygon is only used # when the object shape is set to either Polygon or Polyline. # # \sa setShape() ## def setPolygon(self, polygon): self.mPolygon = polygon ## # Returns the polygon associated with this object. Returns an empty # polygon when no polygon is associated with this object. ## def polygon(self): return QPolygonF(self.mPolygon) ## # Sets the shape of the object. ## def setShape(self, shape): self.mShape = shape ## # Returns the shape of the object. ## def shape(self): return self.mShape ## # Shortcut to getting a QRectF from position() and size(). ## def bounds(self): return QRectF(self.mPos, self.mSize) ## # Shortcut to getting a QRectF from position() and size() that uses cell tile if present. ## def boundsUseTile(self): if (self.mCell.isEmpty()): # No tile so just use regular bounds return self.bounds() # Using the tile for determing boundary # Note the position given is the bottom-left corner so correct for that return QRectF(QPointF(self.mPos.x(), self.mPos.y() - self.mCell.tile.height()), self.mCell.tile.size()) ## # Sets the tile that is associated with this object. The object will # display as the tile image. # # \warning The object shape is ignored for tile objects! ## def setCell(self, cell): self.mCell = cell ## # Returns the tile associated with this object. ## def cell(self): return self.mCell ## # Returns the object group this object belongs to. ## def objectGroup(self): return self.mObjectGroup ## # Sets the object group this object belongs to. Should only be called # from the ObjectGroup class. ## def setObjectGroup(self, objectGroup): self.mObjectGroup = objectGroup ## # Returns the rotation of the object in degrees. ## def rotation(self): return self.mRotation ## # Sets the rotation of the object in degrees. ## def setRotation(self, rotation): self.mRotation = rotation ## # This is somewhat of a workaround for dealing with the ways different objects # align. # # Traditional rectangle objects have top-left alignment. # Tile objects have bottom-left alignment on orthogonal maps, but # bottom-center alignment on isometric maps. # # Eventually, the object alignment should probably be configurable. For # backwards compatibility, it will need to be configurable on a per-object # level. ## def alignment(self): if (self.mCell.isEmpty()): return Alignment.TopLeft elif (self.mObjectGroup): map = self.mObjectGroup.map() if map: if (map.orientation() == Map.Orientation.Isometric): return Alignment.Bottom return Alignment.BottomLeft def isVisible(self): return self.mVisible def setVisible(self, visible): self.mVisible = visible ## # Flip this object in the given \a direction. This doesn't change the size # of the object. ## def flip(self, direction): if (not self.mCell.isEmpty()): if (direction == FlipDirection.FlipHorizontally): self.mCell.flippedHorizontally = not self.mCell.flippedHorizontally elif (direction == FlipDirection.FlipVertically): self.mCell.flippedVertically = not self.mCell.flippedVertically if (not self.mPolygon.isEmpty()): center2 = self.mPolygon.boundingRect().center() * 2 if (direction == FlipDirection.FlipHorizontally): for i in range(self.mPolygon.size()): # oh, QPointF mPolygon returned is a copy of internal object self.mPolygon[i] = QPointF(center2.x() - self.mPolygon[i].x(), self.mPolygon[i].y()) elif (direction == FlipDirection.FlipVertically): for i in range(self.mPolygon.size()): self.mPolygon[i] = QPointF(self.mPolygon[i].x(), center2.y() - self.mPolygon[i].y()) ## # Returns a duplicate of this object. The caller is responsible for the # ownership of this newly created object. ## def clone(self): o = MapObject(self.mName, self.mType, self.mPos, self.mSize) o.setProperties(self.properties()) o.setPolygon(self.mPolygon) o.setShape(self.mShape) o.setCell(self.mCell) o.setRotation(self.mRotation) return o
def render(self, cell, pos, cellSize, origin): if (self.mTile != cell.tile): self.flush() image = cell.tile.currentFrameImage() size = image.size() if cellSize == QSizeF(0,0): objectSize = size else: objectSize = cellSize scale = QSizeF(objectSize.width() / size.width(), objectSize.height() / size.height()) offset = cell.tile.offset() sizeHalf = QPointF(objectSize.width() / 2, objectSize.height() / 2) fragment = QPainter.PixmapFragment() fragment.x = pos.x() + (offset.x() * scale.width()) + sizeHalf.x() fragment.y = pos.y() + (offset.y() * scale.height()) + sizeHalf.y() - objectSize.height() fragment.sourceLeft = 0 fragment.sourceTop = 0 fragment.width = size.width() fragment.height = size.height() if cell.flippedHorizontally: fragment.scaleX = -1 else: fragment.scaleX = 1 if cell.flippedVertically: fragment.scaleY = -1 else: fragment.scaleY = 1 fragment.rotation = 0 fragment.opacity = 1 flippedHorizontally = cell.flippedHorizontally flippedVertically = cell.flippedVertically if (origin == CellRenderer.BottomCenter): fragment.x -= sizeHalf.x() if (cell.flippedAntiDiagonally): fragment.rotation = 90 flippedHorizontally = cell.flippedVertically flippedVertically = not cell.flippedHorizontally # Compensate for the swap of image dimensions halfDiff = sizeHalf.y() - sizeHalf.x() fragment.y += halfDiff if (origin != CellRenderer.BottomCenter): fragment.x += halfDiff if flippedHorizontally: x = -1 else: x = 1 fragment.scaleX = scale.width() * x if flippedVertically: x = -1 else: x = 1 fragment.scaleY = scale.height() * x if (self.mIsOpenGL or (fragment.scaleX > 0 and fragment.scaleY > 0)): self.mTile = cell.tile self.mFragments.append(fragment) return # The Raster paint engine as of Qt 4.8.4 / 5.0.2 does not support # drawing fragments with a negative scaling factor. self.flush() # make sure we drew all tiles so far oldTransform = self.mPainter.transform() transform = oldTransform transform.translate(fragment.x, fragment.y) transform.rotate(fragment.rotation) transform.scale(fragment.scaleX, fragment.scaleY) target = QRectF(fragment.width * -0.5, fragment.height * -0.5, fragment.width, fragment.height) source = QRectF(0, 0, fragment.width, fragment.height) self.mPainter.setTransform(transform) self.mPainter.drawPixmap(target, image, source) self.mPainter.setTransform(oldTransform)