示例#1
0
    def addNewBox(self, pos: QRect) -> None:
        if QApplication.keyboardModifiers() == Qt.ControlModifier:
            return

        if any(isinstance(elem, ResizeHandle) for elem in self.scene.selectedItems()):
            return

        if pos.isEmpty():
            return

        rect = CoupledRectangleElement(
            pos, self.connectionInput, editor=self._editor, scene=self.scene, parent=self.scene.parent()
        )
        rect.setZValue(len(self._currentBoxesList))
        rect.setColor(self.currentColor)
        self._currentBoxesList.append(rect)

        newRow = self.boxListModel.rowCount()
        box = BoxLabel(f"Box{newRow}", self.currentColor)

        box.colorChanged.connect(rect.setColor)
        box.lineWidthChanged.connect(rect.setLineWidth)
        box.fontColorChanged.connect(rect.setFontColor)
        box.fontSizeChanged.connect(rect.setFontSize)
        box.isFixedChanged.connect(self._fixedBoxesChanged)
        box.existenceChanged.connect(self._viewBoxesChanged)

        self.boxListModel.insertRow(newRow, box)
        box.existenceChanged.emit()
        rect.boxLabel = box
        box.isFixedChanged.connect(rect._rectItem.fixSelf)
        rect._updateTextWhenChanges()

        self.currentColor = self._getNextBoxColor()
    def displayGraph(self, selection: QRect):
        reader = self.mediaPlayer.reader()
        if not reader:
            logging.error("Video not available")
        self.values = []
        for frame_number in range(reader.num_frames):
            frame = reader.frame(frame_number)
            temperatures = frame.data
            if not selection.isEmpty():
                temperatures = temperatures[
                    selection.top() : selection.bottom(),
                    selection.left() : selection.right(),
                ]
            self.values.append(numpy.average(temperatures))

        self.plot.setData(self.values)
        self.displayCurrentTemperature(self.mediaPlayer.position())
        self.plotItem.getViewBox().autoRange(padding=0.11)
        self.plotItem.getViewBox().setRange(xRange=(-10, reader.num_frames * 1.12))
示例#3
0
class Manipulator(Tool):
    def __init__(self, canvas):
        super(Manipulator, self).__init__(canvas)

        self._name = 'Manipulator'
        self._load_icon(":/icons/ico_sel_move", ":/icons/ico_sel_move_hover")
        self._cursor = QPixmap(":/images/mover_cursor")

        self._pressMousePos = QPoint()
        self._lastMousePos = QPoint()
        self._curMousePos = QPoint()
        self._selectionRectangle = QRect()
        self._selectionRectColor = QColor(255, 255, 255, 50)
        self._selectionRectDashOffset = 0
        self._selectionImage = None
        self._cutOnSelection = True
        self._doEraseOnSelectionMove = False

        self._selectionBorderPen = QPen()
        self._selectionBorderPen.setWidth(0)
        self._selectionBorderPen.setStyle(Qt.DashLine)
        self._selectionBorderPen.setColor(Qt.white)

        self._selectionRectNodesPen = QPen()
        self._selectionRectNodesPen.setWidth(0)
        self._selectionRectNodesPen.setColor(Qt.white)

        self._state = ManipulatorState.Idle

    def draw_transformed(self, painter):

        if not self._selectionRectangle.isEmpty():
            painter.setPen(self._selectionBorderPen)
            painter.setOpacity(1.0)

            if self._selectionImage is None:

                painter.setCompositionMode(QPainter.CompositionMode_Difference)
                painter.fillRect(self._selectionRectangle, self._selectionRectColor)
                painter.drawRect(self._selectionRectangle)

            else:

                painter.setCompositionMode(QPainter.CompositionMode_SourceOver)
                painter.drawImage(self._selectionRectangle, self._selectionImage)

                painter.setCompositionMode(QPainter.CompositionMode_Difference)
                painter.drawRect(self._selectionRectangle)

            print('Selection Rect Draw')

    def draw_untransformed(self, painter):

        canvas = self._canvas

        x = canvas.mouse_state.global_pos.x() + 1
        y = canvas.mouse_state.global_pos.y() + 1

        if self._enablePointerDraw and self._state == ManipulatorState.Idle \
                or self._state == ManipulatorState.MovingSelection \
                or self._state == ManipulatorState.MovingPixels:
            painter.drawPixmap(x - self._cursor.width() / 2, y -
                               self._cursor.height() / 2, self._cursor)

    def update(self):
        self._animate_selection_border()

    def on_mouse_press(self):

        super(Manipulator, self).on_mouse_press()

        canvas = self._canvas

        button = canvas.mouse_state.pressed_button
        mouse_pos = canvas.mouse_state.canvas_pos

        self._lastMousePos.setX(mouse_pos.x())
        self._lastMousePos.setY(mouse_pos.y())
        self._curMousePos.setX(mouse_pos.x())
        self._curMousePos.setY(mouse_pos.y())
        self._pressMousePos.setX(mouse_pos.x())
        self._pressMousePos.setY(mouse_pos.y())

        if button == Qt.LeftButton:

            if self._selectionRectangle.isEmpty():

                self._state = ManipulatorState.MovingPixels

            else:

                if self._selectionRectangle.contains(
                        QPoint(round(mouse_pos.x()), round(mouse_pos.y()))):

                    self._state = ManipulatorState.MovingSelection

                else:

                    if self._selectionImage is not None:
                        self._paste_selection()

                    self._clear_selection()
                    self._state = ManipulatorState.Idle

        elif button == Qt.RightButton:

            if self._selectionImage is not None:
                self._paste_selection()

            self._clear_selection()
            self._state = ManipulatorState.Selecting

    def on_mouse_move(self):

        canvas = self._canvas

        mouse_pos = canvas.mouse_state.canvas_pos

        if self._state == ManipulatorState.MovingPixels:

            self._lastMousePos.setX(self._curMousePos.x())
            self._lastMousePos.setY(self._curMousePos.y())

            self._curMousePos.setX(mouse_pos.x())
            self._curMousePos.setY(mouse_pos.y())

            dx = self._curMousePos.x() - self._lastMousePos.x()
            dy = self._curMousePos.y() - self._lastMousePos.y()

            image = canvas.sprite_object.active_surface

            if image is not None:

                image_data = canvas.sprite_object.active_surface_pixel_data

                if image_data is None:
                    return

                quickpixler.movePixels(image_data, image.width(), image.height(), dx, dy)

                self._canvas.surfaceChanging.emit()

        elif self._state == ManipulatorState.Selecting:

            top_left = QPoint(min(mouse_pos.x(), self._pressMousePos.x()),
                              min(mouse_pos.y(), self._pressMousePos.y()))

            width = abs(mouse_pos.x() - self._pressMousePos.x())
            height = abs(mouse_pos.y() - self._pressMousePos.y())

            self._selectionRectangle.setRect(top_left.x(), top_left.y(),
                                             width, height)

        elif self._state == ManipulatorState.MovingSelection:

            self._lastMousePos.setX(self._curMousePos.x())
            self._lastMousePos.setY(self._curMousePos.y())

            self._curMousePos.setX(mouse_pos.x())
            self._curMousePos.setY(mouse_pos.y())

            dx = self._curMousePos.x() - self._lastMousePos.x()
            dy = self._curMousePos.y() - self._lastMousePos.y()

            self._move_selection(dx, dy)

        elif self._state == ManipulatorState.ScalingSelection:
            pass

    def on_mouse_release(self):

        super(Manipulator, self).on_mouse_press()

        if self._state == ManipulatorState.Selecting:
            if not self._selectionRectangle.isEmpty():
                self._copy_selection()

                if self._cutOnSelection:
                    self._doEraseOnSelectionMove = True

        elif self._state == ManipulatorState.MovingPixels:
            self._canvas.surfaceChanged.emit()

        self._state = ManipulatorState.Idle

    def on_key_press(self, key):

        if key == Qt.Key_Return:

            if not self._selectionRectangle.isEmpty() and self._selectionImage is not None:
                self._paste_selection()
                self._clear_selection()

    def _animate_selection_border(self):

        self._selectionRectDashOffset += 1.0

        if self._selectionRectDashOffset > 6.0:
            self._selectionRectDashOffset = 0.0

        self._selectionBorderPen.setDashOffset(self._selectionRectDashOffset)

    def _clear_selection(self):

        self._selectionRectangle = QRect()
        self._selectionImage = None

    def _normalize_selection_rect(self):

        sprite_bounding_rect = self._canvas.sprite_object.bounding_rect_i

        if self._selectionRectangle.left() < sprite_bounding_rect.left():
            self._selectionRectangle.setLeft(sprite_bounding_rect.left())

        if self._selectionRectangle.right() > sprite_bounding_rect.right():
            self._selectionRectangle.setRight(sprite_bounding_rect.right())

        if self._selectionRectangle.top() < sprite_bounding_rect.top():
            self._selectionRectangle.setTop(sprite_bounding_rect.top())

        if self._selectionRectangle.bottom() > sprite_bounding_rect.bottom():
            self._selectionRectangle.setBottom(sprite_bounding_rect.bottom())

    def _move_selection(self, dx, dy):

        if self._doEraseOnSelectionMove:

            self._erase_selection_below()
            self._doEraseOnSelectionMove = False

        if not self._selectionRectangle.isEmpty():
            self._selectionRectangle.translate(dx, dy)

    def _copy_selection(self):

        self._normalize_selection_rect()

        sprite_rect = self._canvas.map_global_rect_to_sprite_local_rect(self._selectionRectangle)

        self._selectionImage = self._canvas.sprite_object.active_surface.copy(sprite_rect)

    def _erase_selection_below(self):

        sprite_rect_to_erase = self._canvas.map_global_rect_to_sprite_local_rect(
            self._selectionRectangle)

        drawing.erase_area(self._canvas.sprite_object.active_surface,
                           sprite_rect_to_erase.left(),
                           sprite_rect_to_erase.top(),
                           sprite_rect_to_erase.width(),
                           sprite_rect_to_erase.height())

        self._canvas.surfaceChanged.emit()

    def _paste_selection(self):

        if self._selectionImage is None:
            return

        sprite_rect = self._canvas.map_global_rect_to_sprite_local_rect(self._selectionRectangle)

        painter = QPainter()
        painter.begin(self._canvas.sprite_object.active_surface)

        painter.drawImage(sprite_rect, self._selectionImage, QRect(0, 0,
                                                                   self._selectionImage.width(),
                                                                   self._selectionImage.height()))

        painter.end()

        self._canvas.surfaceChanged.emit()
示例#4
0
class MiniMap(QFrame):
    def __init__(self, parent):
        super().__init__(parent)
        self.mMapDocument = None
        self.mDragging = False
        self.mMouseMoveCursorState = False
        self.mRedrawMapImage = False
        self.mRenderFlags = MiniMapRenderFlag.DrawTiles | MiniMapRenderFlag.DrawObjects | MiniMapRenderFlag.DrawImages | MiniMapRenderFlag.IgnoreInvisibleLayer

        self.mMapImageUpdateTimer = QTimer()
        self.mImageRect = QRect()
        self.mMapImage = QImage()
        self.mDragOffset = QPoint()

        self.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        self.setMinimumSize(50, 50)
        # for cursor changes
        self.setMouseTracking(True)
        self.mMapImageUpdateTimer.setSingleShot(True)
        self.mMapImageUpdateTimer.timeout.connect(self.redrawTimeout)

    def setMapDocument(self, map):
        dm = DocumentManager.instance()
        if (self.mMapDocument):
            self.mMapDocument.disconnect()
            mapView = dm.viewForDocument(self.mMapDocument)
#            if mapView:
#                mapView.zoomable().disconnect()
#                mapView.horizontalScrollBar().disconnect()
#                mapView.verticalScrollBar().disconnect()
        
        self.mMapDocument = map
        
        if (self.mMapDocument):
            self.mMapDocument.undoStack().indexChanged.connect(self.scheduleMapImageUpdate)
            mapView = dm.viewForDocument(self.mMapDocument)
            if mapView:
                mapView.horizontalScrollBar().valueChanged.connect(self.update)
                mapView.verticalScrollBar().valueChanged.connect(self.update)
                mapView.zoomable().scaleChanged.connect(self.update)
            
        self.scheduleMapImageUpdate()

    def setRenderFlags(self, flags):
        self.mRenderFlags = flags

    def sizeHint(self):
        return QSize(200, 200)

    ## Schedules a redraw of the minimap image. */
    def scheduleMapImageUpdate(self):
        self.mMapImageUpdateTimer.start(100)

    def paintEvent(self, pe):
        super().paintEvent(pe)
        if (self.mRedrawMapImage):
            self.renderMapToImage()
            self.mRedrawMapImage = False

        if (self.mMapImage.isNull() or self.mImageRect.isEmpty()):
            return
        p = QPainter(self)
        p.setRenderHints(QPainter.SmoothPixmapTransform)
        backgroundColor = QColor(Qt.darkGray)
        if (self.mMapDocument and self.mMapDocument.map().backgroundColor().isValid()):
            backgroundColor = self.mMapDocument.map().backgroundColor()
        p.setBrush(backgroundColor)
        p.setPen(Qt.NoPen)
        p.drawRect(self.contentsRect())
        p.drawImage(self.mImageRect, self.mMapImage)
        viewRect = self.viewportRect()
        p.setBrush(Qt.NoBrush)
        p.setPen(QColor(0, 0, 0, 128))
        p.translate(1, 1)
        p.drawRect(viewRect)
        outLinePen = QPen(QColor(255, 0, 0), 2)
        outLinePen.setJoinStyle(Qt.MiterJoin)
        p.translate(-1, -1)
        p.setPen(outLinePen)
        p.drawRect(viewRect)
        p.end()

    def resizeEvent(self, arg1):
        self.updateImageRect()
        self.scheduleMapImageUpdate()

    def wheelEvent(self, event):
        delta = event.angleDelta().y()
        if (delta != 0):
            self.centerViewOnLocalPixel(event.pos(), delta)
            return

        super().wheelEvent(event)

    def mousePressEvent(self, event):
        if (event.button() == Qt.LeftButton):
            cursorPos = event.pos()
            viewPort = self.viewportRect()
            if (viewPort.contains(cursorPos)):
                self.mDragOffset = viewPort.center() - cursorPos + QPoint(1, 1)
                cursorPos += self.mDragOffset
            else:
                self.mDragOffset = QPoint()
                self.centerViewOnLocalPixel(cursorPos)

            self.mDragging = True
            self.setCursor(Qt.ClosedHandCursor)
            return

        super().mouseReleaseEvent(event)

    def mouseReleaseEvent(self, event):
        if (event.button() == Qt.LeftButton and self.mDragging):
            self.mDragging = False
            viewPort = self.viewportRect()
            if (viewPort.contains(event.pos())):
                self.setCursor(Qt.OpenHandCursor)
                self.mMouseMoveCursorState = True
            elif (self.rect().contains(event.pos())):
                self.unsetCursor()
                self.mMouseMoveCursorState = False

            return

        super().mouseReleaseEvent(event)

    def mouseMoveEvent(self, event):
        if (self.mDragging):
            self.centerViewOnLocalPixel(event.pos() + self.mDragOffset)
            return

        if (self.viewportRect().contains(event.pos())):
            if (not self.mMouseMoveCursorState):
                self.setCursor(Qt.OpenHandCursor)
                self.mMouseMoveCursorState = True
        else:
            if (self.mMouseMoveCursorState):
                self.unsetCursor()
                self.mMouseMoveCursorState = False

        super().mouseMoveEvent(event)

    def redrawTimeout(self):
        self.mRedrawMapImage = True
        self.update()

    def viewportRect(self):
        mapView = DocumentManager.instance().currentMapView()
        if (not mapView):
            return QRect(0, 0, 1, 1)
        sceneRect = mapView.sceneRect()
        viewRect = mapView.mapToScene(mapView.viewport().geometry()).boundingRect()
        return QRect((viewRect.x() - sceneRect.x()) / sceneRect.width() * self.mImageRect.width() + self.mImageRect.x(),
                 (viewRect.y() - sceneRect.y()) / sceneRect.height() * self.mImageRect.height() + self.mImageRect.y(),
                 viewRect.width() / sceneRect.width() * self.mImageRect.width(),
                 viewRect.height() / sceneRect.height() * self.mImageRect.height())

    def mapToScene(self, p):
        if (self.mImageRect.isEmpty()):
            return QPointF()
        mapView = DocumentManager.instance().currentMapView()
        if (not mapView):
            return QPointF()
        sceneRect = mapView.sceneRect()
        p -= self.mImageRect.topLeft()
        return QPointF(p.x() * (sceneRect.width() / self.mImageRect.width()) + sceneRect.x(),
                       p.y() * (sceneRect.height() / self.mImageRect.height()) + sceneRect.y())

    def updateImageRect(self):
        imageRect = self.mMapImage.rect()
        if (imageRect.isEmpty()):
            self.mImageRect = QRect()
            return

        # Scale and center the image
        r = self.contentsRect()
        scale = min( r.width() / imageRect.width(),
                            r.height() / imageRect.height())
        imageRect.setSize(imageRect.size() * scale)
        imageRect.moveCenter(r.center())
        self.mImageRect = imageRect

    def renderMapToImage(self):
        if (not self.mMapDocument):
            self.mMapImage = QImage()
            return

        renderer = self.mMapDocument.renderer()
        r = self.contentsRect()
        mapSize = renderer.mapSize()
        if (mapSize.isEmpty()):
            self.mMapImage = QImage()
            return

        margins = self.mMapDocument.map().computeLayerOffsetMargins()
        mapSize.setWidth(mapSize.width() + margins.left() + margins.right())
        mapSize.setHeight(mapSize.height() + margins.top() + margins.bottom())
        
        # Determine the largest possible scale
        scale = min( r.width() / mapSize.width(), r.height() / mapSize.height())
        # Allocate a new image when the size changed
        imageSize = mapSize * scale
        if (self.mMapImage.size() != imageSize):
            self.mMapImage = QImage(imageSize, QImage.Format_ARGB32_Premultiplied)
            self.updateImageRect()

        if (imageSize.isEmpty()):
            return
        drawObjects = bool(self.mRenderFlags & MiniMapRenderFlag.DrawObjects)
        drawTiles = bool(self.mRenderFlags & MiniMapRenderFlag.DrawTiles)
        drawImages = bool(self.mRenderFlags & MiniMapRenderFlag.DrawImages)
        drawTileGrid = bool(self.mRenderFlags & MiniMapRenderFlag.DrawGrid)
        visibleLayersOnly = bool(self.mRenderFlags & MiniMapRenderFlag.IgnoreInvisibleLayer)
        # Remember the current render flags
        renderFlags = renderer.flags()
        renderer.setFlag(RenderFlag.ShowTileObjectOutlines, False)
        self.mMapImage.fill(Qt.transparent)
        painter = QPainter(self.mMapImage)
        painter.setRenderHints(QPainter.SmoothPixmapTransform)
        painter.setTransform(QTransform.fromScale(scale, scale))
        painter.translate(margins.left(), margins.top())
        renderer.setPainterScale(scale)
        for layer in self.mMapDocument.map().layers():
            if (visibleLayersOnly and not layer.isVisible()):
                continue
            painter.setOpacity(layer.opacity())
            painter.translate(layer.offset())
            tileLayer = layer
            objGroup = layer
            imageLayer = layer
            tp = type(layer)
            if (tp==TileLayer and drawTiles):
                renderer.drawTileLayer(painter, tileLayer)
            elif (tp==ObjectGroup and drawObjects):
                objects = objGroup.objects()
                if (objGroup.drawOrder() == ObjectGroup.DrawOrder.TopDownOrder):
                    objects = QList(sorted(objects, key=lambda x:x.y(), reverse=True))
                for object in objects:
                    if (object.isVisible()):
                        if (object.rotation() != 0.0):
                            origin = renderer.pixelToScreenCoords_(object.position())
                            painter.save()
                            painter.translate(origin)
                            painter.rotate(object.rotation())
                            painter.translate(-origin)

                        color = MapObjectItem.objectColor(object)
                        renderer.drawMapObject(painter, object, color)
                        if (object.rotation() != 0.0):
                            painter.restore()
            elif (tp==ImageLayer and drawImages):
                renderer.drawImageLayer(painter, imageLayer)
                
            painter.translate(-layer.offset())
            
        if (drawTileGrid):
            prefs = preferences.Preferences.instance()
            renderer.drawGrid(painter, QRectF(QPointF(), renderer.mapSize()),
                               prefs.gridColor())
        
        painter.end()
        renderer.setFlags(renderFlags)

    def centerViewOnLocalPixel(self, centerPos, delta = 0):
        mapView = DocumentManager.instance().currentMapView()
        if (not mapView):
            return
        if (delta != 0):
            mapView.zoomable().handleWheelDelta(delta)
        mapView.centerOn(self.mapToScene(centerPos))
示例#5
0
class MiniMap(QFrame):
    def __init__(self, parent):
        super().__init__(parent)
        self.mMapDocument = None
        self.mDragging = False
        self.mMouseMoveCursorState = False
        self.mRedrawMapImage = False
        self.mRenderFlags = MiniMapRenderFlag.DrawTiles | MiniMapRenderFlag.DrawObjects | MiniMapRenderFlag.DrawImages | MiniMapRenderFlag.IgnoreInvisibleLayer

        self.mMapImageUpdateTimer = QTimer()
        self.mImageRect = QRect()
        self.mMapImage = QImage()
        self.mDragOffset = QPoint()

        self.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        self.setMinimumSize(50, 50)
        # for cursor changes
        self.setMouseTracking(True)
        self.mMapImageUpdateTimer.setSingleShot(True)
        self.mMapImageUpdateTimer.timeout.connect(self.redrawTimeout)

    def setMapDocument(self, map):
        dm = DocumentManager.instance()
        if (self.mMapDocument):
            self.mMapDocument.disconnect()
            mapView = dm.viewForDocument(self.mMapDocument)
#            if mapView:
#                mapView.zoomable().disconnect()
#                mapView.horizontalScrollBar().disconnect()
#                mapView.verticalScrollBar().disconnect()

        self.mMapDocument = map

        if (self.mMapDocument):
            self.mMapDocument.undoStack().indexChanged.connect(
                self.scheduleMapImageUpdate)
            mapView = dm.viewForDocument(self.mMapDocument)
            if mapView:
                mapView.horizontalScrollBar().valueChanged.connect(self.update)
                mapView.verticalScrollBar().valueChanged.connect(self.update)
                mapView.zoomable().scaleChanged.connect(self.update)

        self.scheduleMapImageUpdate()

    def setRenderFlags(self, flags):
        self.mRenderFlags = flags

    def sizeHint(self):
        return QSize(200, 200)

    ## Schedules a redraw of the minimap image. */
    def scheduleMapImageUpdate(self):
        self.mMapImageUpdateTimer.start(100)

    def paintEvent(self, pe):
        super().paintEvent(pe)
        if (self.mRedrawMapImage):
            self.renderMapToImage()
            self.mRedrawMapImage = False

        if (self.mMapImage.isNull() or self.mImageRect.isEmpty()):
            return
        p = QPainter(self)
        p.setRenderHints(QPainter.SmoothPixmapTransform)
        backgroundColor = QColor(Qt.darkGray)
        if (self.mMapDocument
                and self.mMapDocument.map().backgroundColor().isValid()):
            backgroundColor = self.mMapDocument.map().backgroundColor()
        p.setBrush(backgroundColor)
        p.setPen(Qt.NoPen)
        p.drawRect(self.contentsRect())
        p.drawImage(self.mImageRect, self.mMapImage)
        viewRect = self.viewportRect()
        p.setBrush(Qt.NoBrush)
        p.setPen(QColor(0, 0, 0, 128))
        p.translate(1, 1)
        p.drawRect(viewRect)
        outLinePen = QPen(QColor(255, 0, 0), 2)
        outLinePen.setJoinStyle(Qt.MiterJoin)
        p.translate(-1, -1)
        p.setPen(outLinePen)
        p.drawRect(viewRect)
        p.end()

    def resizeEvent(self, arg1):
        self.updateImageRect()
        self.scheduleMapImageUpdate()

    def wheelEvent(self, event):
        delta = event.angleDelta().y()
        if (delta != 0):
            self.centerViewOnLocalPixel(event.pos(), delta)
            return

        super().wheelEvent(event)

    def mousePressEvent(self, event):
        if (event.button() == Qt.LeftButton):
            cursorPos = event.pos()
            viewPort = self.viewportRect()
            if (viewPort.contains(cursorPos)):
                self.mDragOffset = viewPort.center() - cursorPos + QPoint(1, 1)
                cursorPos += self.mDragOffset
            else:
                self.mDragOffset = QPoint()
                self.centerViewOnLocalPixel(cursorPos)

            self.mDragging = True
            self.setCursor(Qt.ClosedHandCursor)
            return

        super().mouseReleaseEvent(event)

    def mouseReleaseEvent(self, event):
        if (event.button() == Qt.LeftButton and self.mDragging):
            self.mDragging = False
            viewPort = self.viewportRect()
            if (viewPort.contains(event.pos())):
                self.setCursor(Qt.OpenHandCursor)
                self.mMouseMoveCursorState = True
            elif (self.rect().contains(event.pos())):
                self.unsetCursor()
                self.mMouseMoveCursorState = False

            return

        super().mouseReleaseEvent(event)

    def mouseMoveEvent(self, event):
        if (self.mDragging):
            self.centerViewOnLocalPixel(event.pos() + self.mDragOffset)
            return

        if (self.viewportRect().contains(event.pos())):
            if (not self.mMouseMoveCursorState):
                self.setCursor(Qt.OpenHandCursor)
                self.mMouseMoveCursorState = True
        else:
            if (self.mMouseMoveCursorState):
                self.unsetCursor()
                self.mMouseMoveCursorState = False

        super().mouseMoveEvent(event)

    def redrawTimeout(self):
        self.mRedrawMapImage = True
        self.update()

    def viewportRect(self):
        mapView = DocumentManager.instance().currentMapView()
        if (not mapView):
            return QRect(0, 0, 1, 1)
        sceneRect = mapView.sceneRect()
        viewRect = mapView.mapToScene(
            mapView.viewport().geometry()).boundingRect()
        return QRect(
            (viewRect.x() - sceneRect.x()) / sceneRect.width() *
            self.mImageRect.width() + self.mImageRect.x(),
            (viewRect.y() - sceneRect.y()) / sceneRect.height() *
            self.mImageRect.height() + self.mImageRect.y(),
            viewRect.width() / sceneRect.width() * self.mImageRect.width(),
            viewRect.height() / sceneRect.height() * self.mImageRect.height())

    def mapToScene(self, p):
        if (self.mImageRect.isEmpty()):
            return QPointF()
        mapView = DocumentManager.instance().currentMapView()
        if (not mapView):
            return QPointF()
        sceneRect = mapView.sceneRect()
        p -= self.mImageRect.topLeft()
        return QPointF(
            p.x() * (sceneRect.width() / self.mImageRect.width()) +
            sceneRect.x(),
            p.y() * (sceneRect.height() / self.mImageRect.height()) +
            sceneRect.y())

    def updateImageRect(self):
        imageRect = self.mMapImage.rect()
        if (imageRect.isEmpty()):
            self.mImageRect = QRect()
            return

        # Scale and center the image
        r = self.contentsRect()
        scale = min(r.width() / imageRect.width(),
                    r.height() / imageRect.height())
        imageRect.setSize(imageRect.size() * scale)
        imageRect.moveCenter(r.center())
        self.mImageRect = imageRect

    def renderMapToImage(self):
        if (not self.mMapDocument):
            self.mMapImage = QImage()
            return

        renderer = self.mMapDocument.renderer()
        r = self.contentsRect()
        mapSize = renderer.mapSize()
        if (mapSize.isEmpty()):
            self.mMapImage = QImage()
            return

        margins = self.mMapDocument.map().computeLayerOffsetMargins()
        mapSize.setWidth(mapSize.width() + margins.left() + margins.right())
        mapSize.setHeight(mapSize.height() + margins.top() + margins.bottom())

        # Determine the largest possible scale
        scale = min(r.width() / mapSize.width(), r.height() / mapSize.height())
        # Allocate a new image when the size changed
        imageSize = mapSize * scale
        if (self.mMapImage.size() != imageSize):
            self.mMapImage = QImage(imageSize,
                                    QImage.Format_ARGB32_Premultiplied)
            self.updateImageRect()

        if (imageSize.isEmpty()):
            return
        drawObjects = bool(self.mRenderFlags & MiniMapRenderFlag.DrawObjects)
        drawTiles = bool(self.mRenderFlags & MiniMapRenderFlag.DrawTiles)
        drawImages = bool(self.mRenderFlags & MiniMapRenderFlag.DrawImages)
        drawTileGrid = bool(self.mRenderFlags & MiniMapRenderFlag.DrawGrid)
        visibleLayersOnly = bool(self.mRenderFlags
                                 & MiniMapRenderFlag.IgnoreInvisibleLayer)
        # Remember the current render flags
        renderFlags = renderer.flags()
        renderer.setFlag(RenderFlag.ShowTileObjectOutlines, False)
        self.mMapImage.fill(Qt.transparent)
        painter = QPainter(self.mMapImage)
        painter.setRenderHints(QPainter.SmoothPixmapTransform)
        painter.setTransform(QTransform.fromScale(scale, scale))
        painter.translate(margins.left(), margins.top())
        renderer.setPainterScale(scale)
        for layer in self.mMapDocument.map().layers():
            if (visibleLayersOnly and not layer.isVisible()):
                continue
            painter.setOpacity(layer.opacity())
            painter.translate(layer.offset())
            tileLayer = layer
            objGroup = layer
            imageLayer = layer
            tp = type(layer)
            if (tp == TileLayer and drawTiles):
                renderer.drawTileLayer(painter, tileLayer)
            elif (tp == ObjectGroup and drawObjects):
                objects = objGroup.objects()
                if (objGroup.drawOrder() == ObjectGroup.DrawOrder.TopDownOrder
                    ):
                    objects = QList(
                        sorted(objects, key=lambda x: x.y(), reverse=True))
                for object in objects:
                    if (object.isVisible()):
                        if (object.rotation() != 0.0):
                            origin = renderer.pixelToScreenCoords_(
                                object.position())
                            painter.save()
                            painter.translate(origin)
                            painter.rotate(object.rotation())
                            painter.translate(-origin)

                        color = MapObjectItem.objectColor(object)
                        renderer.drawMapObject(painter, object, color)
                        if (object.rotation() != 0.0):
                            painter.restore()
            elif (tp == ImageLayer and drawImages):
                renderer.drawImageLayer(painter, imageLayer)

            painter.translate(-layer.offset())

        if (drawTileGrid):
            prefs = preferences.Preferences.instance()
            renderer.drawGrid(painter, QRectF(QPointF(), renderer.mapSize()),
                              prefs.gridColor())

        painter.end()
        renderer.setFlags(renderFlags)

    def centerViewOnLocalPixel(self, centerPos, delta=0):
        mapView = DocumentManager.instance().currentMapView()
        if (not mapView):
            return
        if (delta != 0):
            mapView.zoomable().handleWheelDelta(delta)
        mapView.centerOn(self.mapToScene(centerPos))